【Python实现卷积神经网络】:推导卷积层的W,b的梯度

0.前言

  通过之前的学习【Python实现卷积神经网络】:卷积层的正向传播与反向传播+python实现代码,我们知道卷积层的反向传播有三个梯度要求:

1.对输入数据的求导
这里写图片描述
2.对W的求导
这里写图片描述
3.对b的求导
这里写图片描述

1.正确的推导

  我们看这里篇文章:卷积神经网络(CNN)反向传播算法

  它对这部分做了推导,我摘录如下:


  我们现在已经可以递推出每一层的梯度误差 δl δ l 了,现在求卷积层对的W,b的梯度。

注意到卷积层输出z,输入a(同时也是上层输出,所以是 (l1) ( l − 1 ) 层)和W,b的关系为:

zl=al1Wl+b z l = a l − 1 ∗ W l + b

  因此我们有:
J(W,b)Wl=J(W,b)zlzlWl=al1δl ∂ J ( W , b ) ∂ W l = ∂ J ( W , b ) ∂ z l ∂ z l ∂ W l = a l − 1 ∗ δ l

注意到此时卷积核并没有反转,主要是此时是层内的求导,而不是反向传播到上一层的求导。具体过程我们可以分析一下。

  一个简化的例子,这里输入是矩阵,不是张量,那么对于第 l l 层,某个卷积核矩阵W的导数可以表示如下:

J(W,b)Wpql=ij(δijlxi+p1,j+q1l1)

  首先,我们举一个卷积的小例子。假设我们输入a是4x4的矩阵,卷积核W是3x3的矩阵,输出z是2x2的矩阵,那么反向传播的 z z 的梯度误差δ也是2x2的矩阵。我们列出a,W,z的矩阵表达式如下:

a11a21a31a41a12a22a32a42a13a23a33a43a14a24a34a44w11w21w31w12w22w32w13w23w33=(z11z21z12z22) ( 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 )

  反向传播的 z z 的梯度误差δ是:
(δ11δ21δ12δ22) ( δ 11 δ 12 δ 21 δ 22 )

  利用卷积的定义,很容易得出:
z11=a11w11+a12w12+a13w13+a21w21+a22w22+a23w23+a31w31+a32w32+a33w33z12=a12w11+a13w12+a14w13+a22w21+a23w22+a24w23+a32w31+a33w32+a34w33z21=a21w11+a22w12+a23w13+a31w21+a32w22+a33w23+a41w31+a42w32+a43w33z22=a22w11+a23w12+a24w13+a32w21+a33w22+a34w23+a42w31+a43w32+a44w33 z 11 = a 11 w 11 + a 12 w 12 + a 13 w 13 + a 21 w 21 + a 22 w 22 + a 23 w 23 + a 31 w 31 + a 32 w 32 + a 33 w 33 z 12 = a 12 w 11 + a 13 w 12 + a 14 w 13 + a 22 w 21 + a 23 w 22 + a 24 w 23 + a 32 w 31 + a 33 w 32 + a 34 w 33 z 21 = a 21 w 11 + a 22 w 12 + a 23 w 13 + a 31 w 21 + a 32 w 22 + a 33 w 23 + a 41 w 31 + a 42 w 32 + a 43 w 33 z 22 = a 22 w 11 + a 23 w 12 + a 24 w 13 + a 32 w 21 + a 33 w 22 + a 34 w 23 + a 42 w 31 + a 43 w 32 + a 44 w 33

  那么根据上面的式子,我们有:
 
J(W,b)Wl11=a11δ11+a12δ12+a21δ21+a22δ22 ∂ J ( W , b ) ∂ W 11 l = a 11 δ 11 + a 12 δ 12 + a 21 δ 21 + a 22 δ 22

J(W,b)Wl12=a12δ11+a13δ12+a22δ21+a23δ22 ∂ J ( W , b ) ∂ W 12 l = a 12 δ 11 + a 13 δ 12 + a 22 δ 21 + a 23 δ 22

J(W,b)Wl13=a13δ11+a14δ12+a23δ21+a24δ22 ∂ J ( W , b ) ∂ W 13 l = a 13 δ 11 + a 14 δ 12 + a 23 δ 21 + a 24 δ 22

J(W,b)Wl21=a21δ11+a22δ12+a31δ21+a32δ22 ∂ J ( W , b ) ∂ W 21 l = a 21 δ 11 + a 22 δ 12 + a 31 δ 21 + a 32 δ 22

  最终我们可以一共得到9个式子。整理成矩阵形式后可得:

J(W,b)Wl=a11a21a31a41a12a22a32a42a13a23a33a43a14a24a34a44(δ11δ21δ12δ22) ∂ 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 )

  从而可以清楚的看到这次我们为什么没有反转的原因。

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

