关于反向传播算法个人的一些思考
- 非常简单的一个例子
- 让情况变得复杂一些
- 未完待续
本文为笔者个人对反向传播算法的一个理解,由于笔者也是刚刚踏上深度学习之路,所以很多地方可能理解的不到位,欢迎各位在评论处指出。
本文适合已经了解过反向传播算法但是仍对其不明所以的小伙伴进行阅读,不太适合零基础同学,因为本文并没有从零开始完整介绍相关理论知识。
引用框标注的文字为解释性说明或者从GPT捞来的官方术语解释,非引用文字为笔者大白话解释文字,存在不严谨性。
非常简单的一个例子
本例中所有大写的W和X均为标量,f代表神经元中的激活函数,y3 = y_output。
前向传播流程:
- X 2 = W 1 ∗ X i n p u t X_{2}=W_{1}*X_{input} X2=W1∗Xinput
- Y 2 = f 1 ( X 2 ) Y_{2} = f1(X_{2}) Y2=f1(X2)
- X 3 = W 2 ∗ Y 2 X_{3} =W_{2}* Y_{2} X3=W2∗Y2
- Y 3 = f 2 ( X 3 ) Y_{3} = f2(X_{3}) Y3=f2(X3)
函数复合后的形式:
- Y 3 = f 2 ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) Y_{3}=f2(W_{2}*f1(W_{1}*X_{input})) Y3=f2(W2∗f1(W1∗Xinput))
均方误差损失函数为:
- E ( Y 3 , Y t a r g e t ) = 1 2 ( Y 3 − Y t a r g e t ) 2 E(Y_{3},Y_{target}) =\frac{1}{2}(Y_{3}-Y_{target})^{2} E(Y3,Ytarget)=21(Y3−Ytarget)2
由于已经写出了 Y 3 ( W 1 , W 2 ) Y_{3}(W_{1},W_{2}) Y3(W1,W2)多元函数表达式,将其带入损失函数表达式可得 E ( W 1 , W 2 ) E(W_{1},W_{2}) E(W1,W2):
- E ( W 1 , W 2 ) = 1 2 ( f 2 ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) − Y t a r g e t ) 2 E(W_{1},W_{2})=\frac{1}{2}(f2(W_{2}*f1(W_{1}*X_{input}))-Y_{target})^{2} E(W1,W2)=21(f2(W2∗f1(W1∗Xinput))−Ytarget)2
这里将 E r r o r Error Error损失函数表示为关于权重w1和w2的多元函数形式,是因为神经网络就是要通过不断的训练寻找到尽可能好的权重值使得损失函数 E r r o r Error Error的值尽可能小,即最好能找到一组(w1,w2)使得 E r r o r Error Error在该点取得最小值,最简单的训练方法如: SGD随机梯度下降方法。
w i j = w i j − α ∗ ∂ E ∂ w i j w_{ij} = w{ij} - \alpha * \frac{\partial E}{\partial w_{ij}} wij=wij−α∗∂wij∂E
如果采用梯度下降法,那么我们需要将 E ( W 1 , W 2 ) E(W_{1},W_{2}) E(W1,W2)对W1和W2求偏导,由于已经有了 E ( W 1 , W 2 ) E(W_{1},W_{2}) E(W1,W2)的表达式,所以可以直接利用多元复合函数求导法则分别求出 E ( W 1 , W 2 ) E(W_{1},W_{2}) E(W1,W2)关于W1和W2的偏导函数表达式:
- ∂ E ( W 1 , W 2 ) ∂ W 2 = ( f 2 ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) − Y t a r g e t ) ∗ f 2 ′ ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) ∗ f 1 ( W 1 ∗ X i n p u t ) \frac{\partial E(W_{1},W_{2})}{\partial W_{2}} = (f2(W_{2}*f1(W_{1}*X_{input}))-Y_{target}) * {f2}'(W_{2}*f1(W_{1}*X_{input})) * f1(W_{1}*X_{input}) ∂W2∂E(W1,W2)=(f2(W2∗f1(W1∗Xinput))−Ytarget)∗f2′(W2∗f1(W1∗Xinput))∗f1(W1∗Xinput)
- ∂ E ( W 1 , W 2 ) ∂ W 1 = ( f 2 ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) − Y t a r g e t ) ∗ f 2 ′ ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) ∗ W 2 ∗ f 1 ′ ( W 1 ∗ X i n p u t ) ∗ X i n p u t \frac{\partial E(W_{1},W_{2})}{\partial W_{1}} = (f2(W_{2}*f1(W_{1}*X_{input}))-Y_{target}) * {f2}'(W_{2}*f1(W_{1}*X_{input})) *W_{2}* {f1}'(W_{1}*X_{input})*X_{input} ∂W1∂E(W1,W2)=(f2(W2∗f1(W1∗Xinput))−Ytarget)∗f2′(W2∗f1(W1∗Xinput))∗W2∗f1′(W1∗Xinput)∗Xinput
我们已经得到了 E ( W 1 , W 2 ) E(W_{1},W_{2}) E(W1,W2)关于W1和W2的偏导函数表达式,如果采用梯度下降算法(SGD)不断优化权重并且初始化权重值为 W 1 , W 2 W_{1},W_{2} W1,W2,且用单个样本 ( X i n p u t , Y t a r g e t ) (X_{input},Y_{target}) (Xinput,Ytarget)执行梯度下降,那么只需要将 X i n p u t X_{input} Xinput, Y t a r g e t Y_{target} Ytarget 带入 ∂ E ( W 1 , W 2 ) ∂ W 2 \frac{\partial E(W_{1},W_{2})}{\partial W_{2}} ∂W2∂E(W1,W2)和 ∂ E ( W 1 , W 2 ) ∂ W 1 \frac{\partial E(W_{1},W_{2})}{\partial W_{1}} ∂W1∂E(W1,W2)对应的偏导函数表达式中,算出偏导数值后,再带入梯度下降算法公式中执行权重更新即可。
本例中所给的网络模型十分的简单,但是如果网络模型稍微复杂一些呢?
难不成我们需要计算出 E ( W 12 , W 13 , W 24 , . . . ) E(W_{12},W_{13},W_{24},...) E(W12,W13,W24,...)对网络中每一个需要优化的权重偏导函数表达式吗?这也太麻烦了,而且网络一复杂,神经网络叠加复合得到的最终复合函数表达式也会非常的复杂。
继续观察上面求出的偏导函数表达式可以看出, ∂ E ( W 1 , W 2 ) ∂ W 2 \frac{\partial E(W_{1},W_{2})}{\partial W_{2}} ∂W2∂E(W1,W2)和 ∂ E ( W 1 , W 2 ) ∂ W 1 \frac{\partial E(W_{1},W_{2})}{\partial W_{1}} ∂W1∂E(W1,W2)中 ( f 2 ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) − Y t a r g e t ) ∗ f 2 ′ ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) (f2(W_{2}*f1(W_{1}*X_{input}))-Y_{target}) * {f2}'(W_{2}*f1(W_{1}*X_{input})) (f2(W2∗f1(W1∗Xinput))−Ytarget)∗f2′(W2∗f1(W1∗Xinput))前半部分都是一样的,只有最后一部分不一致:
- ∂ E ( W 1 , W 2 ) ∂ W 2 = ( f 2 ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) − Y t a r g e t ) ∗ f 2 ′ ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) ∗ f 1 ( W 1 ∗ X i n p u t ) \frac{\partial E(W_{1},W_{2})}{\partial W_{2}} = (f2(W_{2}*f1(W_{1}*X_{input}))-Y_{target}) * {f2}'(W_{2}*f1(W_{1}*X_{input})) * f1(W_{1}*X_{input}) ∂W2∂E(W1,W2)=(f2(W2∗f1(W1∗Xinput))−Ytarget)∗f2′(W2∗f1(W1∗Xinput))∗f1(W1∗Xinput)
- ∂ E ( W 1 , W 2 ) ∂ W 1 = ( f 2 ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) − Y t a r g e t ) ∗ f 2 ′ ( W 2 ∗ f 1 ( W 1 ∗ X i n p u t ) ) ∗ W 2 ∗ f 1 ′ ( W 1 ∗ X i n p u t ) ∗ X i n p u t \frac{\partial E(W_{1},W_{2})}{\partial W_{1}} = (f2(W_{2}*f1(W_{1}*X_{input}))-Y_{target}) * {f2}'(W_{2}*f1(W_{1}*X_{input})) *W_{2}* {f1}'(W_{1}*X_{input})*X_{input} ∂W1∂E(W1,W2)=(f2(W2∗f1(W1∗Xinput))−Ytarget)∗f2′(W2∗f1(W1∗Xinput))∗W2∗f1′(W1∗Xinput)∗Xinput
这就是链式求导的特性,从最外层函数开始向内逐步对每一层的中间变量 U U U求导 , 我们可以将权重看做叶子结点,而函数的复合相当于给结点添加了一个父结点,函数的累加相当于给父结点下面添加了很多的子结点,具有很多层的神经网络,如全连接神经网络,每一层都由很多神经元组成,当前层所有神经元产生的n个输出分别乘以不同的权重加上偏置又作为下一层中某个神经元的输入,加上下一层某个神经元采用的激活函数为ReLU,那么该神经元的处理过程大概可以看作是:
R e L U ( w 1 ∗ a 1 + w 2 ∗ a 2 + w 3 ∗ a 3 + b 2 ) ReLU(w1*a1+w2*a2+w3*a3+b2) ReLU(w1∗a1+w2∗a2+w3∗a3+b2)其中 a 1 = s i g m o i d ( . . . ) a1=sigmoid(...) a1=sigmoid(...), a w = s i g m o i d ( . . . ) aw=sigmoid(...) aw=sigmoid(...), a 3 = s i g m o i d ( . . . ) a3=sigmoid(...) a3=sigmoid(...)为上一层神经元的输出,此处 w 1 ∗ a 1 + w 2 ∗ a 2 + w 3 ∗ a 3 w1*a1+w2*a2+w3*a3 w1∗a1+w2∗a2+w3∗a3就是函数的叠加,而 R e L U ( . . . ) ReLU(...) ReLU(...)为函数的复合过程,深层的神经网络不断重复着函数的叠加和复合过程,同时又产生大量需要学习的权重值,通过反复的叠加和复合,便可以让整个网络具有更好的弹性,通过不断训练找出更优秀的权重参数值,便可以去绘制出更加复杂的曲线从而对复杂数据集作出更好的划分效果。
链式求导的过程就是从根结点开始,每个分支结点依次对自己所有子结点挨个进行求导,求导时将子结点看做一个整体进行求导,也就是另中间变量U=子结点代表的整体表达式,对U求导,我们可以将对U求导的结果视为局部求导结果;
损失函数对当前层某个结点求导得到的结果等于从根结点到该结点路径上,每一层对应结点的局部求导结果的乘积之和
给这颗树起个不太严谨的名字: 变量层级树
对于深层次神经网络而言,每一次的叠加和复合都会让树增高一层,同时引入一批新的待优化权重,从而让变量层级树变的庞大且复杂,但是我们只需要从根结点开始往下进行类似层次遍历的操作,每遍历一层便可以将该层所有结点的局部导数求出来,从根结点到某个结点路径上所有结点对应的局部导数乘积之和便为到该结点为止得到的链式求导结果,所以通过一次树的层次遍历便可以将所有结点的链式求导结果得出,而所有叶子结点的链式求导结果便是我们需要的误差函数对各个权重的链式求导结果了,即表明某个权重的微小变化会对误差产生多大的影响。
所以反向传播过程可以看成是对该变量层级树至顶向下的遍历过程,而根结点就是我们误差函数的输出,分支结点为复合产生的中间变量,叶子结点就是我们的权重值。遍历过程中充分利用链式求导法则的通用前缀特性,可以省去很多重复求解的步骤,同时一次遍历变能将全部的链式求导结果得出,大大提高效率。
让情况变得复杂一些
上面给出的例子过于简单,所以可能无法很好体现出反向传播算法的厉害之处,下面我们将例子稍微复杂化一些:
该例对应变量层级树如下图所示,由于绘图空间有限,所以并没有标注出全部结点的求导结果,但是如下图所示,显而易见,我们可以通过一次层次遍历,完成所有结点的导数求解工作,这就是反向传播算法高效之处。
这里给出几个权重的链式求导结果,大家可以对照图观察一下是否符合第一个例子最后所讲的思想:
∂ E ∂ w 46 = ∂ E ∂ y o u t p u t ∗ ∂ y o u t p u t ∂ x 6 ∗ ∂ x 6 ∂ w 46 \frac{\partial E}{\partial w_{46}}=\frac{\partial E}{\partial y_{output}} * \frac{\partial y_{output}}{\partial x_{6}}* \frac{\partial x_{6}}{\partial w_{46}} ∂w46∂E=∂youtput∂E∗∂x6∂youtput∗∂w46∂x6
∂ E ∂ w 24 = ∂ E ∂ y o u t p u t ∗ ∂ y o u t p u t ∂ x 6 ∗ ∂ x 6 ∂ y 4 ∗ ∂ y 4 ∂ x 4 ∗ ∂ x 4 ∂ w 24 \frac{\partial E}{\partial w_{24}}=\frac{\partial E}{\partial y_{output}} * \frac{\partial y_{output}}{\partial x_{6}}* \frac{\partial x_{6}}{\partial y_{4}}* \frac{\partial y_{4}}{\partial x_{4}}* \frac{\partial x_{4}}{\partial w_{24}} ∂w24∂E=∂youtput∂E∗∂x6∂youtput∗∂y4∂x6∗∂x4∂y4∗∂w24∂x4
∂ E ∂ w 12 = ∂ E ∂ y o u t p u t ∗ ∂ y o u t p u t ∂ x 6 ∗ ∂ x 6 ∂ y 4 ∗ ∂ y 4 ∂ x 4 ∗ ∂ x 4 ∂ y 2 ∗ ∂ y 2 ∂ x 2 ∗ ∂ x 2 ∂ w 12 \frac{\partial E}{\partial w_{12}}=\frac{\partial E}{\partial y_{output}} * \frac{\partial y_{output}}{\partial x_{6}}* \frac{\partial x_{6}}{\partial y_{4}}* \frac{\partial y_{4}}{\partial x_{4}}* \frac{\partial x_{4}}{\partial y_{2}}* \frac{\partial y_{2}}{\partial x_{2}}* \frac{\partial x_{2}}{\partial w_{12}} ∂w12∂E=∂youtput∂E∗∂x6∂youtput∗∂y4∂x6∗∂x4∂y4∗∂y2∂x4∗∂x2∂y2∗∂w12∂x2
当我们使用反向传播算法求解出 ∂ E ∂ w i j \frac{\partial E}{\partial w_{ij}} ∂wij∂E后,针对每个权重的值的更新便可以采用梯度下降算法实现,如下所示:
w i j = w i j − α ∗ ∂ E ∂ w i j w_{ij} = w{ij} - \alpha * \frac{\partial E}{\partial w_{ij}} wij=wij−α∗∂wij∂E
E ( Y o u t p u t , Y t a r g e t ) = 1 2 ( Y o u t p u t − Y t a r g e t ) 2 E(Y_{output},Y_{target}) =\frac{1}{2}(Y_{output}-Y_{target})^{2} E(Youtput,Ytarget)=21(Youtput−Ytarget)2
这只是根据单个样本计算得出的某个权重的偏导数值进行更新,不太稳定。
因为单个样本可能包含噪声或异常值,其梯度可能不具有代表性,这会导致更新后的权重可能不是朝着全局最优方向,而是在局部波动,影响收敛速度和最终性能
通常都是计算所有样本或者一批打乱的随机样本的偏导数均值进行更新,如下所示:
E = 1 2 m ∑ i = 1 m ( Y o u t p u t ( i ) − Y t a r g e t ( i ) ) 2 E = \frac{1}{2m}\sum_{i=1}^{m}(Y_{output}^{(i)} - Y_{target}^{(i)})^{2} E=2m1i=1∑m(Youtput(i)−Ytarget(i))2
对于有限项的累加和求导,可以求出每一项的导数值后,累加起来得到最后的结果。
- 通过计算所有样本(或一批样本)的平均误差,可以得到更具代表性的梯度信息。这样的梯度计算更能反映网络在整体数据集上的性能,使用该平均梯度进行权重更新通常可以使训练过程更加稳定和有效。
- 当使用一批打乱的随机样本(随机梯度下降,SGD)时,它结合了批量梯度下降(BGD)和随机梯度下降的优点,既可以利用一定的随机性跳出局部极小值,又可以通过一批样本的平均梯度避免过度随机导致的不稳定,加快收敛速度。
未完待续
关于反向传播算法笔者目前也无法说完全理解,所以本文会不断更新,同时后续会更新反向传播算法的代码实现案例。