8.6多分类神经网络的反向传播

虽然在PyTorch里你只需要定义模型的前向传播过程并给出损失函数。PyTorch框架会帮你在后向传播时自动计算梯度并使用优化器更新参数。但是我们还是需要自己推导一次神经网络反向传播的梯度计算。这将帮助你彻底了解神经网络的训练原理,消除它的神秘感。而且了解反向传播的具体过程也是理解后边一系列神经网络训练优化技术的基础。

8.6.1网络结构

神经网络图 我们以上边这个图里展示的神经网络为例,输入feature维度为2,2个隐藏层,每层的神经元为2个,输出层有3个神经元来支持3分类任务。

8.6.2前向传播过程

我们先写出前向传播过程。 输入:

[x1x2]\begin{bmatrix} x_1& x_2 \end{bmatrix}

第一个隐藏层的logits:

[z11z21]=[x1x2][w111w121w211w221]+[b11b21]\begin{bmatrix}z_1^1& z_2^1 \end{bmatrix}=\begin{bmatrix}x_1& x_2 \end{bmatrix}\begin{bmatrix} w_{11}^1 & w_{12}^1\\ w_{21}^1 & w_{22}^1\end{bmatrix}+\begin{bmatrix} b_1^1& b_2^1 \end{bmatrix}

第一个隐藏层的输出如下。其中act()是激活函数,对logits的值逐个应用激活函数:

[a11a21]=[act(z11)act(z21)]\begin{bmatrix}a_1^1& a_2^1 \end{bmatrix}=\begin{bmatrix} act(z_1^1)& act(z_2^1) \end{bmatrix}

第一个隐藏层的输出作为第二个隐藏层的输入,则第二个隐藏层的logits为:

[z12z22]=[a11a21][w112w122w212w222]+[b12b22]\begin{bmatrix}z_1^2& z_2^2 \end{bmatrix}=\begin{bmatrix}a_1^1& a_2^1 \end{bmatrix}\begin{bmatrix} w_{11}^2 & w_{12}^2\\ w_{21}^2 & w_{22}^2\end{bmatrix}+\begin{bmatrix} b_1^2& b_2^2 \end{bmatrix}

第二个隐藏层的输出:

[a12a22]=[act(z12)act(z22)]\begin{bmatrix}a_1^2& a_2^2 \end{bmatrix}=\begin{bmatrix} act(z_1^2)& act(z_2^2) \end{bmatrix}

输出层的logits:

[z13z23z33]=[a12a22][w113w123w133w213w223w233]+[b13b23b33]\begin{bmatrix}z_1^3& z_2^3 & z_3^3 \end{bmatrix}=\begin{bmatrix}a_1^2& a_2^2 \end{bmatrix}\begin{bmatrix} w_{11}^3 & w_{12}^3& w_{13}^3\\ w_{21}^3 & w_{22}^3 & w_{23}^3\end{bmatrix}+\begin{bmatrix} b_1^3& b_2^3 & b_3^3\end{bmatrix}

输出层经过softmax:

a3=[a13a23a33],ai3=ezi3j=13ezj3a^3 = \begin{bmatrix}a_1^3& a_2^3 & a_3^3 \end{bmatrix},a_i^3=\frac{e^{z_i^3}}{\sum_{j=1}^{3}e^{z_j^3}}

输出层经过cross entropy,计算loss的公式如下:

真实标签用一维的one-hot向量表示:

y=[y1y2y3]y=\begin{bmatrix} y_1& y_2 & y_3 \end{bmatrix}

其中向量yy的元素中只有一个元素为1,其余元素为0。 则 loss公式为:

loss=(y1lna13+y2lna23+y3lna33)loss=-(y_1lna_1^3+y_2lna_2^3+y_3lna_3^3)

8.6.3反向传播过程

