卷积神经网络反向传播推导

由于导师要求自己从头到尾自己实现卷积神经网络,所以最近看了关于神经网络的反向传播内容。内容大部分都是从博客和书上摘录下来。整理完后方便自己以后复习!不喜勿喷。看完真的是清爽明朗!!!知道算法后写程序就简单多啦哈哈。

梯度下降法

我们训练神经网络的目的是找到能最小化代价函数C(w,b)C(w, b)的权重和偏置。

假设我们要最小化某些函数,C(v)C(v)。它可以是任意的多元实值函数,v=v1,v2,v=v_{1}, v_{2}, \dots
为了最小化 C(v)C(v),我们先想象CC是一个只有两个变量v1v_{1}v2v_{2}的函数。

为了更精确地描述这个问题,让我们思考一下,当我们在v1v_{1}v2v_{2}方向分别移动一个很小的量,即Δv1\Delta v_{1}Δv2\Delta v_{2}时,C(v)C(v)将会发生什么情况。微积分告诉我们CC将会有如下变化:
ΔCCv1Δv1+Cv2Δv2......(1) \Delta C \approx \frac{\partial C}{\partial v_{1}} \Delta v_{1}+\frac{\partial C}{\partial v_{2}} \Delta v_{2} ......(1)

我们要寻找一种选择Δv1\Delta v_{1}Δv2\Delta v_{2}的方法使得ΔC\Delta C为负。为了弄明白如何选择,需要定义Δv\Delta vvv变化的向量,Δv(Δv1,Δv2)T\Delta v \equiv\left(\Delta v_{1}, \Delta v_{2}\right)^{T}TT是转置符号。

我们也定义CC的梯度为偏导数的向量,(Cv1,Cv2)T\left(\frac{\partial C}{\partial v_{1}}, \frac{\partial C}{\partial v_{2}}\right)^{T}。我们用C\nabla C来表示梯度向量,即:
C(Cv1,Cv2)T \nabla C \equiv\left(\frac{\partial C}{\partial v_{1}}, \frac{\partial C}{\partial v_{2}}\right)^{T}

有了这些定义,(1)的表达式可以被重写为:
ΔCCΔv......(2) \Delta C \approx \nabla C \cdot \Delta v ......(2)

这个方程真正让我们兴奋的是它让我们看到了如何选取Δv\Delta v 才能让ΔC\Delta C为负数。假设我们选取:
Δv=ηC......(3) \Delta v=-\eta \nabla C......(3)

其中的η\eta是个很小的正数(称为学习率)。方程(2)告诉我们ΔCηCC=ηC2\Delta C \approx-\eta \nabla C \cdot \nabla C=-\eta\|\nabla C\|^{2}。由于C20\|\nabla C\|^{2} \geq 0,这保证了ΔC0\Delta C \leq 0,即,如果我们按照方程(3)的规则去改变vv,那么CC 会一直减小,不会增加。
我们用方程(3)计算Δv\Delta v,来移动位置vv
vv=vηC v \rightarrow v^{\prime}=v-\eta \nabla C

然后我们用它再次更新规则来计算下一次移动。如果我们反复持续这样做,我们将持续减小CC —— 获得一个全局的最小值。

总结一下,梯度下降算法工作的方式就是重复计算梯度C\nabla C,然后沿着相反的方向移动。

为了使梯度下降能够正确地运行,我们需要选择足够小的学习速率η\eta使得方程(2) 能得到很好的近似。如果不这样,我们会以ΔC>0\Delta C>0结束,这显然不好。同时,我们也不想η\eta 太小,因为这会使Δv\Delta v的变化极小,梯度下降算法就会运行得非常缓慢。在真正的实现中,η\eta 通常是变化的,以至方程(2) 能保持很好的近似度,但算法又不会太慢。

前面已经解释了具有两个变量的函数CC的梯度下降。但事实上,即使CC是一个具有更多变量的函数也能很好地工作。我们假设CC是一个有mm个变量v1,,vmv_{1}, \dots, v_{m}的多元函数。那么对CC 中自变量的变化Δv=(Δv1,,Δvm)T\Delta v=\left(\Delta v_{1}, \ldots, \Delta v_{m}\right)^{T}ΔC\Delta C将会变为:
ΔCCΔv \Delta C \approx \nabla C \cdot \Delta v 这里的梯度C\nabla C是向量
C(Cv1,,Cvm)T \nabla C \equiv\left(\frac{\partial C}{\partial v_{1}}, \ldots, \frac{\partial C}{\partial v_{m}}\right)^{T}

正如两个变量的情况,我们可以选取
Δv=ηC \Delta v=-\eta \nabla C

而且ΔC\Delta C的(近似)表达式(2)保证是负数。这给了我们一种方式从梯度中去取得最小值,即使CC是任意的多元函数,我们也能重复运用更新规则
vv=vηC v \rightarrow v^{\prime}=v-\eta \nabla C