J(W,b)bl=u,v(δl)u,v ∂ J ( W , b ) ∂ b l = ∑ u , v ( δ l ) u , v


所以,对w的求导:
这里写图片描述

1.2.扩展:

上边小例子是正向卷积输入数据没有pad的情况,那么输入数据加pad呢?

我们这里以另外一个小例子为例。假设我们输入a是2x2的矩阵,且加入pad=1卷积核W是3x3的矩阵,输出z是2x2的矩阵,那么反向传播的 z z 的梯度误差δ也是2x2的矩阵。我们列出a,W,z的矩阵表达式如下:

00000a11a2100a12a2200000w11w21w31w12w22w32w13w23w33=(z11z21z12z22) ( 0 0 0 0 0 a 11 a 12 0 0 a 21 a 22 0 0 0 0 0 ) ⊗ ( 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 )

反向传播的 z z 的梯度误差δ是:
(δ11δ21δ12δ22) ( δ 11 δ 12 δ 21 δ 22 )

  利用卷积的定义,很容易得出:
z11=0+0+0+0+a11w22+a12w23+0+a21w32+a22w33z12=0+0+0+a11w21+a12w22+0+a21w31+a22w32+0z21=0+a11w12+a12w13+0+a21w22+a22w23+0+0+0z22=a11w11+a12w12+0+a21w21+a22w22+0+0+0+0 z 11 = 0 + 0 + 0 + 0 + a 11 w 22 + a 12 w 23 + 0 + a 21 w 32 + a 22 w 33 z 12 = 0 + 0 + 0 + a 11 w 21 + a 12 w 22 + 0 + a 21 w 31 + a 22 w 32 + 0 z 21 = 0 + a 11 w 12 + a 12 w 13 + 0 + a 21 w 22 + a 22 w 23 + 0 + 0 + 0 z 22 = a 11 w 11 + a 12 w 12 + 0 + a 21 w 21 + a 22 w 22 + 0 + 0 + 0 + 0

  那么根据上面的式子,我们有:
J(W,b)Wl11=a11δ22J(W,b)Wl12=a11δ21+a12δ22J(W,b)Wl13=a12δ21J(W,b)Wl21=a11δ12+a21δ22J(W,b)Wl22=a11δ11+a12δ12+a21δ21+a22δ22 ∂ J ( W , b ) ∂ W 11 l = a 11 δ 22 ∂ J ( W , b ) ∂ W 12 l = a 11 δ 21 + a 12 δ 22 ∂ J ( W , b ) ∂ W 13 l = a 12 δ 21 ∂ J ( W , b ) ∂ W 21 l = a 11 δ 12 + a 21 δ 22 ∂ J ( W , b ) ∂ W 22 l = a 11 δ 11 + a 12 δ 12 + a 21 δ 21 + a 22 δ 22

  最终我们可以一共得到9个式子。整理成矩阵形式后可得:

J(W,b)Wl=00000a11a2100a12a2200000(δ11δ21δ12δ22) ∂ J ( W , b ) ∂ W l = ( 0 0 0 0 0 a 11 a 12 0 0 a 21 a 22 0 0 0 0 0 ) ⊗ ( δ 11 δ 12 δ 21 δ 22 )

需要注意的是:
1.卷积左边是输入数据,右边是残差。
2.输入数据做pad。

1.3.扩展二

我们扩展一是举了加pad的例子,那么我们再看批处理的时候这个公式是怎么实现的?

这里写图片描述

这里有两个方法用python实现:

1.直接按照公式进行卷积

        for m in range(HH):
            for n in range(WW):
                x_pad_masked_d = x_pad[:, :, m * stride:m * stride + H_out, n * stride:n * stride + W_out]
                for k in range(F):
                    for p in range(C):
                        dw[k, p, m, n] = np.sum(x_pad_masked_d[:,p,:,:] * residual[:, k, :, :], axis=(0,1,2)) 

从上边代码可以看出:卷积过程大体与正向传播时的卷积过程一样,有一点需要注意:for p in range(C)这个循环是[k 0 m n]这个位置=sum32[10 14 14]*[10 14 14]求出来的。

2.不卷积的求法:

首先,上代码

        residual_pad = np.pad(residual, ((0,), (0,), (pad,), (pad,)), mode='constant', constant_values=0)
        for i in range(H_out):
            for j in range(W_out):
                x_pad_masked = x_pad[:, :, i * stride:i * stride + HH, j * stride:j * stride + WW]
                for k in range(F):  # compute dw
                    dw[k, :, :, :] += np.sum(x_pad_masked * (residual[:, k, i, j])[:, None, None, None], axis=0)  
                for n in range(N):  # compute dx_pad
                    dx_pad[n, :, i * stride:i * stride + HH, j * stride:j * stride + WW] += np.sum((rot_w[:, :, :, :] * (residual_pad[n, :, i,j])[:, None, None, None]), axis=0)

