0%

卷积神经网络的反向传播算法

阅读本篇前,最好先阅读多层感知机的反向传播算法。反向传播的基础知识和符号定义都在该文章中。

卷积神经网络:前向传播算法

CNN输入层前向传播到卷积层

输入层的前向传播是CNN前向传播算法的第一步。一般输入层对应的都是卷积层。

我们这里还是以图像识别为例。先考虑最简单的,样本都是二维的黑白图片。这样输入层$X$就是一个矩阵,矩阵的值等于图片的各个像素位置的值。这时和卷积层相连的卷积核$W$就也是矩阵如果样本都是有 RGB 的彩色图片,这样输入 $X$ 就是 3 个矩阵,即分别对应 R,G 和 B 的矩阵,或者说是一个张量。这时和卷积层相连的卷积核$W$就也是张量,对应的最后一维的维度为 3 .即每个卷积核都是 3 个子矩阵组成。同样的方法,对于 3D 的彩色图片之类的样本,我们的输入 $X$ 可以是 4 维,5 维的张量,那么对应的卷积核 $W$ 也是个高维的张量。

不管维度多高,对于我们的输入,前向传播的过程可以表示为:

其中,上标代表层数,星号代表卷积,而b代表我们的偏倚, $\sigma$为激活函数,这里一般都是ReLU。和多层感知机的前向传播比较一下,其实形式非常的像,只是我们这儿是张量的卷积,而不是矩阵的乘法。同时由于$W$是张量,那么同样的位置,$W$参数的个数就比多层感知机多很多了。

为了简化我们的描述,本文后面如果没有特殊说明,我们都默认输入是3维的张量,即用RBG可以表示的彩色图片。

这里需要我们自己定义的CNN模型参数是:

  1. 一般我们的卷积核不止一个,比如有K个,那么我们输入层的输出,或者说第二层卷积层的对应的输入就K个。

  2. 卷积核中每个子矩阵的的大小,一般我们都用子矩阵为方阵的卷积核,比如FxF的子矩阵。

  3. 填充padding(以下简称P),我们卷积的时候,为了可以更好的识别边缘,一般都会在输入矩阵在周围加上若干圈的0再进行卷积,加多少圈则P为多少。

  4. 步幅stride(以下简称S),即在卷积过程中每次移动的像素距离大小。

   

隐藏层前向传播到卷积层

现在我们再来看普通隐藏层前向传播到卷积层时的前向传播算法。

假设隐藏层的输出是M个矩阵对应的三维张量,则输出到卷积层的卷积核也是M个子矩阵对应的三维张量。这时表达式和输入层的很像,也是

其中,上标代表层数,星号代表卷积,而 $b$ 代表我们的偏倚, $\sigma$ 为激活函数,这里一般都是ReLU。

也可以写成M个子矩阵子矩阵卷积后对应位置相加的形式,即:

和CNN输入层前向传播到卷积层的区别仅仅在于,这里的输入是隐藏层来的,而不是我们输入的原始图片样本形成的矩阵。

隐藏层前向传播到池化层

池化层的处理逻辑是比较简单的,我们的目的就是对输入的矩阵进行缩小概括。比如输入的若干矩阵是NxN维的,而我们的池化大小是 $k \times k$的区域,则输出的矩阵都是 $\frac{N}{k} \times \frac{N}{k}$ 维的。

这里需要需要我们定义的CNN模型参数是:

!. 池化区域的大小 k

  1. 池化的标准,一般是 MAX 或者 Average。

隐藏层前向传播到全连接层

由于全连接层就是普通的 多层感知机 模型结构,因此我们可以直接使用 多层感知机 的前向传播算法逻辑,即:

这里的激活函数一般是 sigmoid 或者 tanh。

经过了若干全连接层之后,最后的一层为Softmax输出层。此时输出层和普通的全连接层唯一的区别是,激活函数是softmax函数。

这里需要需要我们定义的CNN模型参数是:

  1. 全连接层的激活函数

  2. 全连接层各层神经元的个数

CNN前向传播算法小结

有了上面的基础,我们现在总结下CNN的前向传播算法。

 输入:1 个图片样本,CNN 模型的层数L和所有隐藏层的类型,对于卷积层,要定义卷积核的大小 K,卷积核子矩阵的维度 F,填充大小 P,步幅 S。对于池化层,要定义池化区域大小 k 和池化标准(MAX或Average),对于全连接层,要定义全连接层的激活函数(输出层除外)和各层的神经元个数。

输出:CNN模型的输出$a^L$

  1. 根据输入层的填充大小P,填充原始图片的边缘,得到输入张量$a^1$。

  2. 初始化所有隐藏层的参数$W,b$  

  3. for $l$=2 to $L-1$:
    3.1 如果第$l$层是卷积层,则输出为

    3.2 如果第$l$层是池化层,则输出为$ a^l= pool(a^{l-1})$, 这里的pool指按照池化区域大小k和池化标准将输入张量缩小的过程。
    3.3 如果第$l$层是全连接层,则输出为

  4. 对于输出层第L层:

以上就是 CNN 前向传播算法的过程总结。有了 CNN 前向传播算法的基础,我们后面再来理解CNN的反向传播算法就简单多了。

卷积神经网络:反向传播算法计算

池化层的误差 $\delta^l$

池化层用于削减数据量,在这一层上前向传播的数据会有损失,则在反向传播时,传播来的梯度也会有所损失。一般来说,池化层没有参数,于是仅需要计算梯度反向传播的结果。

池化层的反向传播的方法是upsample,先将矩阵还原成原大小,之后:

  • 对于最大值池化,将梯度放置于每个池化区域取得最大值的位置,其他位置为0
  • 对于平均值池化,则把的所有子矩阵的各个池化局域的值取平均后放在还原后的子矩阵位置(在池化的正向计算过程中需记录每个小区域内最大值的位置)

下面是一个upsample的例子:

例如对于矩阵:

假设经过2*2的池化,还原为原来大小:

若是最大值池化,假设每个窗口的最大值位置都是左上,则传播结果为:

若是经过平均值池化,则传播结果为:

卷积层的误差 $\delta^l$

其中 $rot180(w^{l})$ 为卷积核旋转 180 度的函数,* 为卷积符号。

举一个例子来说,对于以下卷积等式:

对于 $a_11$,有 $z_{11} = a_{11}w_{11} + a_{12}w_{12} + a_{21}w_{21} + a_{22}w_{22}$ ,仅 $z_11$ 与其有关,则有 $\nabla a_{11} = \delta_{11}w_{11}$。
对于 $a_22$,所有 $z$ 项都和该数有关,有 $\nabla a_{22} = \delta_{11}w_{22} + \delta_{12}w_{21} + \delta_{21}w_{12} + \delta_{22}w_{11}$。

依次类推,可得:

卷积层的权重梯度 $\partial C / \partial w$

对权重的梯度为:

同样对于前向传播:

对于z,有以下:

  • $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}$

有梯度:

  • $\nabla w_{11} = \delta_{11}a_{11} + \delta_{12}a_{12} + \delta_{21}a_{21} + \delta_{22}a_{22}$
  • $\nabla w_{12} = \delta_{11}a_{12} + \delta_{12}a_{13} + \delta_{21}a_{22} + \delta_{22}a_{12}$
  • $\nabla w_{21} = \delta_{11}a_{21} + \delta_{12}a_{22} + \delta_{21}a_{31} + \delta_{22}a_{32}$
  • $\nabla w_{22} = \delta_{11}a_{22} + \delta_{12}a_{23} + \delta_{32}a_{21} + \delta_{33}a_{22}$

反向传播为:

卷积层的权重梯度 $\partial C / \partial b$

偏置梯度较为简单,为上一层梯度和:

卷积神经网络:反向传播算法思想

卷积神经网络相比于多层感知机,增加了两种新的层次——卷积层与池化层。由现在我们想把同样的思想用到CNN中,很明显,CNN有些不同的地方,不能直接去套用多层感知机的反向传播算法的公式。

多层感知机反向传播的四个基本方程:

要套用多层感知机的反向传播算法到CNN,有几个问题需要解决:

  1. 池化层没有激活函数,这个问题倒比较好解决,我们可以令池化层的激活函数为 $\sigma(z)=z$,即激活后就是自己本身。这样池化层激活函数的导数为 1.

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

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

  4. 对于卷积层,由于 $w$ 使用的运算是卷积,那么从 $\delta$ 推导出该层的所有卷积核的 $w, b$ 的方式也不同。

从上面可以看出,问题1比较好解决,但是问题 2, 3, 4 就需要好好的动一番脑筋了,而问题 2, 3, 4也是解决 CNN 反向传播算法的关键所在。另外大家要注意到的是,多层感知机中的 $a^l, z^l$ 都只是一个向量,而我们 CNN 中的 $a^l, z^l$ 都是一个张量,这个张量是三维的,即由若干个输入的子矩阵组成。

下面我们就针对问题 2, 3, 4 来一步步研究CNN的反向传播算法。

在研究过程中,需要注意的是,由于卷积层可以有多个卷积核,各个卷积核的处理方法是完全相同且独立的,为了简化算法公式的复杂度,我们下面提到卷积核都是卷积层中若干卷积核中的一个。

卷积神经网络:反向传播计算公式的证明

证明 ${\delta ^l} = {upsample}\left( \delta ^{l + 1} \right) \odot \sigma ‘ \left( {z^l} \right)$

我们首先解决上面的问题2,如果已知池化层的$\delta^l$,推导出上一隐藏层的$\delta^{l-1}$。

在前向传播算法时,池化层一般我们会用 MAX 或者 Average 对输入进行池化,池化的区域大小已知。现在我们反过来,要从缩小后的误差 $\delta^l$ ,还原前一次较大区域对应的误差。

在反向传播时,我们首先会把 $\delta^l$ 的所有子矩阵矩阵大小还原成池化之前的大小,然后如果是 MAX,则把 $\delta^l$ 的所有子矩阵的各个池化局域的值放在之前做前向传播算法得到最大值的位置。如果是 Average,则把 $\delta^l$ 的所有子矩阵的各个池化局域的值取平均后放在还原后的子矩阵位置。这个过程一般叫做 upsample。

这样我们就得到了上一层 $\frac{\partial C}{\partial a_k^{l-1}}$的值,要得到 $\delta_k^{l-1}$:

其中,upsample函数完成了池化误差矩阵放大与误差重新分配的逻辑。

我们概括下,对于张量$\delta^{l-1}$,我们有:

证明 $\delta^{l-1} = \delta^{l}*rot180(w^{l}) \odot \sigma’(z^{l-1})$

对于卷积网络,前向传播公式为:

注意到 $ \delta^{l-1}$ 和 $\delta^l$ 的递推关系为:

因此要推导出 $\delta^{l-1}$ 和 $\delta^{l}$ 的递推关系,必须计算 $\frac{\partial z^{l}}{\partial z^{l-1}}$的梯度表达式。

注意到 $z^{l}$和$z^{l-1}$ 的关系为:

因此我们有:

这里的式子其实和 DNN 的类似,区别在于对于含有卷积的式子求导时,卷积核被旋转了 180 度。即式子中的 $rot180()$,翻转 180 度的意思是上下翻转一次,接着左右翻转一次。在 DNN 中这里只是矩阵的转置。那么为什么呢?由于这里都是张量,直接推演参数太多了。我们以一个简单的例子说明为啥这里求导后卷积核要翻转。

假设我们 $l-1$ 层的输出 $a^{l-1}$ 是一个 3x3 矩阵,第 $l$ 层的卷积核 $W^l$ 是一个2x2矩阵,采用 1 像素的步幅,则输出 $z^{l}$ 是一个 2x2 的矩阵。我们简化 $b^l$ 都是 $0$,则有

我们列出 $a,W,z$ 的矩阵表达式如下:

利用卷积的定义,很容易得出:

  • $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}$

接着我们模拟反向求导:

从上式可以看出,对于 $a^{l-1}$ 的梯度误差 $\nabla a^{l-1}$,等于第 $l$ 层的梯度误差乘以 $\frac{\partial z^{l}}{\partial a^{l-1}}$,而 $\frac{\partial z^{l}}{\partial a^{l-1}}$ 对应上面的例子中相关联的 $w$ 的值。假设我们的 $z$ 矩阵对应的反向传播误差是 $\delta_{11}, \delta_{12}, \delta_{21}, \delta_{22}$ 组成的 2x2 矩阵,则利用上面梯度的式子和 4 个等式,我们可以分别写出 $\nabla a^{l-1}$ 的 9 个标量的梯度。

比如对于 $a_{11}$ 的梯度,由于在 4 个等式中 $a_{11}$ 只和 $z_{11}$ 有乘积关系,从而我们有:

对于 $a_{12}$ 的梯度,由于在 4 个等式中 $a_{12}$ 和 $z_{12}, z_{11}$ 有乘积关系,从而我们有:

同样的道理我们得到:

  • $ \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}$

这上面9个式子其实可以用一个矩阵卷积的形式表示,即:

为了符合梯度计算,我们在误差矩阵周围填充了一圈0,此时我们将卷积核翻转后和反向传播的梯度误差进行卷积,就得到了前一次的梯度误差。这个例子直观的介绍了为什么对含有卷积的式子求导时,卷积核要翻转180度的原因。

以上就是卷积层的误差反向传播过程。

证明 $\frac{\partial C}{\partial w^{l}} = rot180(\delta^l*a^{l-1})$ 和 $\frac{\partial C}{\partial b^{l}} = \sum\limits_{u,v}(\delta^l)_{u,v}$

我们现在已经可以递推出每一层的梯度误差 $\delta^l$ 了,对于全连接层,可以按 DNN 的反向传播算法求该层 $W,b$ 的梯度,而池化层并没有 $W,b$,也不用求 $W,b$ 的梯度。只有卷积层的 $W,b$ 需要求出。

对于卷积网络,前向传播公式为:

又因为

那么

而对于b,则稍微有些特殊,因为 $\delta^l$ 是张量,而 $b$ 只是一个向量,不能像 DNN 那样直接和 $\delta^l$ 相等。通常的做法是将 $\delta^l$ 的各个子矩阵的项分别求和,得到一个误差向量,即为 $b$ 的梯度:


参考文献

[1] 月见樽. CNN的反向传播[DB/OL]. https://qiankun214.github.io/2018/02/21/CNN的反向传播/, 2018-06-26.

[2] oio328Loio. 神经网络学习(三)反向(BP)传播算法(1)[DB/OL]. https://blog.csdn.net/hoho1151191150/article/details/79537246, 2018-06-26.

[3] oio328Loio. 神经网络学习(十二)卷积神经网络与BP算法[DB/OL]. https://blog.csdn.net/hoho1151191150/article/details/79705332, 2018-06-26.

[4] 刘建平Pinard. 卷积神经网络(CNN)反向传播算法[DB/OL]. http://www.cnblogs.com/pinard/p/6494810.html, 2018-06-26.

[5] 刘建平Pinard. 卷积神经网络(CNN)前向传播算法[DB/OL]. http://www.cnblogs.com/pinard/p/6489633.html, 2018-06-26.

本站所有文章和源码均免费开放,如您喜欢,可以请我喝杯咖啡