当我们使用前馈神经网络接收输入 x 并产生输出 y^ 时,信息通过网络向前流动。输入 x 提供初始信息,然后传播到每一层的隐藏单元,最终产生输出 y^ ,这称之为前向传播。在训练过程中,前向传播可以持续向前直到它产生一个标量代价函数 J(θ) 。反向传播算法(Back Propagation),允许来自代价函数的信息通过网络向后流动,以便计算梯度。
链式法则
微积分中的链式法则(为了不与概率中的链式法则相混淆)用于计算复合函数的导数。反向传播是一种计算链式法则的算法,使用高效的特定运算顺序。
设 x 是实数, f 和 g 是从实数映射到实数的函数。 y=g(x) 并且 z=f(g(x))=f(y) 。那么链式法则是说:
dxdz=dydzdxdy
我们可以将这种标量情况进行拓展。假设假设 x∈Rn , y∈Rn , g 是从 Rn 到 Rn 的映射, f 是 Rn 到 Rn 的映射。如果 y=g(x) 并且 z=f(y) ,那么
∂xi∂z=j∑∂yi∂z∂xi∂yj
使用向量记法,可以等价地写成
Δxz=(∂x∂y)TΔyz
这里 ∂x∂y 是 g 的 n×m 的Jacobian矩阵。
通常我们将反向传播算法应用于任意维度的张量,而不仅仅用于向量。从概念上讲,这与使用向量的方向传播完全相同。唯一的区别是如何将数字排列称网格以形成张量。我们可以想象,在运行反向传播之前,将每个张量扁平为一个向量,计算一个向量值梯度,然后将该梯度重新构造成一个张量。从这种重新排列的观点上看,反向传播仍然只是将Jacobian乘以梯度。
反向传播
在进行DNN反向传播算法前,我们需要选择一个损失函数,来度量训练样本计算出的输出和真实的训练样本输出之间的损失。DNN可选择的损失函数有不少,为了专注算法,这里我们使用最常见的均方差来度量损失。当然,针对不同的任务,可以选择不同的损失函数。即对于每个样本,我们期望最小化下式:
J(W,b,x,y)=21∣∣a(L)−y∣∣22
其中, a(L) 和 y 为 nout 维度的向量,而 ∣∣S∣∣2 为 S 的 L2 范数。损失函数有了,现在我们开始用梯度下降法迭代求解每一层的 W 和 b
第一步
首先是输出层(第 L 层)。输出层的 W 和 b 满足下式:
a(L)=σ(z(L))=σ(W(L)a(L−1)+b(L))
这样对于输出层的参数,我们的损失函数变为:
J(W,b,x,y)=21∣∣a(L)−y∣∣22=21∣∣σ(W(L)a(L−1)+b(L))−y∣∣22
这样求解 W 和 b 的梯度就简单了:
∂W(L)∂J(W,b,x,y)=∂a(L)∂J(W,b,x,y)∂W(L)∂a(L)=∂a(L)∂J(W,b,x,y)∂z(L)∂a(L)∂W(L)∂z(L)=(a(L)−y)⊙σ′(z(L))(a(L−1))T
∂b(L)∂J(W,b,x,y)=∂a(L)∂J(W,b,x,y)∂b(L)∂a(L)=∂a(L)∂J(W,b,x,y)∂z(L)∂a(L)∂b(L)∂z(L)=(a(L)−y)⊙σ′(z(L))
上面式子前两项之所以是Hadamard积 ⊙ 形式,是因为 ∂a(L)∂J(W,b,x,y)∂z(L)∂a(L) 都是针对同一层的神经元。如果我们考虑对于 L 层的第 j 个神经元,即 ∂a(L)∂J(W,b,x,y)σ′(zj(L)) ,那么整合这一层的神经元,自然是 (a(L)−y)⊙σ′(z(L)) 这样Hadamard积的形式。
(a(L−1))T 在第一个式子的最后是因为若 Y=WX+B ,那么 ∂W∂C=∂Y∂CXT
第二步
我们注意到在求解输出层的 W 和 b 时,有公共的部分 ∂a(L)∂J(W,b,x,y)∂z(L)∂a(L)=∂z(L)∂J(W,b,x,y) ,因此我们可以把公共的部分即对 z(L) 先算出来,记为
δ(L)=∂z(L)∂J(W,b,x,y)=(a(L)−y)⊙σ′(z(L))
根据第一步的公式我们可以把输出层的梯度计算出来,计算上一层 L−1 ,上上层 L−2 ...的梯度就需要步步递推了:对于第 l 层的未激活输出 z(l) ,它的梯度可以表示为
δ(l)=∂z(l)∂J(W,b,x,y)=∂z(L)∂J(W,b,x,y)∂z(L−1)∂z(L)∂z(L−2)∂z(L−1)⋯∂z(l)∂z(l+1)
如果我们可以依次计算出第 l 层的 δ(l) ,则该层的 W(l) 和 b(l) 就很好计算了,因为根据前向传播:
z(l)=W(l)a(l−1)+b(l)
所以我们可以很方便的计算出第 l 层的 W(l) 和 b(l) 的梯度如下
∂W(l)∂J(W,b,x,y)=∂z(l)∂J(W,b,x,y)∂W(l)∂z(l)=δ(l)(a(l−1))T
∂b(l)∂J(W,b,x,y)=∂z(l)∂J(W,b,x,y)∂b(l)∂z(l)=δ(l)
第三步
现在问题的关键就是求 δ(l) 了。这里我们使用数学归纳法,假设第 l+1 层的 δ(l+1) 已经求出,那我们如何求第 l 层的 δ(l) 呢:
δ(l)=∂z(l)∂J(W,b,x,y)=∂z(l+1)∂J(W,b,x,y)∂z(l)∂z(l+1)=δ(l+1)∂z(l)∂z(l+1)
可见,关键在于求解 ∂z(l)∂z(l+1) ,而 z(l+1) 和 z(l) 的关系很容易求出:
z(l+1)=W(l+1)al+b(l+1)=W(l+1)σ(z(l))+b(l+1)
这样可得
∂z(l)∂z(l+1)=(W(l+1))T⊙nl+1σ′(z(l),…,σ′(z(l))
上式的意思是 (Wl+1)T 的每一列都是Hadamard积 σ′(z(l)) ,将上式代入 δ(l)=δ(l+1)∂z(l)∂z(l+1) ,得
δ(l)=δ(l+1)∂z(l)∂z(l+1)=∂z(l)(δ(l+1))Tz(l+1)=∂z(l)(δ(l+1))T(W(l+1)σ(z(l)+b(l+1)))=∂z(l)(δ(l+1))TW(l+1)σ(z(l))
=((δl+1)TW(l+1))T⊙σ′(z(l))=(W(l+1))Tδ(l+1)⊙σ′(z(l))
总结
其实,对于更新每一层的 Wl,bl 的对应梯度,我们仔细观察整个过程,发现只需要四个公式就可以完整地进行更新。这就是著名的反向传播的四个公式。我们稍加改动,使其可以适用于多种损失函数,即:
δ(L)=∂a(L)∂J⊙σ′(z(L)) BP(1)
δ(l)=(W(l+1))Tδ(l+1)⊙σ′(z(l)) BP(2)
∂W(l)∂J=δ(l)(a(l−1))T BP(3)
∂b(l)∂J=δ(l) BP(4)
现在我们总结下DNN反向传播算法的过程。由于梯度下降法有批量(Batch),小批量(mini-Batch),随机三个变种,为了简化描述,这里我们以最基本的批量梯度下降法为例来描述反向传播算法。实际上在业界使用最多的是mini-Batch的梯度下降法。不过区别仅仅在于迭代时训练样本的选择而已。
输入:总层数 L ,以及各隐藏层与输出层的神经元个数,激活函数,损失函数,迭代步长 α ,最大迭代次数MAX与停止迭代阈值 ϵ ,输入的 m 个训练样本 {(x1,y1),(x2,y2),…,(xm,ym)}
输出:各隐藏层与输出层的线性关系系数矩阵 W 和偏倚向量 b (即输出模型)
1) 初始化各隐藏层与输出层的线性关系系数矩阵 W 和偏倚向量 b 的值为一个随机值
2) for 1 to MAX:
2-1) for i=1 to m :
a) 将DNN输入 a1 设置为 xi
b) for l=2 to L ,进行前向传播算法计算 ai,l=σ(zi,l)=σ(Wlai,l−1+bl)
c) 通过损失函数计算输出层的 δi,L (BP1)
d) for l=2 to L ,进行反向传播算法计算 δi,l=(Wl+1)Tδi,l+1⊙σ′(zi,l) (BP2)
2-2) for l=2 to L,更新第 l 层的 Wl,bl :
Wl=Wl−αi=1∑mδi,l(ai,l−1)T (BP3)
bl=bl−αi=1∑mδi,l (BP4)
2-3) 如果所有 W,b 的变化值都小于停止迭代阈值 ϵ ,则跳出迭代循环到步骤3
3) 输出各隐藏层与输出层的线性关系系数矩阵 W 和偏倚向量 b (即输出模型)
Source