这里边求dw的代码在:

dw[k, :, :, :] += np.sum(x_pad_masked * (residual[:, k, i, j])[:, None, None, None], axis=0)  

这行代码怎么理解呢?
首先,做简单展开:(注意,这里展开i,j不展开k)

dw[k,:,:,:] = 
np.sum(x_pad_masked * (residual[:, k, i=0, j=0])[:, None, None, None], axis=0)  \\
+np.sum(x_pad_masked * (residual[:, k, i=0, j=1])[:, None, None, None], axis=0)  \\
+np.sum(x_pad_masked * (residual[:, k, i=0, j=2])[:, None, None, None], axis=0)  

我们接着上边儿例子看:(这里x对简单例子中的a ;residual对应简单例子中的 δ δ ;i=2,j=2)
按照代码我们的公式为:

J(W,b)Wl=d1+d2+d3+d4 ∂ J ( W , b ) ∂ W l = ( d 1 + d 2 + d 3 + d 4 )

其中:
d1=0000a11a210a12a22δ11=0000a11δ11a21δ110a12δ11a22δ11 d 1 = ( 0 0 0 0 a 11 a 12 0 a 21 a 22 ) ∗ δ 11 = ( 0 0 0 0 a 11 ∗ δ 11 a 12 ∗ δ 11 0 a 21 ∗ δ 11 a 22 ∗ δ 11 )

d2=0a11a210a12a22000δ12=0a11δ12a21δ120a12δ12a22δ12000 d 2 = ( 0 0 0 a 11 a 12 0 a 21 a 22 0 ) ∗ δ 12 = ( 0 0 0 a 11 ∗ δ 12 a 12 ∗ δ 12 0 a 21 ∗ δ 12 a 22 ∗ δ 12 0 )

d3=000a11a210a12a220δ21=000a11δ21a21δ210a12δ21a22δ210 d 3 = ( 0 a 11 a 12 0 a 21 a 22 0 0 0 ) ∗ δ 21 = ( 0 a 11 ∗ δ 21 a 12 ∗ δ 21 0 a 21 ∗ δ 21 a 22 ∗ δ 21 0 0 0 )

d4=a11a210a12a220000δ22=a11δ22a21δ220a12δ22a22δ220000 d 4 = ( a 11 a 12 0 a 21 a 22 0 0 0 0 ) ∗ δ 22 = ( a 11 ∗ δ 22 a 12 ∗ δ 22 0 a 21 ∗ δ 22 a 22 ∗ δ 22 0 0 0 0 )

那么 d1 d 1 d2 d 2 d3 d 3 d4 d 4 对应位置相加结果是:

d11=a11δ22d12=a11δ21+a12δ22d13=a12δ21d21=a11δ12+a21δ22d22=a11δ11+a12δ12+a21δ21+a22δ22 d 11 = a 11 δ 22 d 12 = a 11 δ 21 + a 12 δ 22 d 13 = a 12 δ 21 d 21 = a 11 δ 12 + a 21 δ 22 d 22 = a 11 δ 11 + a 12 δ 12 + a 21 δ 21 + a 22 δ 22

这里我们设:
J(W,b)Wl=d=d11d21d31d12d22d32d13d23d33 ∂ J ( W , b ) ∂ W l = d = ( d 11 d 12 d 13 d 21 d 22 d 23 d 31 d 32 d 33 )

对比之前1.2.扩展推导,说明我们的结果是一样的:

J(W,b)Wl11=a11δ22=d11J(W,b)Wl12=a11δ21+a12δ22=d12J(W,b)Wl13=a12δ21=d13J(W,b)Wl21=a11δ12+a21δ22=d21J(W,b)Wl22=a11δ11+a12δ12+a21δ21+a22δ22=d22 ∂ J ( W , b ) ∂ W 11 l = a 11 δ 22 = d 11 ∂ J ( W , b ) ∂ W 12 l = a 11 δ 21 + a 12 δ 22 = d 12 ∂ J ( W , b ) ∂ W 13 l = a 12 δ 21 = d 13 ∂ J ( W , b ) ∂ W 21 l = a 11 δ 12 + a 21 δ 22 = d 21 ∂ J ( W , b ) ∂ W 22 l = a 11 δ 11 + a 12 δ 12 + a 21 δ 21 + a 22 δ 22 = d 22


2.错误的写法:

  当时,我写2.对w求导时,参考的是这篇文章:CNN卷积神经网络和反向传播,而他的对w求导是需要将卷积层的输入数据做180度翻转,下图是摘自这个博客:


这里写图片描述


  所以,我依照这个说法,做出了如下公式:

这里写图片描述


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值