三、反向传播
课程链接:Pytorch 深度学习实践——反向传播
1、两层的神经网络
问题:每一层输出的都是上一层输入的线性函数,不管加多少隐藏层的神经网络,最后的output也只是input的线性组合。
解决方法:每一层神经网络都需要一个非线性函数单元Nonlinear Function
2、链式法则(Chain Rule)
把复合函数上每一步的偏导数进行累积,以求得最终的导数。
①构建计算图(Forward)
②计算局部导数
③导数通过节点传递,采用链式法则计算导数(Backward)
以线性模型为例:
3、Tensor(张量)
在Pytorch中,Tensor是构建动态计算图的重要成分。它包括存储在节点的权重和上述提到的局部导数。
Ⅰ、课程作业:构建线性模型y=w*x的计算图
代码实现:
#Construct Computation Graph
import torch
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w = torch.Tensor([1.0])
w.requires_grad = True
def forward(x):
return w * x #w是一个Tensor,因此在乘法运算时,x也转换为Tensor变量,所得的结果也是Tensor变量
def loss(t, y):
return (t - y) ** 2
for epoch in range(100):
for x, y in zip(x_data, y_data):
t = forward(x)
l = loss(t, y) #l是一个tensor
l.backward() #backward会反向计算梯度
print('grad:' + '\t' + str(x) + '\t' + str(y) + '\t' + str(format(w.grad.item(), '.2f'))) #把grad里的值变为标量
w.data -= 0.01 * w.grad.data #这里注意要取grad里的data,因为grad是个Tensor变量
w.grad.data.zero_() #由于backward计算完梯度后会一直累加,所以在更新完w后需要把w的梯度重置为0
if(epoch % 10 == 0):
print('Epoch =' + '\t' + str(epoch) + '\t' + str(format(l.item(), '.4f')))
print("predict after training ", 4, forward(4).item())
结果展示:
Epoch = 0 7.3159
Epoch = 10 0.0174
Epoch = 20 0.0000
Epoch = 30 0.0000
Epoch = 40 0.0000
Epoch = 50 0.0000
Epoch = 60 0.0000
Epoch = 70 0.0000
Epoch = 80 0.0000
Epoch = 90 0.0000
predict after training 4 7.999998569488525
Ⅱ、课后作业:构建二次模型 y = w 1 x 2 + w 2 x + b y=w_1x^2+w_2x+b y=w1x2+w2x+b的计算图
代码实现:
#Construct Computation Graph
import torch
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w1 = torch.Tensor([1.0])#初始权值
w1.requires_grad = True#计算梯度,默认是不计算的
w2 = torch.Tensor([1.0])
w2.requires_grad = True
b = torch.Tensor([1.0])
b.requires_grad = True
def forward(x):
return w1 * x**2 + w2 * x + b
def loss(t, y):
return (t - y) ** 2
for epoch in range(100):
for x, y in zip(x_data, y_data):
t = forward(x)
l = loss(t, y) #l是一个tensor
l.backward() #backward会反向计算梯度
#print('grad:' + '\t' + str(x) + '\t' + str(y) + '\t' + str(format(w.grad.item(), '.2f'))) #把grad里的值变为标量
w1.data -= 0.01 * w1.grad.data #这里注意要取grad里的data,因为grad是个Tensor变量
w2.data -= 0.01 * w2.grad.data
b.data -= 0.01 * b.grad.data
w1.grad.data.zero_()
w2.grad.data.zero_()
b.grad.data.zero_()
if(epoch % 10 == 0):
print('Epoch =' + '\t' + str(epoch) + '\t' + str(format(l.item(), '.4f')))
print("predict after training ", 4, forward(4).item())
结果展示:
Epoch = 0 18.3218
Epoch = 10 0.0285
Epoch = 20 0.0191
Epoch = 30 0.0142
Epoch = 40 0.0112
Epoch = 50 0.0094
Epoch = 60 0.0082
Epoch = 70 0.0074
Epoch = 80 0.0069
Epoch = 90 0.0066
predict after training 4 8.544171333312988
结果分析:在构建完二次模型的计算图后,可以看到预测x=4时的 y ^ \hat{y} y^还存在误差(y=8),这是由于数据集是线性模型的数据集导致的,现在把数据集改为如下:
x_data = [1.0, 2.0, 3.0]
y_data = [3.0, 7.0, 13.0]
w1 = torch.Tensor([0.5])#初始权值
w1.requires_grad = True#计算梯度,默认是不计算的
w2 = torch.Tensor([0.5])
w2.requires_grad = True
b = torch.Tensor([0.5])
b.requires_grad = True
显然这个数据集对应的二次模型为
y
=
x
2
+
x
+
1
y=x^2+x+1
y=x2+x+1,权值初始都改为0.5
再来看一下结果:
Epoch = 0 10.7623
Epoch = 10 0.0334
Epoch = 20 0.0152
Epoch = 30 0.0068
Epoch = 40 0.0030
Epoch = 50 0.0013
Epoch = 60 0.0006
Epoch = 70 0.0002
Epoch = 80 0.0001
Epoch = 90 0.0000
predict after training 4 20.987239837646484