可以把这个更新规则看做定义梯度下降算法。这给我们提供了一种方式去通过重复改变vv来找到函数CC的最小值。这个规则并不总是有效的 —— 有一件事能导致错误,让我们无法从梯度下降来求得函数CC的全局最小值。但在实践中,梯度下降算法通常工作地非常好,在神经网络中这是一种非常有效的方式去求代价函数的最小值,进而促进网络自身的学习。

我们怎么在神经网络中用梯度下降算法去学习呢?其思想就是利用梯度下降算法去寻找能使得代价函数代价取得最小值的权重wkw_{k}和偏置blb_{l}。为了清楚这是如何工作的,我们将用权重和偏置代替变量vjv_{j}。也就是说,现在“位置”变量有两个分量组成:wkw_{k}blb_{l},而梯度向量 C\nabla C 则有相应的分量C/wk\partial C / \partial w_{k}C/bl\partial C / \partial b_{l}。 用这些分量来写梯度下降的更新规则,我们得到:
wkwk=wkηCwkblbl=blηCbl \begin{aligned} w_{k} \rightarrow w_{k}^{\prime} &=w_{k}-\eta \frac{\partial C}{\partial w_{k}} \\ b_{l} \rightarrow b_{l}^{\prime} &=b_{l}-\eta \frac{\partial C}{\partial b_{l}} \end{aligned}

通过重复应用这一更新规则我们就能有望能找到代价函数的最小值。换句话说,这是一个能让神经网络学习的规则。

回顾二次代价函数。注意这个代价函数有着这样的形式C=1nxCxC=\frac{1}{n} \sum_{x} C_{x}即,它是遍及每个训练样本代价Cxy(x)a22C_{x} \equiv \frac{\|y(x)-a\|^{2}}{2}的平均值。在实践中,为了计算梯度C\nabla C,我们需要为每个训练输入xx单独地计算梯度值Cx\nabla C_{x},然后求平均值,C=1nxCx\nabla C=\frac{1}{n} \sum_{x} \nabla C_{x}。不幸的是,当训练输入的数量过多时会花费很多时间,这样会使学习变得相当缓慢。

有种叫做\textbf{随机梯度下降}的算法能够加速学习。其思想就是通过随机选取少量训练输入样本来计算 Cx\nabla C_{x},进行估算梯度C\nabla C。通过计算少量样本的平均值我们可以快速得到一个对于实际梯度C\nabla C的很好的估算,这有助于加速梯度下降,进而加速学习过程。

更准确地说,随机梯度下降通过随机选取少量的mm个训练输入来工作。我们将这些随机的训练输入标记为X1,X2,,XmX_{1}, X_{2}, \ldots, X_{m},并把它们称为一个小批量数据(mini-batch)。假设样本数量mm 足够大,我们期望CXj\nabla C_{X_{j}}的平均值大致相等于整个CX\nabla C_{X}的平均值,即,
j=1mCXjmxCxn=C \frac{\sum_{j=1}^{m} \nabla C_{X_{j}}}{m} \approx \frac{\sum_{x} \nabla C_{x}}{n}=\nabla C

这里的第二个求和符号是在整个训练数据上进行的。交换两边我们得到
C1mj=1mCXj \nabla C \approx \frac{1}{m} \sum_{j=1}^{m} \nabla C_{X_{j}}

证实了我们可以通过仅仅计算随机选取的小批量数据的梯度来估算整体的梯度。

为了将其明确地和神经网络的学习联系起来,假设wkw_{k}blb_{l}表示我们神经网络中权重和偏置。随机梯度下降通过随机地选取并训练输入的小批量数据来工作,
wkwk=wkηmjCXjwk w_{k} \rightarrow w_{k}^{\prime}=w_{k}-\frac{\eta}{m} \sum_{j} \frac{\partial C_{X_{j}}}{\partial w_{k}}

blbl=blηmjCXjbl b_{l} \rightarrow b_{l}^{\prime}=b_{l}-\frac{\eta}{m} \sum_{j} \frac{\partial C_{X_{j}}}{\partial b_{l}}

其中两个求和符号是在当前小批量数据中的所有训练样本XjX_{j}上进行的。然后我们再挑选另一随机选定的小批量数据去训练。直到我们用完了所有的训练输入,这被称为完成了一个训练迭代期(epoch)。然后我们就会开始一个新的训练迭代期。

神经网络的反向传播

反向传播算法最初在 1970 年代被提及,但是人们直到 David Rumelhart、Geoffrey Hinton 和Ronald Williams 的著名的 1986 年的论文中才认识到这个算法的重要性。这篇论文描述了对一些神经网络反向传播要比传统的方法更快,这使得使用神经网络来解决之前无法完成的问题变得可行。现在,反向传播算法已经是神经网络学习的重要组成部分。

反向传播预热知识

在讨论反向传播前,我们先熟悉一下基于矩阵的算法来计算网络的输出。

我们首先给出网络中权重的清晰定义。我们使用wjklw_{j k}^{l}表示从(l1)th(l-1)^{\mathrm{th}}层的 kthk^{\mathrm{th}}个神经元到lthl^{\mathrm{th}}层的jthj^{\mathrm{th}} 个神经元的链接上的\textbf{权重}。
卷积神经网络反向传播推导
我们对网络的偏置**值也会使用类似的表示。显式地,我们使用bjlb_{j}^{l}表示在lthl^{\mathrm{th}}层第jthj^{\mathrm{th}}个神经元的偏置,使用ajla_{j}^{l}表示lthl^{\mathrm{th}}层第jthj^{\mathrm{th}}个神经元的**值。
卷积神经网络反向传播推导
有了这些表示lthl^{\mathrm{th}}层的第jthj^{\mathrm{th}}个神经元的**值ajla_{j}^{l}就和(l1)th(l-1)^{\mathrm{th}}层的**值通过方程关联起来了:
ajl=σ(kwjklakl1+bjl)......(4) a_{j}^{l}=\sigma\left(\sum_{k} w_{j k}^{l} a_{k}^{l-1}+b_{j}^{l}\right)......(4)

其中求和是在(l1) th (l-1)^{\text { th }}层的所有kk个神经元上进行的。为了用矩阵的形式重写这个表达式,我们对每一层ll都定义一个权重矩阵wlw^{l}jthj^{\mathrm{th}} 在第kthk^{\mathrm{th}} 列的元素是wjklw_{j k}^{l}。类似的,对每一层ll,定义一个偏置向量blb^{l}。偏置向量的每个元素其实就是前面给出的bjlb_{j}^{l},每个元素对应于lthl^{\mathrm{th}}层的每个神经元。最后,我们定义**向量ala^{l},其元素是那些**值ajla_{j}^{l}
最后我们需要引入向量化函数(如σ\sigma)来按照矩阵形式重写公式(4})。其含义就是作用函数(如σ\sigma)到向量vv中的每个元素。我们使用σ(v)\sigma(v)表示这种按元素进行的函数作用。所以,σ(v)\sigma(v)的每个元素其实满足σ(v)j=σ(vj)\sigma(v)_{j}=\sigma\left(v_{j}\right)

了解了这些表示,方程(4)就可以写成下面这种简洁的向量形式:
al=σ(wlal1+bl) a^{l}=\sigma\left(w^{l} a^{l-1}+b^{l}\right)

在使用上述方程计算ala^{l}的过程中,我们计算了中间量zlwlal1+blz^{l} \equiv w^{l} a^{l-1}+b^{l}。 这个量其实是非常有用的:我们称zlz^{l}ll层神经元的带权输入。zlz^{l} 的每个元素是zjl=kwjklakl1+bjlz_{j}^{l}=\sum_{k} w_{j k}^{l} a_{k}^{l-1}+b_{j}^{l},其实zjlz_{j}^{l}就是第ll层第jj 个神经元的**函数的带权输入。

反向传播算法基于常规的线性代数运算 —— 诸如向量加法,向量矩阵乘法等。但是有一个运算不大常见。特别地,假设sstt是两个同样维度的向量。那么我们使用sts \odot t来表示按元素的乘积。所以sts \odot t的元素就是(st)j=sjtj(s \odot t)_{j}=s_{j} t_{j}。这种类型的按元素乘法有时候被称为 Hadamard 乘积,或者 Schur 乘积。

反向传播的四个基本方程

反向传播其实是对权重和偏置变化影响代价函数过程的理解。最终极的含义其实就是计算偏导数C/wjkl\partial C / \partial w_{j k}^{l}C/bjl\partial C / \partial b_{j}^{l}。但是为了计算这些值,我们首先引入一个中间量,δjl\delta_{j}^{l},这个我们称为在lthl^{\mathrm{th}}层第jthj^{\mathrm{th}}个神经元上的误差。

反向传播将给出计算误差 δjl\delta_{j}^{l}的流程,然后将其关联到计算C/wjkl\partial C / \partial w_{j k}^{l}C/bjl\partial C / \partial b_{j}^{l}

我们定义ll层的第jthj^{\mathrm{th}}个神经元上的误差δjl\delta_{j}^{l}
δjlCzjl \delta_{j}^{l} \equiv \frac{\partial C}{\partial z_{j}^{l}}

Czjl\frac{\partial C}{\partial z_{j}^{l}}是神经元的误差的度量。我们使用δl\delta^{l}表示关联于ll层的误差向量。反向传播会提供给我们一种计算每层的δl\delta^{l}的方法,然后将这些误差和最终我们需要的量C/wjkl\partial C / \partial w_{j k}^{l}C/bjl\partial C / \partial b_{j}^{l}联系起来。

输出层误差的方程,δL\delta^{L}:每个元素的定义如下:
δjL=CajLσ(zjL)......(BP1) \delta_{j}^{L}=\frac{\partial C}{\partial a_{j}^{L}} \sigma^{\prime}\left(z_{j}^{L}\right) ......(BP1)

右式第一个项C/ajL\partial C / \partial a_{j}^{L}表示代价随着jthj^{\mathrm{th}}输出**值的变化而变化的速度。假如CC不太依赖一个特定的输出神经元jj,那么δjL\delta_{j}^{L}就会很小,这也是我们想要的效果。右式第二项σ(zjL)\sigma^{\prime}\left(z_{j}^{L}\right)刻画了在zjLz_{j}^{L}处**函数σ\sigma变化的速度。

在 (BP1) 中的每个部分都是很好计算的。其中C/ajL\partial C / \partial a_{j}^{L}依赖于代价函数的形式。如果我们使用二次函数,那么C=12j(yjaj)2C=\frac{1}{2}\sum_{j}\left(y_{j}-a_{j}\right)^{2},则C/ajL=(ajyj)\partial C / \partial a_{j}^{L}=\left(a_{j}-y_{j}\right)

方程 (BP1) 对δL\delta^{L}来说是个按分量构成的表达式。以矩阵形式重写方程如下:
δL=aCσ(zL) \delta^{L}=\nabla_{a} C \odot \sigma^{\prime}\left(z^{L}\right)

这里aC\nabla_{a} C被定义成一个向量,其元素是偏导数C/ajL\partial C / \partial a_{j}^{L}。 在二次代价函数时,我们有aC=(aLy)\nabla_{a} C=\left(a^{L}-y\right),所以 (BP1) 的整个矩阵形式就变成
δL=(aLy)σ(zL) \delta^{L}=\left(a^{L}-y\right) \odot \sigma^{\prime}\left(z^{L}\right)

使用下一层的误差δl+1\delta^{l+1}来表示当前层的误差δl\delta^{l}: 特别地,
δl=((wl+1)Tδl+1)σ(zl)......(BP2) \delta^{l}=\left(\left(w^{l+1}\right)^{T} \delta^{l+1}\right) \odot \sigma^{\prime}\left(z^{l}\right) ......(BP2)

其中(wl+1)T\left(w^{l+1}\right)^{T}(l+1)th(l+1)^{\mathrm{th}}层权重矩阵wl+1w^{l+1} 的转置。假设我们知道l+1thl+1^{\mathrm{th}}层的误差 δl+1\delta^{l+1}。当我们应用转置的权重矩阵(wl+1)T\left(w^{l+1}\right)^{T},我们可以凭直觉地把它看作是在沿着网络反向移动误差,给了我们度量在lthl^{\mathrm{th}}层输出的误差方法。然后,我们进行 Hadamard 乘积运算σ(zl)\odot \sigma^{\prime}\left(z^{l}\right)。这会让误差通过ll层的**函数反向传递回来并给出在第 ll 层的带权输入的误差δ\delta

通过组合 (BP1) 和 (BP2),我们可以计算任何层的误差δl\delta^{l}。首先使用 (BP1) 计算δL\delta^{L},然后应用方程 (BP2) 来计算δL1\delta^{L-1},然后再次用方程 (BP2) 来计算δL2\delta^{L-2},如此一步一步地反向传播完整个网络。

代价函数关于网络中任意偏置的改变率: 就是
Cbjl=δjl......(BP3) \frac{\partial C}{\partial b_{j}^{l}}=\delta_{j}^{l}......(BP3)

这其实是,误差δjl\delta_{j}^{l}和偏导数值C/bjl\partial C / \partial b_{j}^{l}完全一致。这是很好的性质,因为 (BP1) 和 (BP2) 已经告诉我们如何计算δjl\delta_{j}^{l}。所以就可以将(BP3) 简记为
Cb=δ \frac{\partial C}{\partial b}=\delta

其中δ\delta和偏置bb都是针对同一个神经元。

代价函数关于任何一个权重的改变率:特别地,
Cwjkl=akl1δjl......(BP4) \frac{\partial C}{\partial w_{j k}^{l}}=a_{k}^{l-1} \delta_{j}^{l}......(BP4)

这告诉我们如何计算偏导数C/wjkl\partial C / \partial w_{j k}^{l},其中δl\delta^{l}al1a^{l-1}这些量我们都已经知道如何计算了。方程也可以写成下面用更少下标的表示:
Cw=ainδout \frac{\partial C}{\partial w}=a_{\mathrm{in}} \delta_{\mathrm{out}}

其中aina_{\mathrm{in}}是输入给权重ww的神经元的**值,δ out \delta_{\text { out }}是输出自权重ww的神经元的误差。
卷积神经网络反向传播推导

四个基本方程的证明

我们现在证明这四个基本的方程 (BP1)–(BP4)。所有这些都是多元微积分的链式法则的推论。

从方程 (BP1) 开始,它给出了输出误差δL\delta^{L}的表达式:
δjL=CzjL \delta_{j}^{L}=\frac{\partial C}{\partial z_{j}^{L}}

应用链式法则,我们可以就输出**值的偏导数的形式重新表示上面的偏导数:
δjL=kCakLakLzjL \delta_{j}^{L}=\sum_{k} \frac{\partial C}{\partial a_{k}^{L}} \frac{\partial a_{k}^{L}}{\partial z_{j}^{L}}