神经网络里每层的权重和偏置都可以看成是一个由多个参数构成的矩阵。反向传播时需要计算每个权重和偏置的梯度,实际上就是用最终的loss值对每一个参数求导,这些对单个参数的求导计算可以通过矩阵运算进行加速。后边我们会详细来解释。如果你不理解其中的过程,你可以从最终的loss对单个参数利用链式法则进行求导。你会发现和我下边讲的结果是一致的。推导的过程可能有些麻烦,但是一旦你完成一次,神经网络对你而言,就不再神秘了。

8.6.3.1 loss对logits求导

首先我们来求解loss对模型输出的logits z3z^3的偏导数。它等于loss对z13,z23,z33z_1^3,z_2^3,z_3^3分别求导,我们以loss对z13z_1^3求导为例:

lossz13=lossa13a13z13+lossa23a23z13+lossa33a33z13\frac{\partial loss}{\partial z_1^3}=\frac{\partial loss}{\partial a_1^3}\cdot\frac{\partial a_1^3}{\partial z_1^3}+\frac{\partial loss}{\partial a_2^3}\cdot\frac{\partial a_2^3}{\partial z_1^3}+\frac{\partial loss}{\partial a_3^3}\cdot\frac{\partial a_3^3}{\partial z_1^3}

=y1a13a13z13+y2a23a23z13+y3a33a33z13=\frac{-y_1}{a_1^3}\cdot\frac{\partial a_1^3}{\partial z_1^3}+\frac{-y_2}{a_2^3}\cdot\frac{\partial a_2^3}{\partial z_1^3}+\frac{-y_3}{a_3^3}\cdot\frac{\partial a_3^3}{\partial z_1^3} (式8-1)

接下来,我们分两种情况进行讨论:

第一种情况

这个样本分类结果就是第一类,这时label为:y1=1,y2=0,y3=0y_1=1,y_2=0,y_3=0,可以化简上式为: lossz13=y1a13a13z13\frac{\partial loss}{\partial z_1^3}=\frac{-y_1}{a_1^3}\cdot\frac{\partial a_1^3}{\partial z_1^3}

继续求导:

lossz13=y1a13ez13j=13ezj3(ez13)2(j=13ezj3)2\frac{\partial loss}{\partial z_1^3}=\frac{-y_1}{a_1^3}\cdot\frac{e^{z_1^3}\sum_{j=1}^{3}e^{z_j^3}-(e^{z_1^3})^2}{(\sum_{j=1}^{3}e^{z_j^3})^2}

带入以下a13a_1^3的公式进行化简:

a13=ez13j=13ezj3a_1^3=\frac{e^{z_1^3}}{\sum_{j=1}^{3}e^{z_j^3}}

化简后的结果为:

lossz13=y1a13(a13(a13)2)\frac{\partial loss}{\partial z_1^3}=\frac{-y_1}{a_1^3}\cdot (a_1^3-(a_1^3)^2)

继续化简:

lossz13=a13y1\frac{\partial loss}{\partial z_1^3}=a_1^3-y_1

第二种情况

这个样本分类结果不是第一类: 假设类别为k,k不是第一类。 则化简式8-1为:

lossz13=ykak3ak3z13\frac{\partial loss}{\partial z_1^3}=\frac{-y_k}{a_k^3}\cdot\frac{\partial a_k^3}{\partial z_1^3}

继续求导:(因为k不等于1,所以z13z_1^3仅出现在softmax的分母里。)

lossz13=ykak3ezk3ez13(j=13ezj3)2\frac{\partial loss}{\partial z_1^3}=\frac{-y_k}{a_k^3}\cdot\frac{-e^{z_k^3}e^{z_1^3}}{(\sum_{j=1}^{3}e^{z_j^3})^2}

同样,根据softmax公式进行化简:

lossz13=ykak3a13ak3=yka13\frac{\partial loss}{\partial z_1^3}=\frac{-y_k}{a_k^3}\cdot-a_1^3a_k^3=y_ka_1^3

此时,yk=1,y1=0y_k=1,y_1=0,所以可以改写为:

lossz13=a13y1\frac{\partial loss}{\partial z_1^3}=a_1^3-y_1

