反向传播算法

引言

在上一篇《梯度下降》中,对于没有隐层的网络(文章中是拟合的线性函数),有直接的输入和输出,可以直接使用梯度下降求解。但对于有隐层的神经网络,在输出层可以通过梯度下降直接求出误差来更新参数,但隐层的误差是不存在的,不能对它直接应用梯度下降进行优化,而是先将误差反向传播至隐层,然后再应用梯度下降,其中将误差从末层往前传递的过程需要链式法则(Chain Rule)的帮助,因此反向传播算法可以说是梯度下降在链式法则中的应用。可以快速的从参数空间里找到较好的参数组合。

所以对于含隐层的神经网络来说,反向传播是一种用来训练人工神经网络的常见方法。算法使梯度可以在计算图上进行传播。该方法计算网络中损失函数对神经网络每一层临时输出值的梯度,用来更新权值以最小化损失函数。

反向传播算法的主要步骤如下:
前向传播->反向传播->权重更新->循环迭代

更加详细的推导,这篇文章讲的非常好:反向传播之我见

反向传播通过使用计算图在Tensorflow,Torch等深度学习框架中实现。

pytorch反向传播

在pytorch中进行反向传播,首先要构建计算图。

Pytorch构建计算图

计算图是用来描述运算的有向无环图。 是一种描述方程的“语言”。主要包含节点(数据)和边(运算)

如下便构建了一个计算图:

1
2
3
4
5
6
7
8
9
import torch
x_data = [i for i in range(10)]
y_data = [2*i for i in range(10)]
w = torch.Tensor([1.0])
w.requires_grad = True #需要求梯度的变量,需要将该参数置为True
for x, y in zip(x_data,y_data):
loss = (w*x - y) ** 2
loss.backward() # 反向传播之后,梯度被保存在tensor中,计算图结束,被释放
#如果想让图保留可以使参数retain_graph=True

pytoch构建的计算图是动态图,每次一轮迭代完之后计算图就被释放,不能进行多次的backward

这里的动态主要有两重含义。

第一层含义是:计算图的正向传播是立即执行的。无需等待完整的计算图创建完毕,每条语句都会在计算图中动态添加节点和边,并立即执行正向传播得到计算结果。

第二层含义是:计算图在反向传播后立即销毁。下次调用需要重新构建计算图。如果在程序中使用了backward方法执行了反向传播,或者利用torch.autograd.grad方法计算了梯度,那么创建的计算图会被立即销毁,释放存储空间,下次调用需要重新创建。

Pytorch构建单层网络的反向传播

然后我们使用pytorch构建一个完整的反向传播流程:

这里还是使用f(x)=wxf(x)=w*x作为拟合函数,使用单层的神经网络,并将每次迭代的误差与梯度输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import torch
x_data = [1, 2, 3]
y_data = [2, 4, 6]
w = torch.Tensor([1.0])
w.requires_grad = True
def forward(x):
return w*x
def loss(x, y):#计算误差
y_pred = forward(x)
return (y_pred - y) ** 2
print("predict (before training)", 4, forward(4).item())
for epoch in range(10):
for x, y in zip(x_data,y_data):
l = loss(x,y)#前向传播
l.backward()#反向传播
print('\tgrad:', x, y, w.grad.item())
w.data = w.data - 0.01 * w.grad.data#更新梯度
#正因为求导链式法则衍生的梯度累加规则,张量的grad梯度不会自动清零,在需要的时候需要手动置零。
w.grad.data.zero_()#这里需要将梯度清空,不然下个输入进来会对梯度进行累加
print("progress:", epoch, l.item())

print("predict (after training)", 4, forward(4).item())

输出如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
predict (before training) 4 4.0
grad: 1 2 -2.0
grad: 2 4 -7.840000152587891
grad: 3 6 -16.228801727294922
progress: 0 7.315943717956543
grad: 1 2 -1.478623867034912
grad: 2 4 -5.796205520629883
grad: 3 6 -11.998146057128906
省略。。。。。。
progress: 7 0.10662525147199631
grad: 1 2 -0.17850565910339355
grad: 2 4 -0.699742317199707
grad: 3 6 -1.4484672546386719
progress: 8 0.0582793727517128
grad: 1 2 -0.1319713592529297
grad: 2 4 -0.5173273086547852
grad: 3 6 -1.070866584777832
progress: 9 0.03185431286692619
predict (after training) 4 7.804864406585693

每一步对梯度的求导过程如下:

误差传播

参考: