在前面我们讲述了DNN的模型与前向反向传播算法。而在DNN大类中,卷积神经网络(Convolutional Neural Networks,以下简称CNN)是最为成功的DNN特例之一。CNN广泛的应用于图像识别,当然现在也应用于NLP等其他领域。
本文我们就对CNN的模型结构做一个总结。然后在此基础上,介绍CNN的前向传播算法和反向传播算法。
在学习CNN前,推荐大家先学习DNN的知识。如果不熟悉DNN而去直接学习CNN,难度会比较大。这是DNN的教程的链接:
深度学习(一):DNN前向传播算法和反向传播算法
深度学习(二):DNN损失函数和激活函数的选择
深度学习(三):DNN的正则化策略综述
一、卷积神经网络(CNN)模型结构
1.1 CNN的基本结构
首先我们来看看CNN的基本结构。一个常见的CNN例子如下图:
图中是一个图形识别的CNN模型。可以看出最左边的船的图像就是我们的输入层,计算机理解为输入若干个矩阵,这点和DNN基本相同。
接着是卷积层(Convolution Layer),这个是CNN特有的,我们后面专门来讲。卷积层的激活函数使用的是ReLU。我们在DNN中介绍过ReLU的激活函数,它其实很简单,就是 R e L U ( x ) = m a x ( 0 , x ) ReLU(x)=max(0,x) ReLU(x)=max(0,x)。在卷积层后面是池化层(Pooling layer),这个也是CNN特有的,我们后面也会专门来讲。需要注意的是,池化层没有激活函数。
卷积层+池化层的组合可以在隐藏层出现很多次,上图中出现两次。而实际上这个次数是根据模型的需要而来的。当然我们也可以灵活使用使用卷积层+卷积层,或者卷积层+卷积层+池化层的组合,这些在构建模型的时候没有限制。但是最常见的CNN都是若干卷积层+池化层的组合,如上图中的CNN结构。
在若干卷积层+池化层后面是全连接层(Fully Connected Layer, 简称FC),全连接层其实就是我们前面讲的DNN结构,只是输出层使用了Softmax激活函数来做图像识别的分类,这点我们在DNN中也有讲述。
从上面CNN的模型描述可以看出,CNN相对于DNN,比较特殊的是卷积层和池化层,如果我们熟悉DNN,只要把卷积层和池化层的原理搞清楚了,那么搞清楚CNN就容易很多了。
1.2 CNN中的卷积层
CNN中的卷积,简单来说,就是对输入的图像的不同局部的矩阵和卷积核矩阵各个位置的元素相乘,然后相加得到。
举个例子如下,图中的输入是一个二维的3x4的矩阵,而卷积核是一个2x2的矩阵。这里我们假设卷积是一次移动一个像素来卷积的,那么首先我们对输入的左上角2x2局部和卷积核卷积,即各个位置的元素相乘再相加,得到的输出矩阵S的 S 00 S_{00} S00的元素,值为 a w + b x + e y + f z aw+bx+ey+fz aw+bx+ey+fz。接着我们将输入的局部向右平移一个像素,现在是 ( b , c , f , g ) (b,c,f,g) (b,c,f,g)四个元素构成的矩阵和卷积核来卷积,这样我们得到了输出矩阵 S S S的 S 01 S_{01} S01的元素,同样的方法,我们可以得到输出矩阵 S S S的 S 02 S_{02} S02, S 10 S_{10} S10, S 11 S_{11} S11, S 12 S_{12} S12的元素。
最终我们得到卷积输出的矩阵为一个2x3的矩阵 S S S。
再举一个动态的卷积过程的例子如下:
我们有下面这个绿色的5x5输入矩阵,卷积核是一个下面这个黄色的3x3的矩阵。卷积的步幅是一个像素。则卷积的过程如下面的动图。卷积的结果是一个3x3的矩阵。
上面举的例子都是二维的输入,卷积的过程比较简单,那么如果输入是多维的呢?比如在前面一组卷积层+池化层的输出是3个矩阵,这3个矩阵作为输入呢,那么我们怎么去卷积呢?又比如输入的是对应RGB的彩色图像,即是三个分布对应R,G和B的矩阵呢?
在斯坦福大学的cs231n的课程上,有一个动态的例子,链接在这。建议大家对照着例子中的动图看下面的讲解。
大家打开这个例子可以看到,这里面输入是3个7x7的矩阵。实际上原输入是3个5x5的矩阵。只是在原来的输入周围加上了1的padding,即将周围都填充一圈的0,变成了3个7x7的矩阵。
例子里面使用了两个卷积核,我们先关注于卷积核W0。和上面的例子相比,由于输入是3个7x7的矩阵,或者说是7x7x3的张量,则我们对应的卷积核W0也必须最后一维是3的张量,这里卷积核W0的单个子矩阵维度为3x3。那么卷积核W0实际上是一个3x3x3的张量。同时和上面的例子比,这里的步幅为2,也就是每次卷积后会移动2个像素的位置。
最终的卷积过程和上面的2维矩阵类似,上面是矩阵的卷积,即两个矩阵对应位置的元素相乘后相加。这里是张量的卷积,即两个张量的3个子矩阵卷积后,再把卷积的结果相加后再加上偏倚b。其实我们仔细分析,可以得到:一个卷积kernel后的值类比就是全连接层的神经元,kernel中的权重就是这个神经元的权重。
7x7x3的张量和3x3x3的卷积核张量W0卷积的结果是一个3x3的矩阵。由于我们有两个卷积核W0和W1,因此最后卷积的结果是两个3x3的矩阵。或者说卷积的结果是一个3x3x2的张量。
仔细回味下卷积的过程,输入是7x7x3的张量,卷积核是两个3x3x3的张量。卷积步幅为2,最后得到了输出是3x3x2的张量。如果把上面的卷积过程用数学公式表达出来就是:
s
(
i
,
j
)
=
(
X
∗
W
)
(
i
,
j
)
+
b
=
∑
k
=
1
n
_
i
n
(
X
k
∗
W
k
)
(
i
,
j
)
+
b
s(i,j)=(X*W)(i,j) + b = \sum\limits_{k=1}^{n\_in}(X_k*W_k)(i,j) +b
s(i,j)=(X∗W)(i,j)+b=k=1∑n_in(Xk∗Wk)(i,j)+b
其中, n _ i n n\_{in} n_in为输入矩阵的个数,或者是张量的最后一维的维数。 X k X_k Xk代表第 k k k个输入矩阵。 W k W_k Wk代表卷积核的第 k k k个子卷积核矩阵。 s ( i , j ) s(i,j) s(i,j)即卷积核 W W W对应的输出矩阵的对应位置元素的值。特别需要注意得是: ∗ * ∗代表卷积,并非普通的乘法。这个在后面要反复用到。
通过上面的例子,相信大家对CNN的卷积层的卷积过程有了一定的了解。
对于卷积后的输出,一般会通过ReLU激活函数,将输出的张量中的小于0的位置对应的元素值都变为0。
1.3 CNN中的池化层
相比卷积层的复杂,池化层则要简单的多,所谓的池化,个人理解就是对输入张量的各个子矩阵进行压缩。假如是2x2的池化,那么就将子矩阵的每2x2个元素变成一个元素,如果是3x3的池化,那么就将子矩阵的每3x3个元素变成一个元素,这样输入矩阵的维度就变小了。
要想将输入子矩阵的每 n n nx n n n个元素变成一个元素,那么需要一个池化标准。常见的池化标准有2个,MAX或者是Average。即取对应区域的最大值或者平均值作为池化后的元素值。
下面这个例子采用取最大值的池化方法。同时采用的是2x2的池化。步幅为2。
首先对红色2x2区域进行池化,由于此2x2区域的最大值为6。那么对应的池化输出位置的值为6,由于步幅为2,此时移动到绿色的位置去进行池化,输出的最大值为8。同样的方法,可以得到黄色区域和蓝色区域的输出值。最终,我们的输入4x4的矩阵在池化后变成了2x2的矩阵。进行了压缩。
二、卷积神经网络(CNN)前向传播算法
2.1 回顾CNN的结构
在上一章里,我们已经讲到了CNN的结构,包括输出层,若干的卷积层+ReLU激活函数,若干的池化层,DNN全连接层,以及最后的用Softmax激活函数的输出层。这里我们用一个彩色的汽车样本的图像识别再从感官上回顾下CNN的结构。图中的CONV即为卷积层,POOL即为池化层,而FC即为DNN全连接层,包括了我们上面最后的用Softmax激活函数的输出层。
从上图可以看出,要理顺CNN的前向传播算法,重点是输入层的前向传播,卷积层的前向传播以及池化层的前向传播。而DNN全连接层和用Softmax激活函数的输出层的前向传播算法我们在讲DNN时已经讲到了。
2.2 CNN输入层前向传播到卷积层
输入层的前向传播是CNN前向传播算法的第一步。一般输入层对应的都是卷积层,因此我们标题是输入层前向传播到卷积层。
我们这里还是以图像识别为例。
先考虑最简单的,样本都是二维的黑白图片。这样输入层 X X X就是一个矩阵,矩阵的值等于图片的各个像素位置的值。这时和卷积层相连的卷积核 W W W就也是矩阵。
如果样本都是有RGB的彩色图片,这样输入 X X X就是3个矩阵,即分别对应R,G和B的矩阵,或者说是一个张量。这时和卷积层相连的卷积核 W W W就也是张量,对应的最后一维的维度为3。即每个卷积核都是3个子矩阵组成。
同样的方法,对于3D的彩色图片之类的样本,我们的输入 X X X可以是4维,5维的张量,那么对应的卷积核 W W W也是个高维的张量。
不管维度多高,对于我们的输入,前向传播的过程可以表示为:
a
2
=
σ
(
z
2
)
=
σ
(
a
1
∗
W
2
+
b
2
)
a^2= \sigma(z^2) = \sigma(a^1*W^2 +b^2)
a2=σ(z2)=σ(a1∗W2+b2)
其中,上标代表层数,星号代表卷积,而 b b b代表我们的偏倚, σ \sigma σ为激活函数,这里一般都是ReLU。
和DNN的前向传播比较一下,其实形式非常的像,只是我们这儿是张量的卷积,而不是矩阵的乘法。同时由于 W W W是张量,那么同样的位置, W W W参数的个数就比DNN多很多了。
为了简化我们的描述,本文后面如果没有特殊说明,我们都默认输入是3维的张量,即用RBG可以表示的彩色图片。
这里需要我们自己定义的CNN模型参数是:
1) 一般我们的卷积核不止一个,比如有 K K K个,那么我们这一层卷积层的对应的输出的三维张量最后一维就为 K K K。
2) 卷积核中每个子矩阵的的大小,一般我们都用子矩阵为方阵的卷积核,比如 F × F F\times F F×F的子矩阵。
3) 填充padding(以下简称 P P P),我们卷积的时候,为了可以更好的识别边缘,一般都会在输入矩阵在周围加上若干圈的0再进行卷积,加多少圈则 P P P为多少。
4) 步幅stride(以下简称 S S S),即在卷积过程中每次移动的像素距离大小。
2.3 隐藏层前向传播到卷积层
现在我们再来看普通隐藏层前向传播到卷积层时的前向传播算法。
假设隐藏层的输出是
K
K
K个矩阵对应的三维张量(最后一维为
K
K
K),则输出到卷积层的卷积核也是
K
K
K个子矩阵对应的三维张量(最后一维为
K
K
K)。这时表达式和输入层的很像,也是
a
l
=
σ
(
z
l
)
=
σ
(
a
l
−
1
∗
W
l
+
b
l
)
a^l= \sigma(z^l) = \sigma(a^{l-1}*W^l +b^l)
al=σ(zl)=σ(al−1∗Wl+bl)
其中,上标代表层数,星号代表卷积,而 b b b代表我们的偏倚, σ \sigma σ为激活函数,这里一般都是ReLU。
也可以写成
K
K
K个子矩阵子矩阵卷积后对应位置相加的形式,即:
a
l
=
σ
(
z
l
)
=
σ
(
∑
k
=
1
K
z
k
l
)
=
σ
(
∑
k
=
1
K
a
k
l
−
1
∗
W
k
l
+
b
l
)
a^l= \sigma(z^l) = \sigma(\sum\limits_{k=1}^{K}z_k^l) = \sigma(\sum\limits_{k=1}^{K}a_k^{l-1}*W_k^l +b^l)
al=σ(zl)=σ(k=1∑Kzkl)=σ(k=1∑Kakl−1∗Wkl+bl)
和上一节唯一的区别仅仅在于,这里的输入是隐藏层来的,而不是我们输入的原始图片样本形成的矩阵。
需要我们定义的CNN模型参数也和上一节一样,这里我们需要定义卷积核的个数 K K K,卷积核子矩阵的维度 F F F,填充大小 P P P以及步幅 S S S。
2.4 隐藏层前向传播到池化层
池化层的处理逻辑是比较简单的,我们的目的就是对输入的矩阵进行缩小概括。比如输入的若干矩阵是 N × N N\times N N×N维的,而我们的池化大小是 k × k k\times k k×k的区域,则输出的矩阵都是 N k × N k \frac{N}{k} \times \frac{N}{k} kN×kN维的。
这里需要需要我们定义的CNN模型参数是:
1)池化区域的大小 k k k
2)池化的标准,一般是MAX或者Average。
2.5 隐藏层前向传播到全连接层
由于全连接层就是普通的DNN模型结构,因此我们可以直接使用DNN的前向传播算法逻辑,即:
a
l
=
σ
(
z
l
)
=
σ
(
W
l
a
l
−
1
+
b
l
)
a^l = \sigma(z^l) = \sigma(W^la^{l-1} + b^l)
al=σ(zl)=σ(Wlal−1+bl)
这里的激活函数一般是sigmoid或者tanh。
经过了若干全连接层之后,最后的一层为Softmax输出层。此时输出层和普通的全连接层唯一的区别是,激活函数是softmax函数。
这里需要需要我们定义的CNN模型参数是:
1)全连接层的激活函数
2)全连接层各层神经元的个数
2.6 CNN前向传播算法小结
有了上面的基础,我们现在总结下CNN的前向传播算法。
输入:1个图片样本,CNN模型的层数 L L L和所有隐藏层的类型,对于卷积层,要定义卷积核的大小 K K K,卷积核子矩阵的维度 F F F,填充大小 P P P,步幅 S S S。对于池化层,要定义池化区域大小 k k k和池化标准(MAX或Average),对于全连接层,要定义全连接层的激活函数(输出层除外)和各层的神经元个数。
输出:CNN模型的输出 a L a^L aL
1)根据输入层的填充大小 P P P,填充原始图片的边缘,得到输入张量 a 1 a^1 a1。
2)初始化所有隐藏层的参数 W , b W,b W,b
3)for l = 2 l=2 l=2 to L − 1 L−1 L−1:
a) 如果第 l l l层是卷积层,则输出为
a l = R e L U ( z l ) = R e L U ( a l − 1 ∗ W l + b l ) a^l= ReLU(z^l) = ReLU(a^{l-1}*W^l +b^l) al=ReLU(zl)=ReLU(al−1∗Wl+bl)
b) 如果第 l l l层是池化层,则输出为 a l = p o o l ( a l − 1 ) a^l= pool(a^{l-1}) al=pool(al−1), 这里的pool指按照池化区域大小 k k k和池化标准将输入张量缩小的过程。
c) 如果第
l
l
l层是全连接层,则输出为
a
l
=
σ
(
z
l
)
=
σ
(
W
l
a
l
−
1
+
b
l
)
a^l= \sigma(z^l) = \sigma(W^la^{l-1} +b^l)
al=σ(zl)=σ(Wlal−1+bl)
4)对于输出层第
L
L
L层:
a
L
=
s
o
f
t
m
a
x
(
z
L
)
=
s
o
f
t
m
a
x
(
W
L
a
L
−
1
+
b
L
)
a^L= softmax(z^L) = softmax(W^La^{L-1} +b^L)
aL=softmax(zL)=softmax(WLaL−1+bL)
以上就是CNN前向传播算法的过程总结。有了CNN前向传播算法的基础,我们后面再来理解CNN的反向传播算法就简单多了。下一章我们来讨论CNN的反向传播算法。
三、卷积神经网络(CNN)反向传播算法
3.1 回顾DNN的反向传播算法
我们首先回顾DNN的反向传播算法。在DNN中,我们是首先计算出输出层的
δ
L
\delta^L
δL:
δ
L
=
∂
J
(
W
,
b
)
∂
z
L
=
∂
J
(
W
,
b
)
∂
a
L
⊙
σ
′
(
z
L
)
(BP1)
\delta^L = \frac{\partial J(W,b)}{\partial z^L} = \frac{\partial J(W,b)}{\partial a^L}\odot \sigma^{'}(z^L)\qquad \text{(BP1)}
δL=∂zL∂J(W,b)=∂aL∂J(W,b)⊙σ′(zL)(BP1)
利用数学归纳法,用
δ
l
+
1
\delta^{l+1}
δl+1的值一步步的向前求出第
l
l
l层的
δ
l
\delta^l
δl,表达式为:
δ
l
=
δ
l
+
1
∂
z
l
+
1
∂
z
l
=
(
W
l
+
1
)
T
δ
l
+
1
⊙
σ
′
(
z
l
)
(BP2)
\delta^{l} = \delta^{l+1}\frac{\partial z^{l+1}}{\partial z^{l}} = (W^{l+1})^T\delta^{l+1}\odot \sigma^{'}(z^l)\qquad \text{(BP2)}
δl=δl+1∂zl∂zl+1=(Wl+1)Tδl+1⊙σ′(zl)(BP2)
有了
δ
l
\delta^l
δl的表达式,从而求出
W
,
b
W,b
W,b的梯度表达式:
∂
J
(
W
,
b
)
∂
W
l
=
∂
J
(
W
,
b
,
x
,
y
)
∂
z
l
∂
z
l
∂
W
l
=
δ
l
(
a
l
−
1
)
T
(BP3)
\frac{\partial J(W,b)}{\partial W^l} = \frac{\partial J(W,b,x,y)}{\partial z^l} \frac{\partial z^l}{\partial W^l} = \delta^{l}(a^{l-1})^T\qquad \text{(BP3)}
∂Wl∂J(W,b)=∂zl∂J(W,b,x,y)∂Wl∂zl=δl(al−1)T(BP3)
∂ J ( W , b , x , y ) ∂ b l = ∂ J ( W , b ) ∂ z l ∂ z l ∂ b l = δ l (BP4) \frac{\partial J(W,b,x,y)}{\partial b^l} = \frac{\partial J(W,b)}{\partial z^l} \frac{\partial z^l}{\partial b^l} = \delta^{l}\qquad \text{(BP4)} ∂bl∂J(W,b,x,y)=∂zl∂J(W,b)∂bl∂zl=δl(BP4)
有了 W , b W,b W,b梯度表达式,就可以用梯度下降法来优化 W , b W,b W,b,求出最终的所有 W , b W,b W,b的值。
现在我们想把同样的思想用到CNN中,很明显,CNN有些不同的地方,不能直接去套用DNN的反向传播算法的公式。
3.2 CNN的反向传播算法思想
要套用DNN的反向传播算法到CNN,有几个问题需要解决:
1)池化层没有激活函数,这个问题倒比较好解决,我们可以令池化层的激活函数为 σ ( z ) = z \sigma(z) = z σ(z)=z,即激活后就是自己本身。这样池化层激活函数的导数为1.
2)池化层在前向传播的时候,对输入进行了压缩,那么我们现在需要向前反向推导 δ l − 1 \delta^{l-1} δl−1,这个推导方法和DNN完全不同。
3) 卷积层是通过张量卷积,或者说若干个矩阵卷积求和而得的当前层的输出,这和DNN很不相同,DNN的全连接层是直接进行矩阵乘法得到当前层的输出。这样在卷积层反向传播的时候,上一层的 δ l − 1 \delta^{l-1} δl−1递推计算方法肯定有所不同。
4)对于卷积层,由于 W W W使用的运算是卷积,那么从 δ l \delta^{l} δl推导出该层的所有卷积核的 W , b W,b W,b的方式也不同。
从上面可以看出,问题1比较好解决,但是问题2,3,4就需要好好的动一番脑筋了,而问题2,3,4也是解决CNN反向传播算法的关键所在。另外大家要注意到的是,DNN中的 a l , z l a^l,z^l al,zl都只是一个向量,而我们CNN中的 a l , z l a^l,z^l al,zl都是一个张量,这个张量是三维的,即由若干个输入的子矩阵组成。
下面我们就针对问题2,3,4来一步步研究CNN的反向传播算法。
在研究过程中,需要注意的是,由于卷积层可以有多个卷积核,各个卷积核的处理方法是完全相同且独立的,为了简化算法公式的复杂度,我们下面提到卷积核都是卷积层中若干卷积核中的一个。
3.3 已知池化层的 δ l \delta^{l} δl,推导上一隐藏层的 δ l − 1 \delta^{l-1} δl−1
我们首先解决上面的问题2,如果已知池化层的 δ l \delta^{l} δl,推导出上一隐藏层的 δ l − 1 \delta^{l-1} δl−1。
在前向传播算法时,池化层一般我们会用MAX或者Average对输入进行池化,池化的区域大小已知。现在我们反过来,要从缩小后的误差或者梯度 δ l \delta^{l} δl,还原前一次较大区域对应的误差。
在反向传播时,我们首先会把 δ l \delta^{l} δl的所有子矩阵矩阵大小还原成池化之前的大小。有一个原则就是需要保证传递的loss(或者梯度)总和不变。根据这条原则,average pooling和max pooling的反向传播也是不同的。然后如果是MAX,则把 δ l \delta^{l} δl的所有子矩阵的各个池化局域的值放在之前做前向传播算法得到最大值的位置。如果是Average,则把 δ l \delta^{l} δl的所有子矩阵的各个池化局域的值取平均后放在还原后的子矩阵位置。这个过程一般叫做upsample。
用一个例子可以很方便的表示:假设我们的池化区域大小是2x2。
δ
l
\delta^{l}
δl的第
k
k
k个子矩阵为:
δ
k
l
=
(
2
8
4
6
)
\delta_k^l = \left( \begin{array}{ccc} 2& 8 \\ 4& 6 \end{array} \right)
δkl=(2486)
由于池化区域为2x2,我们先对
δ
k
l
\delta_k^l
δkl做还原,即变成:
(
0
0
0
0
0
2
8
0
0
4
6
0
0
0
0
0
)
\left( \begin{array}{ccc} 0&0&0&0 \\ 0&2& 8&0 \\ 0&4&6&0 \\ 0&0&0&0 \end{array} \right)
⎝⎜⎜⎛0000024008600000⎠⎟⎟⎞
如果是MAX,假设我们之前在前向传播时记录的最大值位置分别是左上,右下,右上,左下,则转换后的矩阵为:
(
2
0
0
0
0
0
0
8
0
4
0
0
0
0
6
0
)
\left( \begin{array}{ccc} 2&0&0&0 \\ 0&0& 0&8 \\ 0&4&0&0 \\ 0&0&6&0 \end{array} \right)
⎝⎜⎜⎛2000004000060800⎠⎟⎟⎞
如果是Average,则进行平均:转换后的矩阵为:
(
0.5
0.5
2
2
0.5
0.5
2
2
1
1
1.5
1.5
1
1
1.5
1.5
)
\left( \begin{array}{ccc} 0.5&0.5&2&2 \\ 0.5&0.5&2&2 \\ 1&1&1.5&1.5 \\ 1&1&1.5&1.5 \end{array} \right)
⎝⎜⎜⎛0.50.5110.50.511221.51.5221.51.5⎠⎟⎟⎞
注:Average pooling比较容易让人理解错的地方就是会简单的认为直接把梯度复制 N N N遍之后直接反向传播回去,但是这样会造成loss之和变为原来的 N N N倍,网络是会产生梯度爆炸的。
这样我们就得到了上一层
∂
J
(
W
,
b
)
∂
a
k
l
−
1
\frac{\partial J(W,b)}{\partial a_k^{l-1}}
∂akl−1∂J(W,b)的值(为什么上面的矩阵的值是
∂
J
(
W
,
b
)
∂
a
k
l
−
1
\frac{\partial J(W,b)}{\partial a_k^{l-1}}
∂akl−1∂J(W,b)?可以这么认为:传入到
l
l
l池化层的是
a
k
l
−
1
a_k^{l-1}
akl−1,那么反向传播时
u
p
s
a
m
p
l
e
(
δ
l
)
upsample(\delta^l)
upsample(δl)的误差自然是
∂
J
(
W
,
b
)
∂
a
k
l
−
1
\frac{\partial J(W,b)}{\partial a_k^{l-1}}
∂akl−1∂J(W,b)),要得到
δ
k
l
−
1
\delta_k^{l-1}
δkl−1:
δ
k
l
−
1
=
∂
J
(
W
,
b
)
∂
a
k
l
−
1
∂
a
k
l
−
1
∂
z
k
l
−
1
=
u
p
s
a
m
p
l
e
(
δ
k
l
)
⊙
σ
′
(
z
k
l
−
1
)
\delta_k^{l-1} = \frac{\partial J(W,b)}{\partial a_k^{l-1}} \frac{\partial a_k^{l-1}}{\partial z_k^{l-1}} = upsample(\delta_k^l) \odot \sigma^{'}(z_k^{l-1})
δkl−1=∂akl−1∂J(W,b)∂zkl−1∂akl−1=upsample(δkl)⊙σ′(zkl−1)
其中,upsample函数完成了池化误差矩阵放大与误差重新分配的逻辑。
我们概括下,对于张量
δ
l
−
1
\delta^{l-1}
δl−1,我们有:
δ
l
−
1
=
u
p
s
a
m
p
l
e
(
δ
l
)
⊙
σ
′
(
z
l
−
1
)
(BP2*)
\delta^{l-1} = upsample(\delta^l) \odot \sigma^{'}(z^{l-1})\qquad \text{(BP2*)}
δl−1=upsample(δl)⊙σ′(zl−1)(BP2*)
上式和普通网络的反向推导误差很类似:
δ
l
=
(
W
l
+
1
)
T
δ
l
+
1
⊙
σ
′
(
z
l
)
(BP2)
\delta^{l} = (W^{l+1})^T\delta^{l+1}\odot \sigma^{'}(z^l)\qquad \text{(BP2)}
δl=(Wl+1)Tδl+1⊙σ′(zl)(BP2)
3.4 已知卷积层的 δ l \delta^{l} δl,推导上一隐藏层的 δ l − 1 \delta^{l-1} δl−1
对于卷积层的反向传播,我们首先回忆下卷积层的前向传播公式:
a
l
=
σ
(
z
l
)
=
σ
(
a
l
−
1
∗
W
l
+
b
l
)
a^l= \sigma(z^l) = \sigma(a^{l-1}*W^l +b^l)
al=σ(zl)=σ(al−1∗Wl+bl)
在DNN中,我们知道
δ
l
−
1
\delta^{l-1}
δl−1和
δ
l
\delta^{l}
δl的递推关系为:
δ
l
=
∂
J
(
W
,
b
)
∂
z
l
=
∂
J
(
W
,
b
)
∂
z
l
+
1
∂
z
l
+
1
∂
z
l
=
δ
l
+
1
∂
z
l
+
1
∂
z
l
\delta^{l} = \frac{\partial J(W,b)}{\partial z^l} = \frac{\partial J(W,b)}{\partial z^{l+1}}\frac{\partial z^{l+1}}{\partial z^{l}} = \delta^{l+1}\frac{\partial z^{l+1}}{\partial z^{l}}
δl=∂zl∂J(W,b)=∂zl+1∂J(W,b)∂zl∂zl+1=δl+1∂zl∂zl+1
因此要推导出 δ l − 1 \delta^{l-1} δl−1和 δ l \delta^{l} δl的递推关系,必须计算 ∂ z l ∂ z l − 1 \frac{\partial z^{l}}{\partial z^{l-1}} ∂zl−1∂zl的梯度表达式。
注意到
z
l
z^l
zl和
z
l
−
1
z^{l−1}
zl−1的关系为:
z
l
=
a
l
−
1
∗
W
l
+
b
l
=
σ
(
z
l
−
1
)
∗
W
l
+
b
l
z^l = a^{l-1}*W^l +b^l =\sigma(z^{l-1})*W^l +b^l
zl=al−1∗Wl+bl=σ(zl−1)∗Wl+bl
因此我们有:
δ
l
−
1
=
δ
l
∂
z
l
∂
z
l
−
1
=
δ
l
∗
r
o
t
180
(
W
l
)
⊙
σ
′
(
z
l
−
1
)
(BP2*)
\delta^{l-1} = \delta^{l}\frac{\partial z^{l}}{\partial z^{l-1}} = \delta^{l}*rot180(W^{l}) \odot \sigma^{'}(z^{l-1})\qquad \text{(BP2*)}
δl−1=δl∂zl−1∂zl=δl∗rot180(Wl)⊙σ′(zl−1)(BP2*)
这里的式子其实和DNN的类似,区别在于对于含有卷积的式子求导时,卷积核被旋转了180度。即式子中的rot180(),翻转180度的意思是上下翻转一次,接着左右翻转一次。在DNN中这里只是矩阵的转置。那么为什么呢?由于这里都是张量,直接推演参数太多了。我们以一个简单的例子说明为啥这里求导后卷积核要翻转。
假设我们
l
−
1
l−1
l−1层的输出
a
l
−
1
a^{l−1}
al−1是一个3x3矩阵,第
l
l
l层的卷积核
W
l
W^l
Wl是一个2x2矩阵,采用1像素的步幅,则输出
z
l
z^l
zl是一个2x2的矩阵。我们简化
b
l
b^l
bl都是0,则有
a
l
−
1
∗
W
l
=
z
l
a^{l-1}*W^l = z^{l}
al−1∗Wl=zl
我们列出
a
,
W
,
z
a,W,z
a,W,z的矩阵表达式如下:
(
a
11
a
12
a
13
a
21
a
22
a
23
a
31
a
32
a
33
)
∗
(
w
11
w
12
w
21
w
22
)
=
(
z
11
z
12
z
21
z
22
)
\left( \begin{array}{ccc} a_{11}&a_{12}&a_{13} \\ a_{21}&a_{22}&a_{23}\\ a_{31}&a_{32}&a_{33} \end{array} \right) * \left( \begin{array}{ccc} w_{11}&w_{12}\\ w_{21}&w_{22} \end{array} \right) = \left( \begin{array}{ccc} z_{11}&z_{12}\\ z_{21}&z_{22} \end{array} \right)
⎝⎛a11a21a31a12a22a32a13a23a33⎠⎞∗(w11w21w12w22)=(z11z21z12z22)
利用卷积的定义,很容易得出:
z
11
=
a
11
w
11
+
a
12
w
12
+
a
21
w
21
+
a
22
w
22
z_{11} = a_{11}w_{11} + a_{12}w_{12} + a_{21}w_{21} + a_{22}w_{22}
z11=a11w11+a12w12+a21w21+a22w22
z 12 = a 12 w 11 + a 13 w 12 + a 22 w 21 + a 23 w 22 z_{12} = a_{12}w_{11} + a_{13}w_{12} + a_{22}w_{21} + a_{23}w_{22} z12=a12w11+a13w12+a22w21+a23w22
z 21 = a 21 w 11 + a 22 w 12 + a 31 w 21 + a 32 w 22 z_{21} = a_{21}w_{11} + a_{22}w_{12} + a_{31}w_{21} + a_{32}w_{22} z21=a21w11+a22w12+a31w21+a32w22
z 22 = a 22 w 11 + a 23 w 12 + a 32 w 21 + a 33 w 22 z_{22} = a_{22}w_{11} + a_{23}w_{12} + a_{32}w_{21} + a_{33}w_{22} z22=a22w11+a23w12+a32w21+a33w22
接着我们模拟反向求导:
∇
a
l
−
1
=
∂
J
(
W
,
b
)
∂
a
l
−
1
=
∂
J
(
W
,
b
)
∂
z
l
∂
z
l
∂
a
l
−
1
=
δ
l
∂
z
l
∂
a
l
−
1
\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}}
∇al−1=∂al−1∂J(W,b)=∂zl∂J(W,b)∂al−1∂zl=δl∂al−1∂zl
从上式可以看出,对于 a l − 1 a^{l-1} al−1的梯度误差 ∇ a l − 1 \nabla a^{l-1} ∇al−1,等于第 l l l层的梯度误差乘以 ∂ z l ∂ a l − 1 \frac{\partial z^{l}}{\partial a^{l-1}} ∂al−1∂zl,而 ∂ z l ∂ a l − 1 \frac{\partial z^{l}}{\partial a^{l-1}} ∂al−1∂zl对应上面的例子中相关联的 w w w的值。假设我们的 z z z矩阵对应的反向传播误差是 δ 11 , δ 12 , δ 21 , δ 22 \delta_{11}, \delta_{12}, \delta_{21}, \delta_{22} δ11,δ12,δ21,δ22组成的2x2矩阵(即, δ l = ∂ J ( W , b ) ∂ z l \delta^{l} = \frac{\partial J(W,b)}{\partial z^l} δl=∂zl∂J(W,b)),则利用上面梯度的式子和4个等式,我们可以分别写出 ∇ a l − 1 \nabla a^{l-1} ∇al−1的9个标量的梯度。
比如对于
a
11
a_{11}
a11的梯度,由于在4个等式中
a
11
a_{11}
a11只和
z
11
z_{11}
z11有乘积关系,从而我们有:
∇
a
11
=
δ
11
w
11
\nabla a_{11} = \delta_{11}w_{11}
∇a11=δ11w11
对于
a
12
a_{12}
a12的梯度,由于在4个等式中
a
12
a_{12}
a12和
z
12
z_{12}
z12,
z
11
z_{11}
z11有乘积关系,从而我们有:
∇
a
12
=
δ
11
w
12
+
δ
12
w
11
\nabla a_{12} = \delta_{11}w_{12} + \delta_{12}w_{11}
∇a12=δ11w12+δ12w11
同样的道理我们得到:
∇
a
13
=
δ
12
w
12
\nabla a_{13} = \delta_{12}w_{12}
∇a13=δ12w12
∇ a 21 = δ 11 w 21 + δ 21 w 11 \nabla a_{21} = \delta_{11}w_{21} + \delta_{21}w_{11} ∇a21=δ11w21+δ21w11
∇ a 22 = δ 11 w 22 + δ 12 w 21 + δ 21 w 12 + δ 22 w 11 \nabla a_{22} = \delta_{11}w_{22} + \delta_{12}w_{21} + \delta_{21}w_{12} + \delta_{22}w_{11} ∇a22=δ11w22+δ12w21+δ21w12+δ22w11
∇ a 23 = δ 12 w 22 + δ 22 w 12 \nabla a_{23} = \delta_{12}w_{22} + \delta_{22}w_{12} ∇a23=δ12w22+δ22w12
∇ a 31 = δ 21 w 21 \nabla a_{31} = \delta_{21}w_{21} ∇a31=δ21w21
∇ a 32 = δ 21 w 22 + δ 22 w 21 \nabla a_{32} = \delta_{21}w_{22} + \delta_{22}w_{21} ∇a32=δ21w22+δ22w21
∇ a 33 = δ 22 w 22 \nabla a_{33} = \delta_{22}w_{22} ∇a33=δ22w22
这上面9个式子其实可以用一个矩阵卷积的形式表示,即:
(
0
0
0
0
0
δ
11
δ
12
0
0
δ
21
δ
22
0
0
0
0
0
)
∗
(
w
22
w
21
w
12
w
11
)
=
(
∇
a
11
∇
a
12
∇
a
13
∇
a
21
∇
a
22
∇
a
23
∇
a
31
∇
a
32
∇
a
33
)
\left( \begin{array}{ccc} 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}{ccc} 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)
⎝⎜⎜⎛00000δ11δ2100δ12δ2200000⎠⎟⎟⎞∗(w22w12w21w11)=⎝⎛∇a11∇a21∇a31∇a12∇a22∇a32∇a13∇a23∇a33⎠⎞
为了符合梯度计算,我们在误差矩阵周围填充了一圈0,此时我们将卷积核翻转后和反向传播的梯度误差进行卷积,就得到了前一次的梯度误差。这个例子直观的介绍了为什么对含有卷积的式子反向传播时,卷积核要翻转180度的原因。
以上就是卷积层的误差反向传播过程。
3.5 已知卷积层的 δ l \delta^l δl,推导该层的 W , b W,b W,b的梯度
好了,我们现在已经可以递推出每一层的梯度误差 δ l \delta^l δl了,对于全连接层,可以按DNN的反向传播算法求该层 W , b W,b W,b的梯度,而池化层并没有 W , b W,b W,b,也不用求 W , b W,b W,b的梯度。只有卷积层的 W , b W,b W,b需要求出。
注意到卷积层
z
z
z和
W
,
b
W,b
W,b的关系为:
z
l
=
a
l
−
1
∗
W
l
+
b
z^l = a^{l-1}*W^l +b
zl=al−1∗Wl+b
因此我们有:
∂
J
(
W
,
b
)
∂
W
l
=
∂
J
(
W
,
b
)
∂
z
l
∂
z
l
∂
W
l
=
a
l
−
1
∗
δ
l
(BP3*)
\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 \qquad \text{(BP3*)}
∂Wl∂J(W,b)=∂zl∂J(W,b)∂Wl∂zl=al−1∗δl(BP3*)
注意到此时卷积核并没有反转,主要是此时是层内的求导,而不是反向传播到上一层的求导。具体过程我们可以分析一下。
和第3.4节一样的一个简化的例子,这里输入是矩阵,不是张量,那么对于第
l
l
l层,某个个卷积核矩阵W的导数可以表示如下:
∂
J
(
W
,
b
)
∂
W
p
q
l
=
∑
i
∑
j
(
δ
i
j
l
a
i
+
p
−
1
,
j
+
q
−
1
l
−
1
)
\frac{\partial J(W,b)}{\partial W_{pq}^{l}} = \sum\limits_i\sum\limits_j(\delta_{ij}^la_{i+p-1,j+q-1}^{l-1})
∂Wpql∂J(W,b)=i∑j∑(δijlai+p−1,j+q−1l−1)
假设我们输入 a l − 1 a^{l-1} al−1是4x4的矩阵,卷积核 W l W^l Wl是3x3的矩阵,输出 z l z^l zl是2x2的矩阵,那么反向传播的 z l z^l zl的梯度误差 δ l \delta^l δl也是2x2的矩阵。
即:
(
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
)
∗
(
w
11
w
12
w
13
w
21
w
22
w
23
w
31
w
32
w
33
)
=
(
z
11
z
12
z
21
z
22
)
\left( \begin{array}{ccc} 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}{ccc} w_{11}&w_{12}&w_{13} \\w_{21}&w_{22}&w_{23}\\ w_{31}&w_{32}&w_{33} \end{array} \right)=\left( \begin{array}{ccc} z_{11}&z_{12}\\ z_{21}&z_{22} \end{array} \right)
⎝⎜⎜⎛a11a21a31a41a12a22a32a42a13a23a33a43a14a24a34a44⎠⎟⎟⎞∗⎝⎛w11w21w31w12w22w32w13w23w33⎠⎞=(z11z21z12z22)
那么根据上面的式子,我们有:
∂
J
(
W
,
b
)
∂
W
11
l
=
a
11
δ
11
+
a
12
δ
12
+
a
21
δ
21
+
a
22
δ
22
\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}
∂W11l∂J(W,b)=a11δ11+a12δ12+a21δ21+a22δ22
∂ J ( W , b ) ∂ W 12 l = a 12 δ 11 + a 13 δ 12 + a 22 δ 21 + a 23 δ 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} ∂W12l∂J(W,b)=a12δ11+a13δ12+a22δ21+a23δ22
∂ J ( W , b ) ∂ W 13 l = a 13 δ 11 + a 14 δ 12 + a 23 δ 21 + a 24 δ 22 \frac{\partial J(W,b)}{\partial W_{13}^{l}} = a_{13}\delta_{11} + a_{14}\delta_{12} + a_{23}\delta_{21} + a_{24}\delta_{22} ∂W13l∂J(W,b)=a13δ11+a14δ12+a23δ21+a24δ22
∂ J ( W , b ) ∂ W 21 l = a 21 δ 11 + a 22 δ 12 + a 31 δ 21 + a 32 δ 22 \frac{\partial J(W,b)}{\partial W_{21}^{l}} = a_{21}\delta_{11} + a_{22}\delta_{12} + a_{31}\delta_{21} + a_{32}\delta_{22} ∂W21l∂J(W,b)=a21δ11+a22δ12+a31δ21+a32δ22
. . . . . . . . ........ ........
最终我们可以一共得到9个式子。整理成矩阵形式后可得:
∂
J
(
W
,
b
)
∂
W
l
=
(
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
)
∗
(
δ
11
δ
12
δ
21
δ
22
)
\frac{\partial J(W,b)}{\partial W^{l}} =\left( \begin{array}{ccc} 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}{ccc} \delta_{11}& \delta_{12} \\ \delta_{21}&\delta_{22} \end{array} \right)
∂Wl∂J(W,b)=⎝⎜⎜⎛a11a21a31a41a12a22a32a42a13a23a33a43a14a24a34a44⎠⎟⎟⎞∗(δ11δ21δ12δ22)
从而可以清楚的看到这次我们为什么没有反转的原因。
而对于
b
b
b,则稍微有些特殊,因为
δ
l
\delta^l
δl是三维张量,而
b
b
b只是一个向量,不能像DNN那样直接和
δ
l
\delta^l
δl相等。通常的做法是将
δ
l
\delta^l
δl的各个子矩阵的项分别求和,得到一个误差向量,即为
b
b
b的梯度:
∂
J
(
W
,
b
)
∂
b
l
=
∑
u
,
v
(
δ
l
)
u
,
v
(BP4*)
\frac{\partial J(W,b)}{\partial b^{l}} = \sum\limits_{u,v}(\delta^l)_{u,v} \qquad \text{(BP4*)}
∂bl∂J(W,b)=u,v∑(δl)u,v(BP4*)
3.6 CNN反向传播算法总结
现在我们总结下CNN的反向传播算法,以最基本的批量梯度下降法为例来描述反向传播算法。
输入: m m m个图片样本,CNN模型的层数 L L L和所有隐藏层的类型,对于卷积层,要定义卷积核的大小 K K K,卷积核子矩阵的维度 F F F,填充大小 P P P,步幅 S S S。对于池化层,要定义池化区域大小 k k k和池化标准(MAX或Average),对于全连接层,要定义全连接层的激活函数(输出层除外)和各层的神经元个数。梯度迭代参数迭代步长 α \alpha α,最大迭代次数MAX与停止迭代阈值 ϵ \epsilon ϵ
输出:CNN模型各隐藏层与输出层的 W , b W,b W,b
1)初始化各隐藏层与输出层的各 W , b W,b W,b的值为一个随机值。
2)for iter to 1 to MAX:
2-1) for i = 1 i =1 i=1 to m m m:
a) 将CNN输入 a 1 a^1 a1设置为 x i x_i xi对应的张量
b) for l = 2 l=2 l=2 to L − 1 L-1 L−1,根据下面3种情况进行前向传播算法计算:
b-1) 如果第 l l l层是卷积层,则输出为 a i , l = σ ( z i , l ) = σ ( W l ∗ a i , l − 1 + b l ) a^{i,l} = \sigma(z^{i,l}) = \sigma(W^l*a^{i,l-1} + b^{l}) ai,l=σ(zi,l)=σ(Wl∗ai,l−1+bl)
b-2) 如果第 l l l层是池化层,则输出为 a i , l = p o o l ( a i , l − 1 ) a^{i,l}= pool(a^{i,l-1}) ai,l=pool(ai,l−1), 这里的pool指按照池化区域大小 k k k和池化标准将输入张量缩小的过程。
b-3) 如果第 l l l层是全连接层,则输出为 a i , l = σ ( z i , l ) = σ ( W l a i , l − 1 + b l ) a^{i,l} = \sigma(z^{i,l}) = \sigma(W^la^{i,l-1} + b^{l}) ai,l=σ(zi,l)=σ(Wlai,l−1+bl)
c) 对于输出层第 L L L层: a i , L = s o f t m a x ( z i , L ) = s o f t m a x ( W L a i , L − 1 + b L ) a^{i,L}= softmax(z^{i,L}) = softmax(W^{L}a^{i,L-1} +b^{L}) ai,L=softmax(zi,L)=softmax(WLai,L−1+bL)
d) 通过损失函数计算输出层的 δ i , L \delta^{i,L} δi,L
e) for l = L − 1 l= L-1 l=L−1 to 2, 根据下面3种情况进行进行反向传播算法计算:
e-1) 如果当前是全连接层: δ i , l = ( W l + 1 ) T δ i , l + 1 ⊙ σ ′ ( z i , l ) \delta^{i,l} = (W^{l+1})^T\delta^{i,l+1}\odot \sigma^{'}(z^{i,l}) δi,l=(Wl+1)Tδi,l+1⊙σ′(zi,l)
e-2) 如果当前是卷积层: δ i , l = δ i , l + 1 ∗ r o t 180 ( W l + 1 ) ⊙ σ ′ ( z i , l ) \delta^{i,l} = \delta^{i,l+1}*rot180(W^{l+1}) \odot \sigma^{'}(z^{i,l}) δi,l=δi,l+1∗rot180(Wl+1)⊙σ′(zi,l)
e-3) 如果当前是池化层: δ i , l = u p s a m p l e ( δ i , l + 1 ) ⊙ σ ′ ( z i , l ) \delta^{i,l} = upsample(\delta^{i,l+1}) \odot \sigma^{'}(z^{i,l}) δi,l=upsample(δi,l+1)⊙σ′(zi,l)
2-2) for l = 2 l = 2 l=2 to L L L,根据下面2种情况更新第 l l l层的 W l , b l W^l,b^l Wl,bl:
2-2-1) 如果当前是全连接层: W l = W l − α ∑ i = 1 m δ i , l ( a i , l − 1 ) T W^l = W^l -\alpha \sum\limits_{i=1}^m \delta^{i,l}(a^{i, l-1})^T Wl=Wl−αi=1∑mδi,l(ai,l−1)T, b l = b l − α ∑ i = 1 m δ i , l b^l = b^l -\alpha \sum\limits_{i=1}^m \delta^{i,l} bl=bl−αi=1∑mδi,l
2-2-2) 如果当前是卷积层,对于每一个卷积核有: W l = W l − α ∑ i = 1 m δ i , l ∗ r o t 180 ( a i , l − 1 ) W^l = W^l -\alpha \sum\limits_{i=1}^m \delta^{i,l}*rot180(a^{i, l-1}) Wl=Wl−αi=1∑mδi,l∗rot180(ai,l−1), b l = b l − α ∑ i = 1 m ∑ u , v ( δ i , l ) u , v b^l = b^l -\alpha \sum\limits_{i=1}^m \sum\limits_{u,v}(\delta^{i,l})_{u,v} bl=bl−αi=1∑mu,v∑(δi,l)u,v
2-3) 如果所有 W , b W,b W,b的变化值都小于停止迭代阈值 ϵ \epsilon ϵ,则跳出迭代循环到步骤3。
3) 输出各隐藏层与输出层的线性关系系数矩阵 W W W和偏倚向量 b b b。
参考文献
本文转自参考文献1-3