可以看到,两种情况都可以得到同一个结果。上边是loss对z13z_1^3求导。不失一般性,loss对zi3z_i^3求导公式为:

losszi3=ai3yi  (i=1,2,3)\frac{\partial loss}{\partial z_i^3}=a_i^3-y_i\;(i=1,2,3)

我们把loss对第三层的logits的导数记作:

δ3=[a13y1a23y2a33y3]\delta^3=\begin{bmatrix}a_1^3-y_1& a_2^3-y_2 & a_3^3-y_3 \end{bmatrix}

8.6.3.1 输出层的梯度

输出层的logits计算公式如下:

[z13z23z33]=[a12a22][w113w123w133w213w223w233]+[b13b23b33]\begin{bmatrix}z_1^3& z_2^3 & z_3^3 \end{bmatrix}=\begin{bmatrix}a_1^2& a_2^2 \end{bmatrix}\begin{bmatrix} w_{11}^3 & w_{12}^3& w_{13}^3\\ w_{21}^3 & w_{22}^3 & w_{23}^3\end{bmatrix}+\begin{bmatrix} b_1^3& b_2^3 & b_3^3\end{bmatrix}

而且上边我们已经求得了loss对输出层logits的导数。我们下边分别求loss对每一个 wij3w_{ij}^3的梯度。

我们以loss对w113w_{11}^3的偏导数为例:

lossw113=lossz13z13w113+lossz23z23w113+lossz33z33w113\frac{\partial loss}{\partial w_{11}^3}=\frac{\partial loss}{\partial z_1^3}\cdot\frac{\partial z_1^3}{\partial w_{11}^3}+\frac{\partial loss}{\partial z_2^3}\cdot\frac{\partial z_2^3}{\partial w_{11}^3}+\frac{\partial loss}{\partial z_3^3}\cdot\frac{\partial z_3^3}{\partial w_{11}^3}

因为其中只有z13z_1^3w113w_{11}^3有关,上边连加表达式的后两项z23,z33z_2^3,z_3^3w113w_{11}^3求导都为0,所以有:

lossw113=lossz13z13w113=δ13a12\frac{\partial loss}{\partial w_{11}^3}=\frac{\partial loss}{\partial z_1^3}\cdot\frac{\partial z_1^3}{\partial w_{11}^3}=\delta_1^3a_1^2

依次类推,我们可以求出每个wij3w_{ij}^3的梯度:

[δ13a12δ23a12δ33a12δ13a22δ23a22δ33a22]\begin{bmatrix} \delta_1^3a_1^2 & \delta_2^3a_1^2& \delta_3^3a_1^2\\ \delta_1^3a_2^2 & \delta_2^3a_2^2 & \delta_3^3a_2^2\end{bmatrix}

可以用矩阵运算表示如下:

lossw3=(a2)Tδ3=[a12a22][δ13δ23δ33]\frac{\partial loss}{\partial w^3}={(a^2)}^T\delta^3=\begin{bmatrix}a_1^2\\ a_2^2 \end{bmatrix}\begin{bmatrix}\delta_1^3 & \delta_2^3 & \delta_3^3\end{bmatrix}

下边我们来考虑偏置的梯度值。以loss对b13b_1^3的偏导为例:

lossb13=lossz13z13b13=δ13\frac{\partial loss}{\partial b_1^3}=\frac{\partial loss}{\partial z_1^3}\cdot\frac{\partial z_1^3}{\partial b_1^3}=\delta_1^3

同理,loss对b23,b33b_2^3,b_3^3的偏导为:δ23,δ33\delta_2^3,\delta_3^3,所以loss对于第三层偏置的偏导就等于δ3\delta^3

因为loss对于第二层参数的偏导数,需要利用链式法则,通过a2a^2进行传递,所以下边我们计算loss对于a2a^2的偏导数。

我们以loss对a12a_1^2为例:

lossa12=lossz13z13a12+lossz23z23a12+lossz33z33a12\frac{\partial loss}{\partial a_1^2}=\frac{\partial loss}{\partial z_1^3}\cdot\frac{\partial z_1^3}{\partial a_1^2}+\frac{\partial loss}{\partial z_2^3}\cdot\frac{\partial z_2^3}{\partial a_1^2}+\frac{\partial loss}{\partial z_3^3}\cdot\frac{\partial z_3^3}{\partial a_1^2}

=δ13w113+δ23w123+δ33w133=\delta_1^3w_{11}^3+\delta_2^3w_{12}^3+\delta_3^3w_{13}^3

同理,可以得到:

lossa22=δ13w213+δ23w223+δ33w233\frac{\partial loss}{\partial a_2^2}=\delta_1^3w_{21}^3+\delta_2^3w_{22}^3+\delta_3^3w_{23}^3

改为矩阵表示loss对第二层激活值的偏导为:

lossa2=δ3(w3)T=[δ13δ23δ33][w113w213w123w223w133w233]\frac{\partial loss}{\partial a^2}=\delta^3(w^3)^T=\begin{bmatrix}\delta_1^3 & \delta_2^3 & \delta_3^3\end{bmatrix}\begin{bmatrix}w_{11}^3& w_{21}^3\\w_{12}^3&w_{22}^3\\w_{13}^3&w_{23}^3\end{bmatrix}

接着,我们求loss对第二层logits值的偏导:

δ2=lossz2=lossa2a2z2=δ3(w3)Tact(z2)\delta^2=\frac{\partial loss}{\partial z^2}=\frac{\partial loss}{\partial a^2}\cdot \frac{\partial a^2}{\partial z^2}=\delta^3(w^3)^T\odot act'(z^2)

其中\odot是矩阵对应元素相乘,因为激活函数是对每个z值单独应用的,所以这里求导也是逐个元素应用的。

8.6.3.2 第二层的梯度

与上边对输出层的权重和偏置的求导方法一样,我们可以得到:

lossw2=(a1)Tδ2\frac{\partial loss}{\partial w^2}={(a^1)}^T\delta^2

loss对于第二层偏置的偏导就等于δ2\delta^2

δ1=δ2(w2)Tact(z1)\delta^1=\delta^2(w^2)^T\odot act'(z^1)

8.6.3.3 第一层的梯度

lossw1=xTδ1\frac{\partial loss}{\partial w^1}={x}^T\delta^1

loss对于第一层偏置的偏导就等于δ1\delta^1

8.6.4 各层的梯度

其中δi\delta^i表示loss对第ii层logits的偏导数。

δ3=[a13y1a23y2a33y3]\delta^3=\begin{bmatrix}a_1^3-y_1& a_2^3-y_2 & a_3^3-y_3 \end{bmatrix}

lossw3=(a2)Tδ3\frac{\partial loss}{\partial w^3}={(a^2)}^T\delta^3

lossb3=δ3\frac{\partial loss}{\partial b^3}=\delta^3

δ2=δ3(w3)Tact(z2)\delta^2=\delta^3(w^3)^T\odot act'(z^2)

lossw2=(a1)Tδ2\frac{\partial loss}{\partial w^2}={(a^1)}^T\delta^2

lossb2=δ2\frac{\partial loss}{\partial b^2}=\delta^2

δ1=δ2(w2)Tact(z1)\delta^1=\delta^2(w^2)^T\odot act'(z^1)

lossw1=xTδ1\frac{\partial loss}{\partial w^1}={x}^T\delta^1

lossb1=δ1\frac{\partial loss}{\partial b^1}=\delta^1

通过上边的推导,你应该已经可以看出来了每一层参数和偏置求导的规律。 假设这个神经网络一共有n层,第n层是输出层。x是输入向量,y是one-hot的label向量。 则:

δn=any\delta^n=a^n-y

对于第i层而言:

δi=δi+1(wi+1)Tact(zi)\delta^i=\delta^{i+1}(w^{i+1})^T\odot act'(z^i)

losswi=(ai1)Tδi\frac{\partial loss}{\partial w^i}={(a^{i-1})}^T\delta^i

lossbi=δi\frac{\partial loss}{\partial b^i}=\delta^i