这里求和是在输出层的所有神经元kk上运行的。当然,第k th k^{\text { th }}个神经元的输出**值akLa_{k}^{L}只依赖于当k=jk=j时第j th j^{\text { th }}个神经元的输入权重zjLz_{j}^{L}。所以当 kjk \neq jakL/zjL\partial a_{k}^{L} / \partial z_{j}^{L}消失了。结果我们可以简化上一个方程为:
δjL=CajLajLzjL \delta_{j}^{L}=\frac{\partial C}{\partial a_{j}^{L}} \frac{\partial a_{j}^{L}}{\partial z_{j}^{L}}

又因为ajL=σ(zjL)a_{j}^{L}=\sigma\left(z_{j}^{L}\right),右边的第二项可以写为σ(zjL)\sigma^{\prime}\left(z_{j}^{L}\right),方程变成:
δjL=CajLσ(zjL) \delta_{j}^{L}=\frac{\partial C}{\partial a_{j}^{L}} \sigma^{\prime}\left(z_{j}^{L}\right)

这正是分量形式的 (BP1)。
下一步,我们将证明 (BP2),它给出了以下一层误差δl+1\delta^{l+1}的形式表示误差 δl\delta^{l}。为此,我们想要以δkl+1=C/zkl+1\delta_{k}^{l+1}=\partial C / \partial z_{k}^{l+1}的形式重写δjl=C/zjl\delta_{j}^{l}=\partial C / \partial z_{j}^{l}。我们可以用链式法则:
δjl=Czjl=kCzkl+1zkl+1zjl=kzkl+1zjlδkl+1 \begin{aligned} \delta_{j}^{l} &=\frac{\partial C}{\partial z_{j}^{l}} \\ &=\sum_{k} \frac{\partial C}{\partial z_{k}^{l+1}} \frac{\partial z_{k}^{l+1}}{\partial z_{j}^{l}} \\ &=\sum_{k} \frac{\partial z_{k}^{l+1}}{\partial z_{j}^{l}} \delta_{k}^{l+1} \end{aligned}

这里最后一行我们交换了右边的两项,并用δkl+1\delta_{k}^{l+1}的定义代入。为了对最后一行的第一项求值,注意:
zkl+1=jwkjl+1ajl+bkl+1=jwkjl+1σ(zjl)+bkl+1 z_{k}^{l+1}=\sum_{j} w_{k j}^{l+1} a_{j}^{l}+b_{k}^{l+1}=\sum_{j} w_{k j}^{l+1} \sigma\left(z_{j}^{l}\right)+b_{k}^{l+1}

做微分,我们得到
zkl+1zjl=wkjl+1σ(zjl) \frac{\partial z_{k}^{l+1}}{\partial z_{j}^{l}}=w_{k j}^{l+1} \sigma^{\prime}\left(z_{j}^{l}\right)

把它代入 (42) 我们得到
δjl=kwkjl+1δkl+1σ(zjl) \delta_{j}^{l}=\sum_{k} w_{k j}^{l+1} \delta_{k}^{l+1} \sigma^{\prime}\left(z_{j}^{l}\right)

这正是以分量形式写的 (BP2)。

最后两个方程(BP3) 和 (BP4)的证明它们同样遵循链式法则,和前面两个方程的证明相似。

反向传播算法

反向传播方程给出了一种计算代价函数梯度的方法。让我们显式地用算法描述出来:

  1. 输入xx: 为输入层设置对应的**值a1a^{1}

  2. 前向传播: 对每个l=2,3,,Ll=2,3, \dots, L计算相应的zl=wlal1+blz^{l}=w^{l} a^{l-1}+b^{l}al=σ(zl)a^{l}=\sigma\left(z^{l}\right)

  3. 输出层误差 δL\delta^{L}: 计算向量δL=aCσ(zL)\delta^{L}=\nabla_{a} C \odot \sigma^{\prime}\left(z^{L}\right)

  4. 反向误差传播: 对每个l=L1,L2,,2l=L-1, L-2, \ldots, 2,计算δl=((wl+1)Tδl+1)σ(zl)\delta^{l}=\left(\left(w^{l+1}\right)^{T} \delta^{l+1}\right) \odot \sigma^{\prime}\left(z^{l}\right)

  5. 输出: 代价函数的梯度由Cwjkl=akl1δjl\frac{\partial C}{\partial w_{j k}^{l}}=a_{k}^{l-1} \delta_{j}^{l}Cbjl=δjl\frac{\partial C}{\partial b_{j}^{l}}=\delta_{j}^{l}得出

卷积神经网络的反向传播

由于CNN的运算过程与DNN不一样,所以CNN的反向传播过程也有所不同。

1.池化层在前向传播的时候,对输入进行了压缩,那么我们现在需要向前反向推导
δl1\delta^{l-1},这个推导方法和DNN完全不同。

2.卷积层是通过张量卷积,或者说若干个矩阵卷积求和而得的当前层的输出,这和DNN很不相同,DNN的全连接层是直接进行矩阵乘法得到当前层的输出。这样在卷积层反向传播的时候,上一层的δl1\delta^{l-1} 递推计算方法肯定有所不同。

3.对于卷积层,由于WW使用的运算是卷积,那么从推导出该层的所有卷积核的WWbb的梯度方式也不同。

对于这三个问题,我们一个一个来解决。

已知池化层的δl\delta^{l}推导上一层的δl1\delta^{l-1},这个过程一般称为upsample

假设池化的size为2*2,δl\delta^{l}
δl=[2345] \delta^{l}=\left[ \begin{array}{ll}{2} & {3} \\ {4} & {5}\end{array}\right]

由于池化size为2*2,首先将size还原:
[0000023004500000] \left[ \begin{array}{llll}{0} & {0} & {0} & {0} \\ {0} & {2} & {3} & {0} \\ {0} & {4} & {5} & {0} \\ {0} & {0} & {0} & {0}\end{array}\right]

假设是最大池化,并且之前记录的最大值的位置为左上,右下,右上,左下。那么
δl1\delta ^{l-1}:
δl1=[2000000304000050] \delta^{l-1}=\left[ \begin{array}{llll}{2} & {0} & {0} & {0} \\ {0} & {0} & {0} & {3} \\ {0} & {4} & {0} & {0} \\ {0} & {0} & {5} & {0}\end{array}\right]

解释下为什么要这么做,在正向传播的时候,池化之前的四个最大值位置左上,右下,右上,左下,都以比例为1的系数传递到下一层。而其他位置对输出的贡献都为0,也就是说对池化输出没有影响,因此比例系数可以理解为0。所以在正向传播的过程中,最大值所在位置可以理解为通过函数f(x)=xf(x)=x传递到下一层,而其他位置则通过f(x)=0f(x)=0传递到下一层,并且把这些值相加构成下一层的输出,虽然f(x)=0f(x)=0并没有作用,但这样也就不难理解反向传播时,把的各个值移到最大值所在位置,而其他位置为0了。因为由f(x)=xf(x)=x,最大值位置的偏导数为1,而f(x)=0f(x)=0的偏导数为0。

如果是平均池化,那么δl1\delta ^{l-1}
δl1=[0.50.50.750.750.50.50.750.75111.251.25111.251.25] \delta^{l-1}=\left[ \begin{array}{cccc}{0.5} & {0.5} & {0.75} & {0.75} \\ {0.5} & {0.5} & {0.75} & {0.75} \\ {1} & {1} & {1.25} & {1.25} \\ {1} & {1} & {1.25} & {1.25}\end{array}\right]

平均池化的话,池化操作的四个位置传递到下一层的作用可以等价为f(x)=x/4f(x)=x/4,所以在方向传播过程中就相当于把δl\delta ^{l}每一个位置的值乘1/4再还原回去。

所以由δl\delta ^{l}推导δl1\delta ^{l-1}可以总结为:
δl1=upsample(δl)σ(zl1) \delta^{l-1}=u p s a m p l e\left(\delta^{l}\right) \odot \sigma^{\prime}\left(z^{l-1}\right)

等式右边第一项表示上采样,第二项是**函数的导数,在池化中可以理解为常数1(因为池化过程的正向传播过程中没有**函数)。

已知卷积层的δl\delta ^{l}推导上一层的δl1\delta ^{l-1}
δl1=δlzlzl1=δlrot180(Wl)σ(zl1) \delta^{l-1}=\delta^{l} \frac{\partial z^{l}}{\partial z^{l-1}}=\delta^{l} * r o t 180\left(W^{l}\right) \odot \sigma^{\prime}\left(z^{l-1}\right)

首先由链式法则:
δl1=Czlzlal1σ(zl1) \delta^{l-1}=\frac{\partial C}{\partial z^{l}} \frac{\partial z^{l}}{\partial a^{l-1}} \odot \sigma^{\prime}\left(z^{l-1}\right)

rot180(wl)rot180({w^{l}})代表对卷积核进行翻转180°的操作,σ(zl1){\sigma }'(z^{l-1})为**函数的导数。这里比较难理解的是为什么要对卷积核进行180°的翻转。

假设我们l1l-1层的输出al1a^{l-1}是一个3x3矩阵,第l层的卷积核WW是一个2x2矩阵,采用1像素的步幅,则输出zlz^{l}是一个2x2的矩阵。这里暂时不考虑偏置项bb的影响。
那么可得:
al1Wl=zl a^{l-1} * W^{l}=z^{l}

即:
(a11a12a13a21a22a23a31a32a33)(w11w12w21w22)=(z11z12z21z22) \left( \begin{array}{lll}{a_{11}} & {a_{12}} & {a_{13}} \\ {a_{21}} & {a_{22}} & {a_{23}} \\ {a_{31}} & {a_{32}} & {a_{33}}\end{array}\right) * \left( \begin{array}{ll}{w_{11}} & {w_{12}} \\ {w_{21}} & {w_{22}}\end{array}\right)=\left( \begin{array}{ll}{z_{11}} & {z_{12}} \\ {z_{21}} & {z_{22}}\end{array}\right)

展开后得到:
z11=a11w11+a12w12+a21w21+a22w22z12=a12w11+a13w12+a22w21+a23w22z21=a21w11+a22w12+a31w21+a32w22z22=a22w11+a23w12+a32w21+a33w22 \begin{array}{l}{z_{11}=a_{11} w_{11}+a_{12} w_{12}+a_{21} w_{21}+a_{22} w_{22}} \\ {z_{12}=a_{12} w_{11}+a_{13} w_{12}+a_{22} w_{21}+a_{23} w_{22}} \\ {z_{21}=a_{21} w_{11}+a_{22} w_{12}+a_{31} w_{21}+a_{32} w_{22}} \\ {z_{22}=a_{22} w_{11}+a_{23} w_{12}+a_{32} w_{21}+a_{33} w_{22}}\end{array}

ala^{l}的梯度:
al1=J(W,b)al1=J(W,b)zlzlal1=δlzlal1 \nabla a^{l-1}=\frac{\partial J(W, b)}{\partial a^{l-1}}=\frac{\partial J(W, b)}{\partial z^{l}} \frac{\partial z^{l}}{\partial a^{l-1}}=\delta^{l} \frac{\partial z^{l}}{\partial a^{l-1}}

又由展开式可知:
a11a_{11}只与z11z_{11}有关,并且系数为w11w_{11},所以有:
a11=δ11w11 \nabla a_{11}=\delta_{11} w_{11}

a12a_{12}只与z11z_{11}z12z_{12}有关,并且系数分别为w11w_{11}w12w_{12}所以:
a12=δ11w12+δ12w11 \nabla a_{12}=\delta_{11} w_{12}+\delta_{12} w_{11}

同理可以得到:
a13=δ12w12a21=δ11w21+δ21w11a22=δ11w22+δ12w21+δ21w12+δ22w11a23=δ12w22+δ22w12a31=δ21w21a32=δ21w22+δ22w21a33=δ22w22 \begin{array}{c}{\nabla a_{13}=\delta_{12} w_{12}} \\ {\nabla a_{21}=\delta_{11} w_{21}+\delta_{21} w_{11}} \\ {\nabla a_{22}=\delta_{11} w_{22}+\delta_{12} w_{21}+\delta_{21} w_{12}+\delta_{22} w_{11}} \\ {\nabla a_{23}=\delta_{12} w_{22}+\delta_{22} w_{12}} \\ {\nabla a_{31}=\delta_{21} w_{21}} \\ {\nabla a_{32}=\delta_{21} w_{22}+\delta_{22} w_{21}} \\ {\nabla a_{33}=\delta_{22} w_{22}}\end{array}

使用矩阵形式表示就是:
(00000δ11δ1200δ21δ2200000)(w22w21w12w11)=(a11a12a13a21a22a23a31a32a33) \left( \begin{array}{cccc}{0} & {0} & {0} & {0} \\ {0} & {\delta_{11}} & {\delta_{12}} & {0} \\ {0} & {\delta_{21}} & {\delta_{22}} & {0} \\ {0} & {0} & {0} & {0}\end{array}\right) * \left( \begin{array}{cc}{w_{22}} & {w_{21}} \\ {w_{12}} & {w_{11}}\end{array}\right)=\left( \begin{array}{ccc}{\nabla a_{11}} & {\nabla a_{12}} & {\nabla a_{13}} \\ {\nabla a_{21}} & {\nabla a_{22}} & {\nabla a_{23}} \\ {\nabla a_{31}} & {\nabla a_{32}} & {\nabla a_{33}}\end{array}\right)

这就解释了为什么在反向传播时需要将卷积核进行180°的翻转操作了。

已知卷积层的δl\delta ^{l}推导ww,bb的梯度

全连接层中的ww,bb的梯度与DNN中的推导一致,池化层没有ww,bb参数,所以不用进行ww,bb 梯度的推导。

对于卷积层正向传播过程:
zl=al1Wl+b z^{l}=a^{l-1} * W^{l}+b

所以参数ww的梯度:
J(W,b)Wl=J(W,b)zlzlWl=al1δl \frac{\partial J(W, b)}{\partial W^{l}}=\frac{\partial J(W, b)}{\partial z^{l}} \frac{\partial z^{l}}{\partial W^{l}}=a^{l-1} * \delta^{l}

注意到这里我们并没有使用翻转180°的操作。因为由之前的展开式:
z11=a11w11+a12w12+a21w21+a22w22z12=a12w11+a13w12+a22w21+a23w22z21=a21w11+a22w12+a31w21+a32w22z22=a22w11+a23w12+a32w21+a33w22 \begin{array}{l}{z_{11}=a_{11} w_{11}+a_{12} w_{12}+a_{21} w_{21}+a_{22} w_{22}} \\ {z_{12}=a_{12} w_{11}+a_{13} w_{12}+a_{22} w_{21}+a_{23} w_{22}} \\ {z_{21}=a_{21} w_{11}+a_{22} w_{12}+a_{31} w_{21}+a_{32} w_{22}} \\ {z_{22}=a_{22} w_{11}+a_{23} w_{12}+a_{32} w_{21}+a_{33} w_{22}}\end{array}

J(W,b)W11l=a11δ11+a12δ12+a21δ21+a22δ22J(W,b)W12l=a12δ11+a13δ12+a22δ21+a23δ22J(W,b)W21l=a13δ11+a14δ12+a23δ21+a24δ22J(W,b)W22l=a21δ11+a22δ12+a31δ21+a32δ22 \begin{array}{l}{\frac{\partial J(W, b)}{\partial W_{11}^{l}}=a_{11} \delta_{11}+a_{12} \delta_{12}+a_{21} \delta_{21}+a_{22} \delta_{22}} \\ {\frac{\partial J(W, b)}{\partial W_{12}^{l}}=a_{12} \delta_{11}+a_{13} \delta_{12}+a_{22} \delta_{21}+a_{23} \delta_{22}} \\ {\frac{\partial J(W, b)}{\partial W_{21}^{l}}=a_{13} \delta_{11}+a_{14} \delta_{12}+a_{23} \delta_{21}+a_{24} \delta_{22}} \\ {\frac{\partial J(W, b)}{\partial W_{22}^{l}}=a_{21} \delta_{11}+a_{22} \delta_{12}+a_{31} \delta_{21}+a_{32} \delta_{22}}\end{array}

所以ww的梯度:
J(W,b)Wl=(a11a12a13a14a21a22a23a24a31a32a33a34a41a42a43a44)(δ11δ12δ21δ22) \frac{\partial J(W, b)}{\partial W^{l}}=\left( \begin{array}{llll}{a_{11}} & {a_{12}} & {a_{13}} & {a_{14}} \\ {a_{21}} & {a_{22}} & {a_{23}} & {a_{24}} \\ {a_{31}} & {a_{32}} & {a_{33}} & {a_{34}} \\ {a_{41}} & {a_{42}} & {a_{43}} & {a_{44}}\end{array}\right) * \left( \begin{array}{cc}{\delta_{11}} & {\delta_{12}} \\ {\delta_{21}} & {\delta_{22}}\end{array}\right)

这也就是没有进行翻转的原因。

bb的梯度:

这里假设w=0w=0,那么z=bz=b,梯度δl\delta ^{^{l}}是三维张量,而bb只是一个向量,不能像普通网络中那样直接和δl\delta ^{^{l}}相等。通常的做法是将误差δ\delta的各个子矩阵的项分别求和,得到一个误差向量所以这里bb的梯度就是δl\delta ^{^{l}} 的各个通道对应位置求和:
J(W,b)bl=u,v(δl)u,v \frac{\partial J(W, b)}{\partial b^{l}}=\sum_{u, v}\left(\delta^{l}\right)_{u, v}

得到的是一个误差向量。

总结一下CNN的反向传播过程:

1 池化层的误差反向传播
δl1=upsample(δl)σ(zl1) \delta^{l-1}=u p s a m p l e\left(\delta^{l}\right) \odot \sigma^{\prime}\left(z^{l-1}\right)

2 卷积层的误差反向传播
δl1=δlzlzl1=δlrot180(Wl)σ(zl1) \delta^{l-1}=\delta^{l} \frac{\partial z^{l}}{\partial z^{l-1}}=\delta^{l} * \operatorname{rot} 180\left(W^{l}\right) \odot \sigma^{\prime}\left(z^{l-1}\right)

3 参数更新
J(W,b)Wl=J(W,b)zlzlWl=al1δl \frac{\partial J(W, b)}{\partial W^{l}}=\frac{\partial J(W, b)}{\partial z^{l}} \frac{\partial z^{l}}{\partial W^{l}}=a^{l-1} * \delta^{l}

J(W,b)bl=u,v(δl)u,v \frac{\partial J(W, b)}{\partial b^{l}}=\sum_{u, v}\left(\delta^{l}\right)_{u, v}

参考文献

[1]https://blog.****.net/u013093426/article/details/81086396 (手把手教你搭建卷积神经网络(CNN))

[2]https://www.cnblogs.com/charlotte77/p/7783261.htm (【深度学习系列】卷积神经网络详解(二)——自己手写一个卷积神经网络)

[3]https://www.cnblogs.com/pinard/p/6494810.htm (卷积神经网络(CNN)反向传播算法)

[4]https://www.jianshu.com/p/8ad58a170fd (反向传播算法推导-卷积神经)

[5]https://blog.****.net/weixin_40446651/article/details/81516944 (深层神经网络和卷积神经网络的反向传播过程推导)

[6]神经网络与深度学习中文版