第一层的输入是x:

a0=xa^0=x

8.6.5 批量数据支持

上边我们的推导是针对一条数据的,但是我们实际训练神经网络时都是用一个batch的数据进行训练的。

同样以上边的网络结构为例:

按行输入三条数据,batch size是3:

[x11x12x21x22x31x32]\begin{bmatrix} x_{11}& x_{12}\\ x_{21}& x_{22}\\ x_{31}& x_{32}\end{bmatrix}

第一个隐藏层的logits:

[z111z121z211z221z311z321]=[x11x12x21x22x31x32][w111w121w211w221]+[b11b21b11b21b11b21]\begin{bmatrix}z_{11}^1& z_{12}^1 \\z_{21}^1& z_{22}^1\\z_{31}^1& z_{32}^1\end{bmatrix}=\begin{bmatrix} x_{11}& x_{12}\\ x_{21}& x_{22}\\ x_{31}& x_{32}\end{bmatrix}\begin{bmatrix} w_{11}^1 & w_{12}^1\\ w_{21}^1 & w_{22}^1\end{bmatrix}+\begin{bmatrix} b_1^1& b_2^1\\ b_1^1& b_2^1 \\ b_1^1& b_2^1\end{bmatrix}

注意上边的偏置参数矩阵,它的三行是相同的参数。这是因为需要对每条记录的计算结果都增加偏置,所以将偏置复制了3行,这里的3是BatchSize。权重参数矩阵不变。

忽略第二个隐藏层,我们看输出层的logits:

[z113z123z133z213z223z233z313z323z333]=[a112a122a212a222a312a322][w113w123w133w213w223w233]+[b13b23b33b13b23b33b13b23b33]\begin{bmatrix}z_{11}^3& z_{12}^3 & z_{13}^3 \\z_{21}^3& z_{22}^3 & z_{23}^3\\z_{31}^3& z_{32}^3 & z_{33}^3 \end{bmatrix}=\begin{bmatrix}a_{11}^2& a_{12}^2 \\a_{21}^2& a_{22}^2\\a_{31}^2& a_{32}^2 \end{bmatrix}\begin{bmatrix} w_{11}^3 & w_{12}^3& w_{13}^3\\ w_{21}^3 & w_{22}^3 & w_{23}^3\end{bmatrix}+\begin{bmatrix} b_1^3& b_2^3 & b_3^3\\b_1^3& b_2^3 & b_3^3\\b_1^3& b_2^3 & b_3^3\end{bmatrix}

输出层对每一行应用softmax,得到:

a3=[a113a123a133a213a223a233a313a323a333]a^3 = \begin{bmatrix}a_{11}^3& a_{12}^3 & a_{13}^3 \\a_{21}^3& a_{22}^3 & a_{23}^3\\a_{31}^3& a_{32}^3 & a_{33}^3 \end{bmatrix}

label为:

y=[y11y12y13y21y22y23y31y32y33]y=\begin{bmatrix} y_{11}& y_{12} & y_{13}\\y_{21}& y_{22} & y_{23}\\y_{31}& y_{32} & y_{33}\end{bmatrix}

其中y的每一行都是one-hot编码的,也就是每行只有一个元素是1,其余为0。

loss函数为:

loss=13i=13(yi1lnai13+yi2lnai23+yi3lnai33)loss=-\frac{1}{3}\sum_{i=1}^{3} (y_{i1}lna_{i1}^3+y_{i2}lna_{i2}^3+y_{i3}lna_{i3}^3)

因为softmax是按行计算,loss计算也是按行进行计算,最终再对loss求平均,其他行的数据并不会对当前行的计算造成影响。所以3行的lossz3\frac{\partial loss}{\partial z^3}和只有一行的唯一区别就是前边多了个13\frac{1}{3}。所以:

δ3=13[a113y11a123y12a133y13a213y21a223y22a233y23a313y31a323y32a333y33]\delta^3=\frac{1}{3}\begin{bmatrix}a_{11}^3-y_{11}& a_{12}^3-y_{12} & a_{13}^3-y_{13} \\a_{21}^3-y_{21}& a_{22}^3-y_{22} & a_{23}^3-y_{23} \\a_{31}^3-y_{31}& a_{32}^3-y_{32} & a_{33}^3-y_{33} \end{bmatrix}

接下来我们分析loss对输出层权重的偏导数。以w113w_{11}^3为例:

lossw113=lossz113z113w113+lossz213z213w113+lossz313z313w113\frac{\partial loss}{\partial w_{11}^3}=\frac{\partial loss}{\partial z_{11}^3}\cdot\frac{\partial z_{11}^3}{\partial w_{11}^3}+\frac{\partial loss}{\partial z_{21}^3}\cdot\frac{\partial z_{21}^3}{\partial w_{11}^3}+\frac{\partial loss}{\partial z_{31}^3}\cdot\frac{\partial z_{31}^3}{\partial w_{11}^3}

=δ113a112+δ213a212+δ313a312=\delta_{11}^3a_{11}^2+\delta_{21}^3a_{21}^2+\delta_{31}^3a_{31}^2

你可以求出其他第三层权重的偏导数,你会发现它和只有一行输入的情况下,没有变化,依然是:

lossw3=(a2)Tδ3\frac{\partial loss}{\partial w^3}={(a^2)}^T\delta^3

接下来我们分析loss对输出层偏置的偏导数,以b13b_1^3为例:

lossb13=lossz113z113b13+lossz213z213b13+lossz313z313b13\frac{\partial loss}{\partial b_1^3}=\frac{\partial loss}{\partial z_{11}^3}\cdot\frac{\partial z_{11}^3}{\partial b_1^3}+\frac{\partial loss}{\partial z_{21}^3}\cdot\frac{\partial z_{21}^3}{\partial b_1^3}+\frac{\partial loss}{\partial z_{31}^3}\cdot\frac{\partial z_{31}^3}{\partial b_1^3}

=lossz113+lossz213+lossz313=\frac{\partial loss}{\partial z_{11}^3}+\frac{\partial loss}{\partial z_{21}^3}+\frac{\partial loss}{\partial z_{31}^3}

=δ113+δ213+δ313=\delta_{11}^3+\delta_{21}^3+\delta_{31}^3

同理可以得到:

lossb23=δ123+δ223+δ323\frac{\partial loss}{\partial b_2^3}=\delta_{12}^3+\delta_{22}^3+\delta_{32}^3

lossb33=δ133+δ233+δ333\frac{\partial loss}{\partial b_3^3}=\delta_{13}^3+\delta_{23}^3+\delta_{33}^3

注意,可以看到这里loss对b3b^3求偏导的结果和单个样本的结果不同。之前只有一个样本,δ3\delta^3也只有一行,loss对b3b^3求偏导就直接是δ3\delta^3。但是当BatchSize为3的时候,截距被复制到3行,对每一个样本都起作用。δ3\delta^3也有3行。loss对b3b^3求偏导就是δ3\delta^3的三行相加。

loss对于下一层logits的偏导和权重类似,都不受BatchSize的影响,依然为:

δi=δi+1(wi+1)Tact(zi)\delta^i=\delta^{i+1}(w^{i+1})^T\odot act'(z^i)

最终我们得到针对BatchSize为N的批量数据的梯度公式如下:

δn=1N(any)\delta^n=\frac{1}{N}(a^n-y)

对于第i层而言:

δi=δi+1(wi+1)Tact(zi)\delta^i=\delta^{i+1}(w^{i+1})^T\odot act'(z^i)

losswi=(ai1)Tδi\frac{\partial loss}{\partial w^i}={(a^{i-1})}^T\delta^i

lossbji=k=1Nδkji\frac{\partial loss}{\partial b_j^i}=\sum_{k=1}^{N}\delta_{kj}^i

第一层的输入是x:

a0=xa^0=x

后边我们会利用这些我们推导出的公式来手动实现一个神经网络的训练。

results matching ""

    No results matching ""