CNN反向传播原理!(超级详细地推导)


前言

本篇文章将会从数学层面推导二维CNN的反向传播的公式!将会考虑到stride,kernel_size,padding,dilation等所有主要参数,并且给出一个通用公式!【数学形式上简洁的公式并不代表代码实现起来方便,所以本篇会先给出代码实现更方便的公式,再以此为依据进行数学形式上的简化】!!

阅读本篇需要对卷积神经网络的基本概念 和 torch.nn.Conv2d有所了解
在此我们需要了解先卷积操作,大家可以先阅读这篇文章

不过不要担心!本篇将会从最基础全连接网络的反向传播切入,适时给出一些引用博客的链接,深入讲解

文章开头先给出这篇通过具体例子讲解CNN反向传播理论的博客链接

本篇会从多角度去讲解反向传播,通过多角度+具体实现策略,相信大家能够彻底理解CNN,CNN反向传播的面纱也不再神秘!

【其实这篇文章是手写神经网络系列的后续, 但由于手写CNN需要大量的理论依据,如果放在一篇文章里太过冗余,因此决定先从理论详细推导一遍CNN(由于后续会给出代码,所以本篇也会提及一些实现技巧!通过思考具体的实现方法,加深对CNN反向传播的理解!)】

[注]本篇只包含卷积层的BP,不包括池化层和激活层 (这些都很简单,可以参考这篇博客)


一、反向传播是什么

首先反向传播是神经网络训练里的一个术语,任何神经网络可以看做一个函数,输入任意,输出任意(这里的任意是指形状任意,但元素还是数字,因为这里是‘函数’,而不是‘映射’),因此神经网络可以看做一个输入和输出都为多维矩阵的多元函数,
通用近似定理告诉我们,一个具有线性输出层和至少一个有“挤压”性质的激活函数的隐藏层组成的前馈网络 可以以任意精度拟合任意一个定义在实数空间中的有界闭集函数

既然这么普通的网络都能做到任意拟合,更不用说更复杂的网络了,

因此简言之就是: 神经网络是一个含多个参数的函数,通过调整参数值,理论上可以拟合任意函数

那么如何调整参数呢? 其实不管多复杂的网络都采用的是梯度下降法,即用原参数减去导数乘上学习率 η \eta η(可以理解为每次修正的力度)来修正偏差。

比如这里给出一个梯度下降的例子,:

求函数 f 1 ( w ) = w 2 f_1(w)=w^2 f1(w)=w2 距离 直线 f 2 ( w ) = − 1 f_2(w)=-1 f2(w)=1的最小值,

这个问题里我们需要一个评估距离的函数(神经网络里称为:代价/损失函数)
L o s s = 1 2 ( f 1 ( w ) − f 2 ( w ) ) 2 Loss=\cfrac{1}{2}(f_1(w)-f_2(w))^2 Loss=21(f1(w)f2(w))2,于是问题转换为最小化 L o s s Loss Loss
作为人类我们自然可以直接求导数,导数为零的点就是极值点,但计算机不一定能解得出那个方程组, 因此计算机只能通过不断逼近去接近这个导数为零的点,而我们都知道,导数方向相反方向,是函数的下降方向,因此每次更新操作就是:
w = w − η ∂ L o s s w w=w-\eta \cfrac{\partial Loss}{w} w=wηwLoss

设学习率 η = 0.1 \eta=0.1 η=0.1

那么随机初始化一个点 x=1,
L o s s ∣ w = 1 = 2 Loss|_{w=1}=2 Lossw=1=2

∂ L o s s w ∣ w = 1 = ( w 2 + 1 ) ⋅ 2 w = 4 \cfrac{\partial Loss}{w}\bigg|_{w=1}=(w^2+1)\cdot 2w=4 wLoss w=1=(w2+1)2w=4

w = w − 0.1 ∗ 4 = 0.6 w=w-0.1*4=0.6 w=w0.14=0.6

L o s s ∣ w = 0.6 = 0.9428 Loss|_{w=0.6}=0.9428 Lossw=0.6=0.9428 ,可以看到有所降低

如此反复直至误差足够低,这就是梯度下降的过程


下面进入正题

神经网络梯度下降必须求得导数, 而反向传播其实就是求 导数 的过程,所以并不是更新过程, 因此,我们这片文章主要讲的是:矩阵层面的链式求导法则

在上面的简单例子里,求导是一件很容易的事,

但设想一下假如:损失函数 L o s s = F 1 ( w 1 , F 2 ( w 2 , F 3 ( w 3 , x 1 , x 2 , x 3 , . . . , x n ) ) ) ) Loss=F_1(w_1,F_2(w_2,F_3(w_3,x_1,x_2,x_3,...,x_n)))) Loss=F1(w1,F2(w2,F3(w3,x1,x2,x3,...,xn))))
那么求导就不太容易了,事实上,每个F恰好对应一个神经网络的’层’,

请注意(这个函数是随便写的不要在意…),在这里,我们需要更新的参数是 w 1 , w 2 , w 3 w_1,w_2,w_3 w1,w2,w3,而不是样本参数 x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3

那么现在我们思考两个问题,

1.为什么叫它反向传播呢?

2.传播的是什么呢?

先说结论:
1.反向传播是指在神经网络里使用链式求导法则求导,需要从后往前求,这样就可以求出沿途所有参数的导数
2.传播的是‘误差‘,其实误差就是导数,比如上面那个函数,若我们已经求得了 ∂ L o s s ∂ F 1 \cfrac{\partial Loss}{\partial F_1} F1Loss(这往往并不难),
那么我们记当前导数为 c g r a d = ∂ L o s s ∂ F 1 cgrad=\cfrac{\partial Loss}{\partial F_1} cgrad=F1Loss,可以发现我们想求 ∂ L o s s ∂ w 2 \cfrac{\partial Loss}{\partial w_2} w2Loss 就必须求 ∂ L o s s ∂ F 2 \cfrac{\partial Loss}{\partial F_2} F2Loss,
∂ L o s s ∂ F 2 = ∂ F 1 ∂ F 2 ⋅ c g r a d , \cfrac{\partial Loss}{\partial F_2}=\cfrac{\partial F_1}{\partial F_2}\cdot cgrad, F2Loss=F2F1cgrad, 只要求得 ∂ F 1 ∂ F 2 \cfrac{\partial F_1}{\partial F_2} F2F1即可求得它。

然后更新当前导数 c g r a d = ∂ L o s s ∂ F 2 cgrad=\cfrac{\partial Loss}{\partial F_2} cgrad=F2Loss,

于是求得 ∂ L o s s ∂ w 2 = ∂ F 2 ∂ w 2 ⋅ c g r a d \cfrac{\partial Loss}{\partial w_2}=\cfrac{\partial F_2}{\partial w_2}\cdot cgrad w2Loss=w2F2cgrad,

c g r a d = ∂ L o s s ∂ F 2 cgrad=\cfrac{\partial Loss}{\partial F_2} cgrad=F2Loss已经求得,

因此只要求出 ∂ F 2 ∂ F 3 \cfrac{\partial F_2}{\partial F_3} F3F2,就可以求出 ∂ L o s s ∂ F 3 \cfrac{\partial Loss}{\partial F_3} F3Loss,求出之后,更新 c g r a d = ∂ L o s s ∂ F 3 , . . . . . . cgrad=\cfrac{\partial Loss}{\partial F_3},...... cgrad=F3Loss,......

过程中 c g r a d cgrad cgrad 不断更新,因此传播的就是 c g r a d cgrad cgrad ,而 c g r a d cgrad cgrad 其实就可以理解成,最终的误差反向传播到当前层的误差


二、全连接网络的反向传播

相信大家都了解全连接层,
全连接层的 BP 比较好理解,可以看我的这篇博客的封面图,图在文中 反向传播原理公式 反向传播原理公式 反向传播原理公式 章节下面,还是比较形象的,在此就不过多讲解了(…)

这里再次给出这两个在全连接层 BP 中十分重要的公式(求导采用分母布局):

∂ z ∂ X = A T ⋅ ∂ z ∂ ( A X ) ,   w h e r e   z = f ( A X ) ∈ R ,   A ∈ R m × n ,   X ∈ R n × p \cfrac{\partial z}{\partial X}=A^T \cdot \cfrac{\partial z}{\partial (AX)} , \ where\ z=f(AX) \in R , \ A \in R^{m \times n} , \ X \in R^{n \times p} Xz=AT(AX)z, where z=f(AX)R, ARm×n, XRn×p
∂ z ∂ X = ∂ z ∂ ( X B ) ⋅ B T ,   w h e r e   z = f ( X B ) ∈ R ,   B ∈ R p × m   ,   X ∈ R n × p \cfrac{\partial z}{\partial X}=\cfrac{\partial z}{\partial (XB)} \cdot B^T ,\ where \ z=f(XB) \in R, \ B \in R^{p \times m}\ , \ X \in R^{n \times p} Xz=(XB)zBT, where z=f(XB)R, BRp×m , XRn×p

我们在推导CNN反向传播时会用到 !

三、卷积网络(CNN)的反向传播(BP)

我们在此推导带有通道的、多卷积核的二维卷积的BP,

本篇中的各种矩阵的初始形式与torch里完全相同 (比如卷积核的形状,图像的形状等)

本节各种符号和函数其实用numpy和torch都很好实现,只是为了方便书写

因为我们要贴合torch去推导,因此给出torch卷积操作的参数是必要的,下面给出所有对运算产生决定性影响的参数:

n n . C o n v 2 d ( i n _ c h a n n e l s   :   i n t , o u t _ c h a n n e l s   :   i n t , k e r n e l _ s i z e   :   U n i o n [ i n t   , T u p l e [ i n t , i n t ]   ] , s t r i d e   :   U n i o n [   i n t   , T u p l e [ i n t , i n t ]   ] = 1 , p a d d i n g   :   U n i o n [ s t r   , i n t ,   T u p l e [ i n t , i n t ]   ] = 0 , d i l a t i o n   :   U n i o n [ i n t   , T u p l e [ i n t , i n t ]   ] = 1 , ) nn.Conv2d(\\ \quad \quad in\_channels\ :\ int,\\ \quad \quad out\_channels\ : \ int,\\ \quad \quad kernel\_size\ :\ Union[int\ , Tuple[int, int]\ ],\\ \quad \quad stride \ :\ Union[\ int\ , Tuple[int, int]\ ] = 1,\\ \quad \quad padding \ :\ Union[str\ , int, \ Tuple[int, int]\ ] = 0,\\ \quad \quad dilation\ : \ Union[int\ , Tuple[int, int]\ ] = 1,\\ ) nn.Conv2d(in_channels : int,out_channels : int,kernel_size : Union[int ,Tuple[int,int] ],stride : Union[ int ,Tuple[int,int] ]=1,padding : Union[str ,int, Tuple[int,int] ]=0,dilation : Union[int ,Tuple[int,int] ]=1,)

这里顺便提一下 n n . C o n v 3 d nn.Conv3d nn.Conv3d 也是这几个参数,只不过 k e r n e l _ s i z e , s t r i d e , p a d d i n g , d i l a t i o n kernel\_size ,stride,padding,dilation kernel_size,stride,padding,dilation都多了一维【后面会用到】

这些参数分别表示
in_channels: 输入通道维度

out_channels: 输出通道维度

kernel_size: 单个卷积核大小,通道与输入通道相同,高和宽分别对应图像高和宽

stride: 在输入图像高和宽两个维度的卷积步长

padding: 在输入图像高和宽两个维度两端的填充行数 (我们本篇默认填0)

dilation: 对卷积核的高和宽两个维度分别进行"膨胀" 的 “倍数”

1. 一些会用到的公式

(1)符号定义和卷积操作

A ∈ R c × h × w A \in R^{c\times h\times w} ARc×h×w是输入带通道维度( c c c )的图像, K ∈ R o c × c × k h × k w K \in R^{oc\times c \times kh \times kw} KRoc×c×kh×kw是对应于该图像的卷积核矩阵,
其中 o c oc oc 表示卷积核的个数,也是卷积输出图像的通道维度,

∗ * ’为卷积符号,

我们用 K i = K [   i   ] ∈ R c × k h × k w K_i=K[ \ i \ ] \in R^{c \times kh \times kw} Ki=K[ i ]Rc×kh×kw表示单个卷积核

这里给出快速计算卷积结果的公式,并且我们加入空洞卷积的概念(这个对公式推导很重要 ) :
【大家可以阅读这篇关于空洞卷积的博客

其中 p h , p w ph,pw ph,pw p a d d i n g padding padding 高和宽, s h , s w sh,sw sh,sw 为卷积步长, d h , d w dh,dw dh,dw 为膨胀系数,则:

输出图像的高度 o h = ⌊ h + 2 p h − ( ( k h − 1 ) ⋅ d h + 1 ) s h ⌋ + 1 oh=\lfloor \cfrac{h+2ph-((kh-1)\cdot dh+1)}{sh} \rfloor+1 oh=shh+2ph((kh1)dh+1)+1
输出图像的宽度 o w = ⌊ w + 2 p w − ( ( k w − 1 ) ⋅ d w + 1 ) s w ⌋ + 1 ow=\lfloor \cfrac{w+2pw-((kw-1)\cdot dw+1)}{sw} \rfloor+1 ow=sww+2pw((kw1)dw+1)+1

注意当膨胀系数 d h = d w = 1 dh=dw=1 dh=dw=1 时,空洞卷积就是普通卷积,上面的公式也可以验证这一点

【注】因为 p a d pad pad 是在图像周围填0,修改了图像, 而 d i l a t e dilate dilate 实际上是在卷积核的间隙填 0,修改了卷积核,是在这两个操作之后才开始正式卷积,因此这两个操作只是一种优化处理的方法,并没有修改卷积运算的本质,实际上只有 s t r i d e stride stride 参数对卷积运算的方式有所影响

(2)定义一些函数(现在不用理解,看到后面可以回来找)

F l a t t e n Flatten Flatten
记函数 F = F l a t t e n : ( . . . , c , k h , k w , . . . ) → ( . . . , c ⋅ k h ⋅ k w , . . . ) F=Flatten:(...,c,kh,kw,...)\rightarrow (...,c \cdot kh \cdot kw,...) F=Flatten:(...,c,kh,kw,...)(...,ckhkw,...),表示摊平( c , k h , k w c,kh,kw c,kh,kw)这三个维度, (其逆函数记为 F − 1 F^{-1} F1)
关于逆函数,只需要事先记录好形状就很好实现,使用numpy和torch里的reshape即可

M e r g e Merge Merge
记函数 M = M e r g e : ( . . . , o h , o w , . . . ) → ( . . . , o h ⋅ o w , . . . ) M=Merge:(...,oh,ow,...)\rightarrow (...,oh \cdot ow,...) M=Merge:(...,oh,ow,...)(...,ohow,...),表示摊平( o h , o w oh,ow oh,ow)这两个维度 , (其逆函数为 M − 1 M^{-1} M1)

E l e v a t e Elevate Elevate
记函数 E = E l e v a t e : ( . . , c , . . . ) → ( . . . c , 1 , . . . ) E=Elevate:(..,c,...)\rightarrow(...c,1,...) E=Elevate:(..,c,...)(...c,1,...),用于升高图像和卷积核的维度(添加时序维度),(其逆函数为 E − 1 E^{-1} E1)

P a c k Pack Pack
记函数 P = P a c k : ( . . , d , . . . ) → ( . . . 1 , d , . . . ) P=Pack:(..,d,...)\rightarrow(...1,d,...) P=Pack:(..,d,...)(...1,d,...),用于升高图像的维度(添加通道维度),(其逆函数为 P − 1 P^{-1} P1)

S t a c k Stack Stack
S t a c k Stack Stack 为对第一个维度进行堆叠,比如: S t a c k 2 p = 0 [   [ p , p + 1 ]   ] = [ [ 0 1 ] [ 1 2 ] [ 2 3 ] ] \underset{p=0}{\overset{2}{Stack}}[\ [p,p+1] \ ]=\begin{bmatrix} [0 &1]\\ [1 &2] \\ [2 & 3]\end{bmatrix} p=0Stack2[ [p,p+1] ]= [0[1[21]2]3] (Stack 用 numpy非常容易实现)

P a d p h × p w Pad_{ph\times pw} Padph×pw
表示对图像 h h h 维度上下分别填充 p h ph ph 行 0,对图像 w w w 维度左右分别填充 p w pw pw 行 0,
P a d 0 × 0 ( A ) = A Pad_{0 \times 0}(A)=A Pad0×0(A)=A

D i l a t e d h × d w Dilate_{dh\times dw} Dilatedh×dw
表示对卷积核 k h kh kh 维度膨胀 d h dh dh 倍,对卷积核 k w kw kw 维度膨胀 d w dw dw倍,
D i l a t e 1 × 1 ( K ) = K Dilate_{1 \times 1}(K)=K Dilate1×1(K)=K

R o t π Rot\pi Rotπ
旋转180度

(3)二维卷积的交换律

【注意这里我们默认 A A A 已经过 p a d pad pad 操作 , K i K_i Ki 已经过 d i l a t e dilate dilate 操作】

给出公式:

A ∗ K i = P a d ( h − k h ) × ( w − k w ) ( R o t π ( K i ) ) ∗ R o t π ( A ) A * K_i=Pad_{(h-kh) \times(w-kw)}(Rot\pi(K_i)) * Rot\pi(A) AKi=Pad(hkh)×(wkw)(Rotπ(Ki))Rotπ(A) ,(必须有: k h ≤ h   a n d   k w ≤ w kh \leq h \ and \ kw \leq w khh and kww,这里 P a d Pad Pad R o t π Rot\pi Rotπ 可以交换)

【说明】这里 P a d Pad Pad 和卷积里的padding方式一样,并且填充的是 0 ,参数 p h = h − k h ,   p w = w − k w ph= h-kh, \ pw=w-kw ph=hkh, pw=wkw

举个栗子:

A = [ 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 ] A =\begin{bmatrix} 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{bmatrix} A= a11a21a31a41a12a22a32a42a13a23a33a43a14a24a34a44

K i = [ k 11 k 12 k 21 k 22 ] K_i=\begin{bmatrix} k_{11} & k_{12} \\ k_{21} & k_{22} \end{bmatrix} Ki=[k11k21k12k22]

P a d 2 × 2 ( R o t π ( K i ) ) = [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 k 22 k 21 0 0 0 0 k 12 k 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] Pad_{2\times 2}(Rot\pi(K_i))=\begin{bmatrix} 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & k_{22} & k_{21} & 0 & 0\\ 0 & 0 & k_{12} & k_{11} & 0 & 0\\ 0 & 0 & 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0 & 0 & 0 \end{bmatrix} Pad2×2(Rotπ(Ki))= 00000000000000k22k120000k21k1100000000000000

R o t π ( A ) = [ a 44 a 43 a 42 a 41 a 34 a 33 a 32 a 31 a 24 a 23 a 22 a 21 a 14 a 13 a 12 a 11 ] Rot\pi(A)=\begin{bmatrix} a_{44}& a_{43} & a_{42} & a_{41} \\ a_{34}& a_{33} & a_{32} & a_{31} \\ a_{24}& a_{23} & a_{22} & a_{21} \\ a_{14}& a_{13} & a_{12} & a_{11} \\ \end{bmatrix} Rotπ(A)= a44a34a24a14a43a33a23a13a42a32a22a12a41a31a21a11

其实可以发现用单个卷积核 K i K_i Ki作为卷积核 去卷图像 A A A, 和用 R o t π ( A ) Rot\pi(A) Rotπ(A) 作为卷积核去卷 P a d ( R o t π ( K i ) ) Pad(Rot\pi(K_i)) Pad(Rotπ(Ki))的结果是一样的,并且不管卷积步长是多少都一样!
其实这很好理解,
因为大家在卷积的时候总是默认让卷积核动而图像固定,想像一下图像在动而卷积核固定,这个交换律就是一个很显然的结论 !

注意为了方便展示, 上面的例子没有加入通道层,如果有多个通道,那么通道维度始终不变,旋转时只旋转后两个维度( k h kh kh k w kw kw ), P a d Pad Pad 的时候把三(多)个通道的相应位置填0即可.


2.前向传播-------将卷积操作转换为矩阵乘法(先不考虑pad和dilate)

【注意以下我们假定 A A A 已经过 p a d pad pad 操作 , K i K_i Ki 已经过 d i l a t e dilate dilate 操作,因为两个操作不影响卷积运算,我们最后再用这两个操作后的结果替换即可】

转成矩阵乘法有一个好处,就是可以加速运算,但还有一个非常好的好处,那就是求导方便

而这么做的依据是 卷积的每一步其实都类似于矩阵乘法!,当我们想象卷积核在动而图像不动时,我们把每个卷
积核 摊平 成形状: K i ∈ R 1 × ( c ⋅ k h ⋅ k w ) K_i \in R^{1 \times (c \cdot kh \cdot kw)} KiR1×(ckhkw)

每一个卷积步的图像 A [   :   ] [ i , i + k h ] [ j , j + k w ] ∈ R c × k h × k w A[\ :\ ][i,i+kh][j,j+kw] \in R^{c \times kh \times kw} A[ : ][i,i+kh][j,j+kw]Rc×kh×kw (表示在多通道图像 A A A中以 ( i , j ) (i ,j) (i,j)位置为左上角取出卷积核大小的部分图像) 摊平 R 1 × ( c ⋅ k h ⋅ k w ) R^{1\times (c \cdot kh \cdot kw)} R1×(ckhkw)

注意这两种摊平方法要一致,保证摊平后对应元素位置仍然相同,而用同一个 F F F 作用就保证了这点。

那么每个卷积步的卷积操作的结果(设此时 s h = s w = 1 sh=sw=1 sh=sw=1),就可写矩阵乘法的形式:

A [   :   ] [ i , i + k h ] [ j , j + k w ] ∗ K i = F ( K i ) ⋅ F ( A [   :   ] [ i , i + k h ] [ j , j + k w ] ) T ∈ R 1 A[\ :\ ][i,i+kh][j,j+kw]*K_i=F(K_i) \cdot F(A[\ :\ ][i,i+kh][j,j+kw])^T \in R^{1} A[ : ][i,i+kh][j,j+kw]Ki=F(Ki)F(A[ : ][i,i+kh][j,j+kw])TR1

如果有多个卷积核,那么结果可以写成:

A [   :   ] [ i , i + k h ] [ j , j + k w ] ∗ K = F ( K ) ⋅ F ( A [   :   ] [ i , i + k h ] [ j , j + k w ] ) T ∈ R o c A[\ :\ ][i,i+kh][j,j+kw]*K=F(K) \cdot F(A[\ :\ ][i,i+kh][j,j+kw])^T \in R^{oc} A[ : ][i,i+kh][j,j+kw]K=F(K)F(A[ : ][i,i+kh][j,j+kw])TRoc

因此我们只需要按照卷积顺序依次切片取出 A A A 中的部分元素,摊平后堆叠成输出图像的形状即可
[注意如果一个矩阵 A 1 ∈ R d 1 × d 2 × d 3 A_1 \in R^{d_1\times d_2 \times d_3} A1Rd1×d2×d3,那么它和一个矩阵 A 2 ∈ R d 3 × d 4 × d 5 A_2 \in R^{d_3 \times d_4 \times d_5} A2Rd3×d4×d5 相乘只需要看 d 3 d_3 d3维度即可,结果为 A 1 ⋅ A 2 ∈ R d 1 × d 2 × d 4 × d 5 A_1 \cdot A_2 \in R^{d_1 \times d_2 \times d_4 \times d_5} A1A2Rd1×d2×d4×d5]

设此时 A A A 已完成 p a d d i n g padding padding ,步长参数 s t r i d e = ( s h , s w ) stride=(sh,sw) stride=(sh,sw),我们先通过卷积结果公式计算出卷积输出图像的高和宽 ( o h , o w ) (oh,ow) (oh,ow),并用 O ∈ R o c × o h × o w O \in R^{oc \times oh \times ow} ORoc×oh×ow来表示卷积结果,

A ( i , j ) = A [   :   ] [ i ⋅ s h , i ⋅ s h + k h ] [ j ⋅ s w , j ⋅ s w + k w ] A(i,j)=A[\ :\ ][i\cdot sh,i\cdot sh+kh][j\cdot sw,j\cdot sw+kw] A(i,j)=A[ : ][ish,ish+kh][jsw,jsw+kw]为在多通道图像 A A A中以 ( i ⋅ s h , j ⋅ s w ) (i \cdot sh,j\cdot sw) (ish,jsw)位置为左上角 取出卷积核大小的部分图像

那么有:

A ∗ K = S t a c k o c − 1 p = 0 [ S t a c k o h − 1 i = 0 [ S t a c k o w − 1 j = 0 [ A ( i , j ) ∗ K p   ]   ]   ] = S t a c k o c − 1 p = 0 [ S t a c k o h − 1 i = 0 [ S t a c k o w − 1 j = 0 [ F ( K p ) ⋅ F ( A ( i , j ) ) T   ]   ]   ] = S t a c k o c − 1 p = 0 [ F ( K p ) ⋅ M − 1 ( M ( S t a c k o h − 1 i = 0 [ S t a c k o w − 1 j = 0 [ F ( A ( i , j ) )   ]   ] ) T )   ] (这一步需要仔细想想) = F ( K ) ⋅ M − 1 ( M ( S t a c k o h − 1 i = 0 [ S t a c k o w − 1 j = 0 [ F ( A ( i , j ) )   ]   ] ) T )   = O ∈ R o c × o h × o w A*K\\=\underset{p=0}{\overset{oc-1}{Stack}}[\underset{i=0}{\overset{oh-1}{Stack}}[\underset{j=0}{\overset{ow-1}{Stack}}[ A(i,j)*K_p\ ] \ ] \ ] \\=\underset{p=0}{\overset{oc-1}{Stack}}[\underset{i=0}{\overset{oh-1}{Stack}}[\underset{j=0}{\overset{ow-1}{Stack}}[ F(K_p) \cdot F(A(i,j))^T\ ] \ ] \ ] \\ =\underset{p=0}{\overset{oc-1}{Stack}}[F(K_p) \cdot M^{-1} (M(\underset{i=0}{\overset{oh-1}{Stack}}[\underset{j=0}{\overset{ow-1}{Stack}}[ F(A(i,j))\ ]\ ])^T) \ ](这一步需要仔细想想) \\=F(K) \cdot M^{-1} (M(\underset{i=0}{\overset{oh-1}{Stack}}[\underset{j=0}{\overset{ow-1}{Stack}}[ F(A(i,j))\ ]\ ])^T) \ \\=O \in R^{oc \times oh \times ow} AK=p=0Stackoc1[i=0Stackoh1[j=0Stackow1[A(i,j)Kp ] ] ]=p=0Stackoc1[i=0Stackoh1[j=0Stackow1[F(Kp)F(A(i,j))T ] ] ]=p=0Stackoc1[F(Kp)M1(M(i=0Stackoh1[j=0Stackow1[F(A(i,j)) ] ])T) ](这一步需要仔细想想)=F(K)M1(M(i=0Stackoh1[j=0Stackow1[F(A(i,j)) ] ])T) =ORoc×oh×ow

至此我们把卷积操作 通过对原图像的切片和堆叠 转换成了 矩阵乘法 !
这样做有个非常大的好处就是,我们在反向传播中求卷积核的导数会非常容易,
这不就是全连接层的求导吗?

(别急,上面的式子还没有简化,不是最终形态)


3.反向传播-------误差对卷积核参数求导

我们已经将卷积操作转换成矩阵乘法(看到最后!过程很"复杂",但是结果…也不是很简单,但是很全面)

【注】以下的卷积运算 ‘ ∗ * ’,除非特别说明,否则都包含卷积核的个数维度

(1)用全连接层的 BP 公式来计算 CNN 的 BP

设最终误差为 L ∈ R L\in R LR,前向传播有 A ∗ K = O A * K=O AK=O,
且已经求得了 L L L对输出层 O O O 的导数 ∂ L ∂ O \cfrac{\partial L}{\partial O} OL
我们现在需要求 ∂ L ∂ K \cfrac{\partial L}{\partial K} KL

不要忘记,在前向传播中我们是这样计算卷积的

A ∗ K = F ( K ) ⋅ M − 1 ( M ( S t a c k o h − 1 i = 0 [ S t a c k o w − 1 j = 0 [ F ( A ( i , j ) )   ]   ] ) T ) A*K= F(K) \cdot M^{-1} (M(\underset{i=0}{\overset{oh-1}{Stack}}[\underset{j=0}{\overset{ow-1}{Stack}}[ F(A(i,j))\ ]\ ])^T) AK=F(K)M1(M(i=0Stackoh1[j=0Stackow1[F(A(i,j)) ] ])T)

我们先进一步简化写法:

F ( A [ c h a n n e l , r o w , c o l ] ) = S t a c k o h − 1 i = 0 [ S t a c k o w − 1 j = 0 [ F ( A ( i , j ) )   ]   ] ∈ R o h × o w × ( c ⋅ k h ⋅ k w ) F(A[channel,row,col])^= \underset{i=0}{\overset{oh-1}{Stack}}[\underset{j=0}{\overset{ow-1}{Stack}}[F( A(i,j))\ ] \ ] \in R^{oh \times ow \times (c \cdot kh \cdot kw)} F(A[channel,row,col])=i=0Stackoh1[j=0Stackow1[F(A(i,j)) ] ]Roh×ow×(ckhkw),


这么写不是没有道理的 (事实上可以通过numpy索引操作轻松实现):
其中 c h a n n e l , r o w , c o l channel,row,col channel,row,col 的形状和这一坨 S t a c k o h − 1 i = 0 [ S t a c k o w − 1 j = 0 [ F ( A ( i , j ) )   ]   ] \underset{i=0}{\overset{oh-1}{Stack}}[\underset{j=0}{\overset{ow-1}{Stack}}[F( A(i,j))\ ] \ ] i=0Stackoh1[j=0Stackow1[F(A(i,j)) ] ] 相同,

分别表示 这一坨式子表示的矩阵 中的元素 在 A A A 中的位置的行,列,通道的索引 组成的矩阵,
具体地,只需要找到卷积过程中行,列,通道维度的索引变化规律,把每一步卷积对应的三个索引都堆叠成 R o h × o w × c × k h × k w R^{oh \times ow \times c \times kh \times kw} Roh×ow×c×kh×kw 的形状就分别得到了 c h a n n e l , r o w , c o l channel,row,col channel,row,col

(如果了解了numpy的索引操作这个会很好理解,实际上代码层面我们也是这么实现的)

[注意,行( r o w row row)体现高度( h h h),列( c o l col col)体现宽度( w w w),我们在取索引时,更看重 A A A 的矩阵性质而不是图像性质,因此采用 ( c h a n n e l , r o w , c o l ) (channel,row,col) (channel,row,col) 而不是 ( c , h , w ) (c,h,w) (c,h,w)]

简化之后的卷积结果(前向传播)的写法为:

A ∗ K = F ( K ) ⋅ M − 1 ( M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T )   = O ∈ R o c × o h × o w A*K=F(K) \cdot M^{-1}(M(F(A[channel,row,col]))^T) \ =O \in R^{oc \times oh \times ow} AK=F(K)M1(M(F(A[channel,row,col]))T) =ORoc×oh×ow

虽然看起来很复杂,但其实从内向外使用numpy每一步都很容易,

唯独切片索引取值操作 A [ c h a n n e l , r o w , c o l ] A[channel,row,col] A[channel,row,col]需要思考一番

由于 K K K F ( K ) F(K) F(K)只是形状有变化,而我们可以事先记录 K K K的形状,因此
我们又可以很容易将 F ( K ) F(K) F(K)通过, F − 1 ( F ( K ) ) = K F^{-1}(F(K))=K F1(F(K))=K,恢复成原形状,

既然导数矩阵和原矩阵形状相同且一 一对应,因此我们先求 F ( K ) ∈ R o c × ( c ⋅ k h ⋅ k w ) F(K) \in R^{oc \times (c \cdot kh \cdot kw)} F(K)Roc×(ckhkw)的导数,再恢复形状就好了

但如果我们想用全连接层BP的这个公式,还有一点不满足,那就是 M − 1 ( M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T ) ∈ R ( c ⋅ k h ⋅ k w ) × o h × o w , O ∈ R o c × o h × o w M^{-1}(M(F(A[channel,row,col]))^T)\in R^{ (c\cdot kh \cdot kw)\times oh \times ow}, O \in R^{oc \times oh \times ow} M1(M(F(A[channel,row,col]))T)R(ckhkw)×oh×ow,ORoc×oh×ow

都是三维的不是二维的,怎么办呢?

其实解决方法相当简单,别忘了之所以 M − 1 ( M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T ) M^{-1}(M(F(A[channel,row,col]))^T) M1(M(F(A[channel,row,col]))T) O O O,前两个维度是 o h × o w oh \times ow oh×ow 是因为我们在堆叠的时候( S t a c k [ S t a c k [ . . . . ] ] Stack[Stack[....]] Stack[Stack[....]])就是这样叠的 !
只是为了让 O O O 以图像的形状输出, 方便下一层的卷积,实际上我们完全可以合并它们的前两个维度 !

但我们还是从理论方面去理解:

给出具体公式:

M ( M − 1 ( M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T ) ) = M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T ∈ R ( c ⋅ k h ⋅ k w ) × ( o h ⋅ o w ) M(M^{-1}(M(F(A[channel,row,col]))^T))=M(F(A[channel,row,col]))^T \in R^{(c \cdot kh \cdot kw) \times (oh \cdot ow) } M(M1(M(F(A[channel,row,col]))T))=M(F(A[channel,row,col]))TR(ckhkw)×(ohow)

M ( O ) ∈ R o c × ( o h ⋅ o w ) M(O) \in R^{oc \times (oh \cdot ow)} M(O)Roc×(ohow)

然后因为 M ( F ( K ) ⋅ M − 1 ( M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T ) ) = M ( O ) M(F(K) \cdot M^{-1}(M(F(A[channel,row,col]))^T) )=M(O) M(F(K)M1(M(F(A[channel,row,col]))T))=M(O)

M M M 此时作用于后两个维度,不影响矩阵乘法 ! 因此有:

F ( K ) ⋅ M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T = M ( O ) F(K) \cdot M(F(A[channel,row,col]))^T=M(O) F(K)M(F(A[channel,row,col]))T=M(O)

我们终于可以用那个公式了!根据公式我们有:

∂ L ∂ F ( K ) = ∂ L ∂ M ( O ) ⋅ M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) ∈ R o c × ( c ⋅ k h ⋅ k w ) \cfrac{\partial L}{\partial F(K)}=\cfrac{\partial L}{\partial M(O)}\cdot M(F(A[channel,row,col]))\in R^{oc \times (c \cdot kh \cdot kw)} F(K)L=M(O)LM(F(A[channel,row,col]))Roc×(ckhkw)

因此导数写为:

∂ L ∂ K = F − 1 ( ∂ L ∂ F ( K ) ) = F − 1 ( ∂ L ∂ M ( O ) ⋅ M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) ) \cfrac{\partial L}{\partial K}=F^{-1}(\cfrac{\partial L}{\partial F(K)})=F^{-1}(\cfrac{\partial L}{\partial M(O)} \cdot M(F(A[channel,row,col]))) KL=F1(F(K)L)=F1(M(O)LM(F(A[channel,row,col])))

请注意我们只知道 ∂ L ∂ O \cfrac{\partial L}{\partial O} OL的导数,因此还需要用它来表示 ∂ L ∂ M ( O ) \cfrac{\partial L}{\partial M(O)} M(O)L,由于 L L L是标量,直接提出来就行,写为:

∂ L ∂ K = F − 1 ( M ( ∂ L ∂ O ) ⋅ M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) ) \cfrac{\partial L}{\partial K}=F^{-1}(M(\cfrac{\partial L}{\partial O}) \cdot M(F(A[channel,row,col]))) KL=F1(M(OL)M(F(A[channel,row,col])))

其实最终我们在编程的时候就可以采用这种计算方式,一次性就能计算出所有卷积核的偏导数

而上面的式子可以进一步简化:

我们先考虑是否能够去掉最外层的 F − 1 F^{-1} F1,

F − 1 F^{-1} F1就做了一件事:就是把维度 ( . . . , c ⋅ k h ⋅ k w , . . . ) 恢复为 ( . . . , c , k h , k w , . . . ) (... ,c \cdot kh \cdot kw,...)恢复为(...,c,kh,kw,...) (...,ckhkw,...)恢复为(...,c,kh,kw,...)

而我们发现 F − 1 F^{-1} F1内的两个矩阵乘法作用维度与 F − 1 F^{-1} F1的此时作用维度无关!

因此完全可以直接作用于 M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) M(F(A[channel,row,col])) M(F(A[channel,row,col])) ,于是写为:

∂ L ∂ K = M ( ∂ L ∂ O ) ⋅ F − 1 ( M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) ) \cfrac{\partial L}{\partial K}=M(\cfrac{\partial L}{\partial O}) \cdot F^{-1}(M(F(A[channel,row,col]))) KL=M(OL)F1(M(F(A[channel,row,col])))

而请注意对于 A [ c h a n n e l , r o w , c o l ] ∈ R o h × o w × c × k h × k w A[channel,row,col] \in R^{oh \times ow \times c\times kh \times kw} A[channel,row,col]Roh×ow×c×kh×kw 来说, M M M合并的是它的前两个维度, F F F 合并的是它的后三个维度,且维度之间不重合,这意味着他们是可以交换的

于是最终的偏导数为:

∂ L ∂ K = M ( ∂ L ∂ O ) ⋅ M ( A [ c h a n n e l , r o w , c o l ] ) \cfrac{\partial L}{\partial K}=M(\cfrac{\partial L}{\partial O}) \cdot M(A[channel,row,col]) KL=M(OL)M(A[channel,row,col])            ( ∗ ) \ \ \ \ \ \ \ \ \ \ (*)           ()

其中 M ( ∂ L ∂ O ) ∈ R o c × ( o h ⋅ o w ) ,    M ( A [ c h a n n e l , r o w , c o l ] ) ) ∈ R ( o h ⋅ o w ) × c × k h × k w , M(\cfrac{\partial L}{\partial O}) \in R^{oc \times (oh \cdot ow)} , \ \ M(A[channel,row,col])) \in R^{(oh \cdot ow) \times c \times kh \times kw}, M(OL)Roc×(ohow),  M(A[channel,row,col]))R(ohow)×c×kh×kw, 可以发现完全吻合!

我们消掉了 F , F − 1 F , F^{-1} F,F1, 虽然这个式子看起来仍然有些复杂,但对于编程而言,每一个部分式子实现起来都很轻松,
但是注意,在numpy和torch计算矩阵乘法时,第二个矩阵的维度不能超过两维,因此消去 F F F F − 1 F^{-1} F1只是为了形式上的化简
【注】根据 M M M 的定义, 对于 ∂ L ∂ O \cfrac{\partial L}{\partial O} OL , M M M合并它的后两个维度,对于 A [ c h a n n e l , r o w , c o l ] A[channel,row,col ] A[channel,row,col], M M M 合并它的前两个维度,因此并不矛盾. 函数 F F F 也同理


那么还能再简化吗?

能 !不过能简化的只是数学形式而不是编程了

(2)形式上进一步简化BP方程

我们再次仔细回顾这个等式:

A ∗ K = F ( K ) ⋅ M − 1 ( M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T ) A*K=F(K) \cdot M^{-1}(M(F(A[channel,row,col]))^T) AK=F(K)M1(M(F(A[channel,row,col]))T)

其中 F ( K ) ∈ R o c × ( c ⋅ k h ⋅ k w ) ,    M − 1 ( M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T ) ∈ R ( c ⋅ k h ⋅ k w ) × o h × o w F(K) \in R^{oc \times (c \cdot kh \cdot kw)}, \ \ M^{-1}(M(F(A[channel,row,col]))^T) \in R^{(c\cdot kh \cdot kw) \times oh \times ow} F(K)Roc×(ckhkw),  M1(M(F(A[channel,row,col]))T)R(ckhkw)×oh×ow

不难发现   ( ∗ ) \ (*)  () 式 右端和上式右端的运算形式上非常相似,只不过 F F F 摊平了三个维度,而 M M M 摊平了两个维度, 这是否意味着,我们可以把   ( ∗ ) \ (*)  () 式 转换成卷积的形式呢?

为此我们统一 一下形式:

我们把上式的 M − 1 M^{-1} M1 提出来:

A ∗ K = M − 1 ( F ( K ) ⋅ M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T ) A*K=M^{-1}(F(K) \cdot M(F(A[channel,row,col]))^T) AK=M1(F(K)M(F(A[channel,row,col]))T)

两边同时用 M M M 作用,
并且一个维度值是一个数值,因此我们完全可以把 ( o h ⋅ o w ) (oh \cdot ow) (ohow)写成 ( 1 ⋅ o h ⋅ o w ) (1 \cdot oh \cdot ow) (1ohow)
得到形式:

M ( A ∗ K ) = F ( K ) ⋅ M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T      ( Δ ) M(A*K)=F(K) \cdot M(F(A[channel,row,col]))^T \ \ \ \ (\Delta) M(AK)=F(K)M(F(A[channel,row,col]))T    (Δ)

其中 F ( K ) ∈ R o c × ( c ⋅ k h ⋅ k w ) ,   M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T ∈ R ( c ⋅ k h ⋅ k w ) × ( 1 ⋅ o h ⋅ o w ) F(K) \in R^{oc \times (c \cdot kh \cdot kw)}, \ M(F(A[channel,row,col]))^T \in R^{(c \cdot kh \cdot kw) \times (1 \cdot oh \cdot ow)} F(K)Roc×(ckhkw), M(F(A[channel,row,col]))TR(ckhkw)×(1ohow)

我们将   ( ∗ ) \ (*)  () 式两边用 F F F 作用:

F ( ∂ L ∂ K ) = F ( M ( ∂ L ∂ O ) ⋅ M ( A [ c h a n n e l , r o w , c o l ] ) ) F(\cfrac{\partial L}{\partial K})=F(M(\cfrac{\partial L}{\partial O}) \cdot M(A[channel,row,col])) F(KL)=F(M(OL)M(A[channel,row,col]))

因矩阵乘法的作用维度和 F F F 不同 , 因此 F F F 可直接作用于后者,

得到形式

F ( ∂ L ∂ K ) = M ( ∂ L ∂ O ) ⋅ F ( M ( A [ c h a n n e l , r o w , c o l ] ) )      ( ∇ ) F(\cfrac{\partial L}{\partial K})=M(\cfrac{\partial L}{\partial O}) \cdot F(M(A[channel,row,col])) \ \ \ \ (\nabla) F(KL)=M(OL)F(M(A[channel,row,col]))    ()

其中 M ( ∂ L ∂ O ) ∈ R o c × ( 1 ⋅ o h ⋅ o w ) , F ( M ( A [ c h a n n e l , r o w , c o l ] ) ) ∈ R ( 1 ⋅ o h ⋅ o w ) × ( c ⋅ k h ⋅ k w ) M(\cfrac{\partial L}{\partial O}) \in R^{oc \times (1 \cdot oh \cdot ow)} , F(M(A[channel,row,col])) \in R^{(1 \cdot oh \cdot ow) \times (c\cdot kh \cdot kw)} M(OL)Roc×(1ohow),F(M(A[channel,row,col]))R(1ohow)×(ckhkw)

至此   ( Δ ) \ (\Delta)  (Δ) 式和   ( ∇ ) \ (\nabla)  ()式在形式上统一,(括号内都是三个维度)


因此,我们有必要重新理解它们的含义

由于维度在含义上都升高了一维,我们自然想到用 三维卷积 去理解它们,



这里插一段,

给出这篇讲解三维卷积非常详细的博客
解释了什么是三维卷积,因为后面我们将会用三维卷积中的术语来描述多出来的那个维度(时序维度)



好的,现在我们了解了什么是三维卷积,因此我们也有必要先重新理解一下三维卷积的输入和卷积核:

此前的二维卷积里: A ∈ R c × h × w A \in R^{c \times h \times w} ARc×h×w , K ∈ R o c × c × k h × k w K \in R^{oc \times c \times kh \times kw} KRoc×c×kh×kw,

c c c 表示输入的通道维度 , o c oc oc 表示输出的通道维度,有多少个卷积核就有多少个输出通道

卷积遍历时,先在第一行上从左向右移动,每次移动 s w sw sw 个单位, 到行末后再换到该行下的第 s h sh sh 行的开头继续移动,直至遍历完整个图像

而三维卷积里:

输入 A ′ ∈ R c × d × h × w A'\in R^{c\times d \times h \times w} ARc×d×h×w , K ′ ∈ R o c × c × k d × k h × k w K' \in R^{oc\times c\times kd\times kh \times kw} KRoc×c×kd×kh×kw
c c c o c oc oc 的含义依然不变,并且依然是有多少个卷积核就有多少个输出通道 , h , k h h,kh hkh w , k w w,kw w,kw的含义也不变,只是多了 d , k d d,kd dkd维度,表示时序维度( d = d e p t h d=depth d=depth深度 ,代表时序维度), s d sd sd 表示在时序维度的卷积步长, p d pd pd 表示在图像时序维度前后的填充, d d dd dd 表示在卷积核时序维度前后的膨胀

卷积遍历时,现在第一个时序维度的第一行上从左向右移动,每次移动 s w sw sw 个单位,到行末后换到该行下的第 s h sh sh 行的开头继续移动,到该时序维度的图像末时,换到该时序维度后第 s d sd sd 的时序维度的第一行的开头继续移动,直至遍历完所有时序维度的图像

所以在三维卷积里 ,卷积核是四维的

现在我们把之前的一切都推广到三维意义下(对于函数,只是添加了它们的定义域,它们仍然可以作用于二维):

(1)我们把二维卷积运算符 ‘ ∗ * ’ ,推广到三维的意义

补充时序维度结果的计算公式:

o d = ⌊ d + 2 p d − ( ( k d − 1 ) ⋅ d d + 1 ) s d ⌋ + 1 od=\lfloor \cfrac{d+2pd-((kd-1)\cdot dd +1)}{sd}\rfloor+1 od=sdd+2pd((kd1)dd+1)+1

(2)输入图像和卷积核

我们令 d = k d = 1 d=kd=1 d=kd=1,(此时 s d sd sd 多少已经不重要了,因为总会遍历第一行并且只有一行)

E ( A ) ∈ R c × 1 × h × w , E ( K ) ∈ R o c × c × 1 × k h × k w ,   E ( O ) ∈ R o c × 1 × o h × o w E(A) \in R^{c \times 1 \times h \times w} , E(K) \in R^{oc \times c \times 1 \times kh \times kw},\ E(O) \in R^{oc \times 1 \times oh\times ow} E(A)Rc×1×h×w,E(K)Roc×c×1×kh×kw, E(O)Roc×1×oh×ow, ( E E E前面这里有定义)

(3) F = F l a t t e n : ( . . . , c , k d , k h , k w , . . . ) → ( . . . , ( c ⋅ k d ⋅ k h ⋅ k w ) , . . . ) F=Flatten:(...,c,kd,kh,kw,...) \rightarrow (...,(c\cdot kd \cdot kh \cdot kw),...) F=Flatten:(...,c,kd,kh,kw,...)(...,(ckdkhkw),...) , ( F − 1 F^{-1} F1是其逆运算)

因此 F ( E ( X ) ) = F ( X ) , F(E(X ))=F(X), F(E(X))=F(X), 其中 X X X是带通道二维图像

(4) M = M e r g e : ( . . . , o d , o h , o w , . . . . ) → ( . . . , ( o d ⋅ o h ⋅ o w ) , . . . ) M=Merge:(...,od,oh,ow,....)\rightarrow (...,(od \cdot oh \cdot ow),... ) M=Merge:(...,od,oh,ow,....)(...,(odohow),...) , ( M − 1 M^{-1} M1是其逆运算)

因此 M ( E ( X ) ) = M ( X ) , M(E(X ))=M(X), M(E(X))=M(X), 其中 X X X是带通道二维图像

我们把这些一切推广到三维的 符号和函数 都带入之前的公式,可以发现完全正确!从这里开始,直接给出结论:

E ( A ) ∗ E ( K ) = F ( K ) ⋅ M − 1 ( M ( S t a c k o d − 1 k = 0 [ S t a c k o h − 1 i = 0 [ S t a c k o w − 1 j = 0 [ F ( A ( k , i , j ) )   ]   ]   ] ) T )   = E ( O ) ∈ R o c × 1 × o h × o w E(A)*E(K)\\ =F(K) \cdot M^{-1} (M(\underset{k=0}{\overset{od-1}{Stack}}[\underset{i=0}{\overset{oh-1}{Stack}}[\underset{j=0}{\overset{ow-1}{Stack}}[ F(A(k,i,j))\ ]\ ]\ ])^T) \ \\=E(O) \in R^{oc \times 1 \times oh \times ow} E(A)E(K)=F(K)M1(M(k=0Stackod1[i=0Stackoh1[j=0Stackow1[F(A(k,i,j)) ] ] ])T) =E(O)Roc×1×oh×ow

A [ c h a n n e l , d e p , r o w , c o l ] = S t a c k o d − 1 k = 0 [ S t a c k o h − 1 i = 0 [ S t a c k o w − 1 j = 0 [ F ( A ( k , i , j ) )   ]   ]   ] A[channel,dep,row,col]=\underset{k=0}{\overset{od-1}{Stack}}[\underset{i=0}{\overset{oh-1}{Stack}}[\underset{j=0}{\overset{ow-1}{Stack}}[ F(A(k,i,j))\ ]\ ]\ ] A[channel,dep,row,col]=k=0Stackod1[i=0Stackoh1[j=0Stackow1[F(A(k,i,j)) ] ] ]

则上式简写为:

E ( A ) ∗ E ( K ) = F ( K ) ⋅ M − 1 ( M ( F ( A [ c h a n n e l , d e p , r o w , c o l ] ) ) T ) ∈ R o c × 1 × o h × o w E(A)*E(K)=F(K) \cdot M^{-1}(M(F(A[channel,dep,row,col]))^T) \in R^{oc \times 1 \times oh \times ow} E(A)E(K)=F(K)M1(M(F(A[channel,dep,row,col]))T)Roc×1×oh×ow

两边同时用 M M M 作用:

M ( A ∗ K ) = M ( E ( A ) ∗ E ( K ) ) = F ( K ) ⋅ M ( F ( A [ c h a n n e l , d e p , r o w , c o l ] ) ) T M(A*K)=M(E(A)*E(K))=F(K) \cdot M(F(A[channel,dep,row,col]))^T M(AK)=M(E(A)E(K))=F(K)M(F(A[channel,dep,row,col]))T

其中 F ( K ) ∈ R o c × ( c ⋅ 1 ⋅ k h ⋅ k w ) ,   M ( F ( A [ c h a n n e l , d e p , r o w , c o l ] ) ) T ∈ R ( c ⋅ 1 ⋅ k h ⋅ k w ) × ( 1 ⋅ o h ⋅ o w ) F(K) \in R^{oc \times (c \cdot 1 \cdot kh \cdot kw)}, \ M(F(A[channel,dep,row,col]))^T \in R^{(c \cdot 1 \cdot kh \cdot kw) \times (1 \cdot oh \cdot ow)} F(K)Roc×(c1khkw), M(F(A[channel,dep,row,col]))TR(c1khkw)×(1ohow)

有没有发现,因为 d e p dep dep只有一个取值,其实这个就是   ( Δ ) \ (\Delta)  (Δ) 式, 这意味着,我们完全可以从三维卷积的意义去理解   ( Δ ) \ (\Delta)  (Δ) 式和   ( ∇ ) \ (\nabla)  ()

这为我们优化至最终结果提供了重要的理论依据

先看   ( Δ ) \ (\Delta)  (Δ) 式:

M ( A ∗ K ) = F ( K ) ⋅ M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T      ( Δ ) M(A*K)=F(K) \cdot M(F(A[channel,row,col]))^T \ \ \ \ (\Delta) M(AK)=F(K)M(F(A[channel,row,col]))T    (Δ)

其中 F ( K ) ∈ R o c × ( c ⋅ k h ⋅ k w ) ,   M ( F ( A [ c h a n n e l , r o w , c o l ] ) ) T ∈ R ( c ⋅ k h ⋅ k w ) × ( 1 ⋅ o h ⋅ o w ) F(K) \in R^{oc \times (c \cdot kh \cdot kw)}, \ M(F(A[channel,row,col]))^T \in R^{(c \cdot kh \cdot kw) \times (1 \cdot oh \cdot ow)} F(K)Roc×(ckhkw), M(F(A[channel,row,col]))TR(ckhkw)×(1ohow)

我们清楚 o h oh oh o w ow ow维度分别表示卷积操作在 行( r o w row row h h h)和 列( c o l col col w w w)中的 步数,
这个很关键,所以很容易就能想到 ( 1 ⋅ o h ⋅ o w ) (1 \cdot oh \cdot ow) (1ohow) 中的 1 1 1表示卷积核在"时序"维度的步数是 1 1 1,

再看   ( ∇ ) \ (\nabla)  () 式:

F ( ∂ L ∂ K ) = M ( ∂ L ∂ O ) ⋅ F ( M ( A [ c h a n n e l , r o w , c o l ] ) )      ( ∇ ) F(\cfrac{\partial L}{\partial K})=M(\cfrac{\partial L}{\partial O}) \cdot F(M(A[channel,row,col])) \ \ \ \ (\nabla) F(KL)=M(OL)F(M(A[channel,row,col]))    ()

其中 M ( ∂ L ∂ O ) ∈ R o c × ( 1 × o h ⋅ o w ) , F ( M ( A [ c h a n n e l , r o w , c o l ] ) ) ∈ R ( 1 ⋅ o h ⋅ o w ) × ( c ⋅ k h ⋅ k w ) M(\cfrac{\partial L}{\partial O}) \in R^{oc \times (1 \times oh \cdot ow)} , F(M(A[channel,row,col])) \in R^{(1 \cdot oh \cdot ow) \times (c\cdot kh \cdot kw)} M(OL)Roc×(1×ohow),F(M(A[channel,row,col]))R(1ohow)×(ckhkw)

我们要做的就是1.找到卷积核和被卷的内容 2.确定卷积三个方向的步长

[注意]以下所有的 d = k d = o d = s d = 1 d=kd=od=sd=1 d=kd=od=sd=1,不单独写出了

为此,我们先考虑是否能将矩阵乘法操作转换成卷积操作,只需从相反方向思考就行了,这比从卷积转换成矩阵乘法更简单!
观察   ( ∇ ) \ (\nabla)  ()式矩阵乘法作用维度,我们可以看成是 o c oc oc 个形状为 R 1 × o h × o w R^{1 \times oh \times ow} R1×oh×ow的卷积核去卷 c ⋅ k h ⋅ k w c \cdot kh \cdot kw ckhkw 个形状为 R 1 × o h × o w R^{1 \times oh \times ow} R1×oh×ow的图像,这仍然是二维卷积的理解方式,并且其实这并不是一次卷积操作就能完成的,事实上这需要 c ⋅ k h ⋅ k w c \cdot kh \cdot kw ckhkw次卷积操作才能完成,

这更加确定了我们只有从三维卷积的方式去理解才可能转换成一次卷积操作

为此我们先看看三维卷积的形式:

A ′ ∗ K ′ = O ′ A' * K'=O' AK=O

其中 A ′ ∈ R c × d × h × w , K ′ ∈ R o c × c × k d × k h × k w , O ′ ∈ R o c × o d × o h × o w A' \in R^{c\times d \times h \times w}, K' \in R^{oc \times c \times kd \times kh\times kw}, O' \in R^{oc \times od \times oh \times ow} ARc×d×h×w,KRoc×c×kd×kh×kw,ORoc×od×oh×ow
o d = ⌊ d − k d s d ⌋ + 1 od=\lfloor \cfrac{d-kd}{sd} \rfloor+1 od=sddkd+1
o h = ⌊ h − k h s h ⌋ + 1 oh=\lfloor \cfrac{h-kh}{sh} \rfloor+1 oh=shhkh+1
o w = ⌊ w − k w s w ⌋ + 1 ow=\lfloor \cfrac{w-kw}{sw} \rfloor+1 ow=swwkw+1 (我们此时不必考虑 P a d Pad Pad D i l a t e Dilate Dilate,原因前面已说明)

我们类比一下   ( Δ ) \ (\Delta)  (Δ)式就可以很轻松地确定卷积核是 P ( E ( ∂ L ∂ O ) ) ∈ R o c × 1 × 1 × o h ⋅ o w P(E(\cfrac{\partial L}{\partial O})) \in R^{oc \times 1 \times 1 \times oh \cdot ow} P(E(OL))Roc×1×1×ohow, 其中 o c oc oc 仍然为卷积核的个数,卷积核的形状为 R 1 × 1 × o h × o w R^{1 \times 1 \times oh \times ow} R1×1×oh×ow,

被卷的东西是 P ( A ) ∈ R 1 × c × h × w P(A) \in R^{1 \times c \times h \times w} P(A)R1×c×h×w【注意这里面 1 1 1为通道维度, c c c 为时序维度,回顾一下 P P P的定义!】

卷积膨胀为 ( d d = 1 , d h = s h , d w = s w ) (dd=1,dh=sh,dw=sw) (dd=1,dh=sh,dw=sw)【这里BP的膨胀和FP时的步长是对应的! !】

卷积步长为 ( s d = 1 , s h = 1 , s w = 1 ) (sd=1,sh=1,sw=1) (sd=1,sh=1,sw=1)

但需要注意一个非常非常重要的细节:卷积步长不一定整除图像高宽,因此有一部分图像是可能没有进行卷积操作的,这是我们在定义卷积操作时定义的!!!但实际上“更准确”的卷积定义不应该出现这种不整除的现象 ! ! !

但需要注意一个非常非常重要的细节:卷积步长不一定整除图像高宽,因此有一部分图像是可能没有进行卷积操作的,这是我们在定义卷积操作时定义的!!!但实际上“更准确”的卷积定义不应该出现这种不整除的现象 ! ! !
重要的事情说两遍

具体地:

图像下端 ( h − k h ) % s h (h-kh)\%sh (hkh)%sh 的部分在卷积运算中将会被 “剪掉”,
图像右端 ( w − k w ) % s w (w-kw)\%sw (wkw)%sw的部分将会被 “剪掉

而我们在反向传播时空洞卷积的步长为1,意味着它可以卷积到图像的所有部分,而它并不应该访问到前向转播中被“剪掉”的部分

所以我们应该定义一个 C u t 函数 Cut函数 Cut函数,用来减掉图像多余的部分, C u t Cut Cut 函数和卷积核与步长有关,参数有点多,
因此 (为了简化写法我们就不写下角标了):


C u t ( A ′ ) ∈ R c × ( d − ( d − k d ) % s d ) × ( h − ( h − k h ) % s h ) × ( w − ( w − k w ) % s w ) Cut(A') \in R^{c\times (d-(d-kd)\%sd) \times (h-(h-kh)\%sh) \times (w-(w-kw)\%sw)} Cut(A)Rc×(d(dkd)%sd)×(h(hkh)%sh)×(w(wkw)%sw)

于是我们将结果写为(注意此时 ‘*’ 为三维意义下的卷积操作,并且此后必须要求“整除”):

∂ L ∂ K = C u t ( P ( A ) ) ∗ D i l a t e 1 × s h × s w ( P ( E ( ∂ L ∂ O ) ) ) \cfrac{\partial L}{\partial K}=Cut(P(A)) * Dilate_{1 \times sh \times sw}(P(E(\cfrac{\partial L}{\partial O}))) KL=Cut(P(A))Dilate1×sh×sw(P(E(OL)))

由于卷积操作有维度、步长参数,我们不妨把 ∗ * 运算加入这些参数,统一前向传播和反向转播的形式:

< ∗ s d × s h × s w > <*_{sd \times sh \times sw} > <sd×sh×sw> 表示卷积步长为   ( s d , s h , s w ) \ (sd,sh,sw)  (sd,sh,sw) 的卷积的操作
那么:

E ( O ) = C u t ( E ( A ) )   < ∗ 1 , s h , s w >   E ( K ) E(O)=Cut(E(A)) \ <*_{1,sh,sw}> \ E(K) E(O)=Cut(E(A)) <1,sh,sw> E(K)

∂ L ∂ K = C u t ( P ( A ) )    < ∗ 1 × 1 × 1 >    D i l a t e 1 × s h × s w ( P ( E ( ∂ L ∂ O ) ) ) \cfrac{\partial L}{\partial K}=Cut(P(A))\ \ <*_{1\times 1\times 1} >\ \ Dilate_{1\times sh \times sw}(P(E(\cfrac{\partial L}{\partial O}))) KL=Cut(P(A))  <1×1×1>  Dilate1×sh×sw(P(E(OL)))

别忘了我们还没在前向传播加入 P a d Pad Pad D i l a t e Dilate Dilate , 那么有(注意, C u t Cut Cut P a d Pad Pad 不能交换, E , P E,P E,P P a d Pad Pad,以及 E , P E,P E,P D i l a t e Dilate Dilate都可以交换,因为E,P只是加了维度,并没有复制和改变任何东西):

E ( O ) = C u t ( E ( P a d p h × p w ( A ) ) )    < ∗ 1 × s h × s w >    E ( D i l a t e d h × d w ( K ) ) E(O)=Cut(E(Pad_{ ph \times pw}(A)))\ \ <*_{1\times sh\times sw}>\ \ E(Dilate_{dh\times dw}(K)) E(O)=Cut(E(Padph×pw(A)))  <1×sh×sw>  E(Dilatedh×dw(K))
【注意】此时的 O O O和之前的不一样了!但是 A , K A,K A,K仍然没有变

∂ L ∂ D i l a t e d h × d w ( K ) = C u t ( P ( P a d p h × p w ( A ) ) )    < ∗ 1 × 1 × 1 >    P ( E ( D i l a t e s h × s w ( ∂ L ∂ O ) ) ) \cfrac{\partial L}{\partial Dilate_{dh\times dw}(K)}=Cut(P(Pad_{ph \times pw}(A)))\ \ <*_{1\times 1\times 1}> \ \ P(E(Dilate_{sh \times sw}(\cfrac{\partial L}{\partial O}))) Dilatedh×dw(K)L=Cut(P(Padph×pw(A)))  <1×1×1>  P(E(Dilatesh×sw(OL)))

然后因为 L L L 是标量,直接把 D i l a t e Dilate Dilate 提到外面,再用逆函数作用一下就ok了,

我们得到BP公式的终极形式:

∂ L ∂ K = D i l a t e d h × d w − 1 ( C u t ( P ( P a d p h × p w ( A ) ) )    < ∗ 1 × 1 × 1 >    P ( E ( D i l a t e s h × s w ( ∂ L ∂ O ) ) ) ) \cfrac{\partial L}{\partial K}= Dilate_{dh\times dw}^{-1}(Cut(P(Pad_{ph \times pw}(A)))\ \ <*_{1\times 1\times 1}> \ \ P(E(Dilate_{sh \times sw}(\cfrac{\partial L}{\partial O})))) KL=Dilatedh×dw1(Cut(P(Padph×pw(A)))  <1×1×1>  P(E(Dilatesh×sw(OL))))

上面的形式虽然看起来复杂,但是它以最简单的形式涵盖了二维卷积操作中的所有主要参数和所有情况!!!


(3)形状上进行验证

我们不妨利用卷积步数计算公式来从形状上验证一下这个式子:
先给出所有输入的形状:
E ( A ) ∈ R c × 1 × h × w E(A) \in R^{c \times 1\times h \times w} E(A)Rc×1×h×w

E ( K ) ∈ R o c × c × 1 × o h × o w E(K) \in R^{oc \times c \times 1\times oh \times ow} E(K)Roc×c×1×oh×ow

s d = d = 1 , sd=d=1, sd=d=1,

故(前向传播):

E ( P a d p h × p w ( A ) ) ∈ R c × 1 × ( h + 2 p h ) × ( w + 2 p w ) E(Pad_{ph \times pw}(A)) \in R^{c \times1\times (h+2ph)\times (w+2pw)} E(Padph×pw(A))Rc×1×(h+2ph)×(w+2pw)

E ( D i l a t e d h × d w ( K ) ) ∈ R o c × c × 1 × ( ( k h − 1 ) ⋅ d h + 1 ) × ( ( k w − 1 ) ⋅ d w + 1 ) E(Dilate_{dh \times dw}(K)) \in R^{oc \times c \times 1 \times ((kh-1)\cdot dh+1) \times ((kw-1)\cdot dw+1)} E(Dilatedh×dw(K))Roc×c×1×((kh1)dh+1)×((kw1)dw+1)

下面两个 C u t Cut Cut 操作都是针对前向传播的,卷积核都是 E ( D i l a t e d h × d w ( K ) ) E(Dilate_{dh \times dw}(K)) E(Dilatedh×dw(K))

C u t ( E ( P a d p h × p w ( A ) ) ) ∈ R c × 1 × [ h + 2 p h − ( h + 2 p h − ( ( k h − 1 ) ⋅ d h + 1 ) ) % s h ]   × [ w + 2 p w − ( w + 2 p w − ( ( k w − 1 ) ⋅ d w + 1 ) ) % s w ] Cut(E(Pad_{ph \times pw}(A)) ) \in R^{c \times1\times [h+2ph-(h+2ph-((kh-1)\cdot dh+1))\%sh]\ \times [w+2pw-(w+2pw-((kw-1)\cdot dw+1))\%sw]} Cut(E(Padph×pw(A)))Rc×1×[h+2ph(h+2ph((kh1)dh+1))%sh] ×[w+2pw(w+2pw((kw1)dw+1))%sw]

C u t ( P ( P a d p h × p w ( A ) ) ) ∈ R 1 × c × [ h + 2 p h − ( h + 2 p h − ( ( k h − 1 ) ⋅ d h + 1 ) ) % s h ]   × [ w + 2 p w − ( w + 2 p w − ( ( k w − 1 ) ⋅ d w + 1 ) ) % s w ] Cut(P(Pad_{ph \times pw}(A)) ) \in R^{1 \times c \times [h+2ph-(h+2ph-((kh-1)\cdot dh+1))\%sh]\ \times [w+2pw-(w+2pw-((kw-1)\cdot dw+1))\%sw]} Cut(P(Padph×pw(A)))R1×c×[h+2ph(h+2ph((kh1)dh+1))%sh] ×[w+2pw(w+2pw((kw1)dw+1))%sw]

计算前向转播输出形状:

o d = ⌊ 1 − 1 1 ⌋ + 1 = 1 od=\lfloor \cfrac{1-1}{1} \rfloor+1=1 od=111+1=1
o h = ⌊ [ h + 2 p h − ( h + 2 p h − ( ( k h − 1 ) ⋅ d h + 1 ) ) % s h − ( ( k h − 1 ) ⋅ d h + 1 ) ] s h ⌋ + 1 = ⌊ ( h + 2 p h − ( ( k h − 1 ) ⋅ d h + 1 ) ) − ( h + 2 p h − ( ( k h − 1 ) ⋅ d h + 1 ) ) % s h s h ⌋ + 1 = ⌊ h + 2 p h − ( ( k h − 1 ) ⋅ d h + 1 ) s h ⌋ + 1 oh=\lfloor \cfrac{[h+2ph-(h+2ph-((kh-1)\cdot dh+1))\%sh-((kh-1)\cdot dh+1)]}{sh}\rfloor+1 \\=\lfloor \cfrac{(h+2ph-((kh-1)\cdot dh+1))-(h+2ph-((kh-1)\cdot dh+1))\%sh}{sh}\rfloor+1 \\=\lfloor \cfrac{h+2ph-((kh-1)\cdot dh+1)}{sh}\rfloor+1 oh=sh[h+2ph(h+2ph((kh1)dh+1))%sh((kh1)dh+1)]+1=sh(h+2ph((kh1)dh+1))(h+2ph((kh1)dh+1))%sh+1=shh+2ph((kh1)dh+1)+1

同理:
o w = ⌊ w + 2 p w − ( ( k w − 1 ) ⋅ d w + 1 ) s w ⌋ + 1 ow=\lfloor \cfrac{w+2pw-((kw-1)\cdot dw+1)}{sw}\rfloor+1 ow=sww+2pw((kw1)dw+1)+1

有:

E ( O ) ∈ R o c × 1 × o h × o w ,   P ( E ( ∂ L ∂ O ) ) ∈ R o c × 1 × 1 × o h × o w E(O) \in R^{oc \times 1 \times oh \times ow}, \ P(E(\cfrac{\partial L}{\partial O})) \in R^{oc \times 1\times 1 \times oh \times ow} E(O)Roc×1×oh×ow, P(E(OL))Roc×1×1×oh×ow

P ( E ( D i l a t e s h × s w ( ∂ L ∂ O ) ) ) ∈ R o c × 1 × 1 × ( ( o h − 1 ) ⋅ s h + 1 ) × ( ( o w − 1 ) ⋅ s w + 1 ) P(E(Dilate_{sh \times sw}(\cfrac{\partial L}{\partial O}))) \in R^{oc \times 1\times1 \times ((oh-1)\cdot sh+1) \times ((ow-1)\cdot sw+1)} P(E(Dilatesh×sw(OL)))Roc×1×1×((oh1)sh+1)×((ow1)sw+1)

我们用 B P _ o c ,   B P _ o d ,   B P _ o h ,   B P _ o w BP\_oc,\ BP\_od,\ BP\_oh,\ BP\_ow BP_oc, BP_od, BP_oh, BP_ow 来表示反向传播卷积操作:

(令) C o n v O u t = C u t ( P ( P a d p h × p w ( A ) ) )    < ∗ 1 × 1 × 1 >    P ( E ( D i l a t e s h × s w ( ∂ L ∂ O ) ) ) ConvOut=Cut(P(Pad_{ph \times pw}(A)))\ \ <*_{1\times 1\times 1}> \ \ P(E(Dilate_{sh \times sw}(\cfrac{\partial L}{\partial O}))) ConvOut=Cut(P(Padph×pw(A)))  <1×1×1>  P(E(Dilatesh×sw(OL)))

的输出形状,则:

B P _ o c = o c BP\_oc=oc BP_oc=oc

B P _ o d = ⌊ c − 1 1 ⌋ + 1 = c BP\_od=\lfloor \cfrac{c-1}{1}\rfloor+1=c BP_od=1c1+1=c

B P _ o h BP\_oh BP_oh

= ⌊ [ h + 2 p h − ( h + 2 p h − ( ( k h − 1 ) ⋅ d h + 1 ) ) % s h ] − ( ( o h − 1 ) ⋅ s h + 1 ) 1 ⌋ + 1 =\lfloor \cfrac{[h+2ph-(h+2ph-((kh-1)\cdot dh+1))\%sh]-((oh-1)\cdot sh+1)}{1}\rfloor+1 =1[h+2ph(h+2ph((kh1)dh+1))%sh]((oh1)sh+1)+1

= [ h + 2 p h − ( h + 2 p h − ( ( k h − 1 ) ⋅ d h + 1 ) ) % s h ] − ( o h − 1 ) ⋅ s h =[h+2ph-(h+2ph-((kh-1)\cdot dh+1))\%sh]-(oh-1)\cdot sh =[h+2ph(h+2ph((kh1)dh+1))%sh](oh1)sh

= [ h + 2 p h − ( h + 2 p h − ( ( k h − 1 ) ⋅ d h + 1 ) ) % s h ] − ⌊ h + 2 p h − ( ( k h − 1 ) ⋅ d h + 1 ) s h ⌋ ⋅ s h =[h+2ph-(h+2ph-((kh-1)\cdot dh+1))\%sh]-\lfloor \cfrac{h+2ph-((kh-1)\cdot dh+1)}{sh}\rfloor\cdot sh =[h+2ph(h+2ph((kh1)dh+1))%sh]shh+2ph((kh1)dh+1)sh

= ( k h − 1 ) ⋅ d h + 1 =(kh-1)\cdot dh+1 =(kh1)dh+1

同理:

B P _ o w = ( k w − 1 ) ⋅ d w + 1 BP\_ow=(kw-1)\cdot dw+1 BP_ow=(kw1)dw+1

于是:

C o n v O u t ∈ R o c × c × ( ( k h − 1 ) ⋅ d h + 1 ) × ( ( k w − 1 ) ⋅ d w + 1 ) ConvOut \in R^{oc\times c \times ((kh-1)\cdot dh+1) \times ((kw-1)\cdot dw+1)} ConvOutRoc×c×((kh1)dh+1)×((kw1)dw+1)

而最后一步:

D i l a t e d h × d w − 1 ( C o n v O u t ) ∈ R o c × c × k h × k w Dilate_{dh\times dw}^{-1}(ConvOut) \in R^{oc \times c \times kh \times kw} Dilatedh×dw1(ConvOut)Roc×c×kh×kw

恰好是 o c oc oc 个卷积核的形状! ! !

这印证了我们的推导是没有问题的。

最后我们再以终极的数学三维卷积形式给出二维卷积 前向传播、反向传播 的这两个公式:
---------

E − 1 ( C u t ( E ( P a d p h × p w ( A ) ) )    < ∗ 1 × s h × s w >    E ( D i l a t e d h × d w ( K ) ) ) = O E^{-1}(Cut(E(Pad_{ ph \times pw}(A)))\ \ <*_{1\times sh\times sw}>\ \ E(Dilate_{dh\times dw}(K)))=O E1(Cut(E(Padph×pw(A)))  <1×sh×sw>  E(Dilatedh×dw(K)))=O

∂ L ∂ K = D i l a t e d h × d w − 1 ( C u t ( P ( P a d p h × p w ( A ) ) )    < ∗ 1 × 1 × 1 >    P ( E ( D i l a t e s h × s w ( ∂ L ∂ O ) ) ) ) \cfrac{\partial L}{\partial K}= Dilate_{dh\times dw}^{-1}(Cut(P(Pad_{ph \times pw}(A)))\ \ <*_{1\times 1\times 1}> \ \ P(E(Dilate_{sh \times sw}(\cfrac{\partial L}{\partial O})))) KL=Dilatedh×dw1(Cut(P(Padph×pw(A)))  <1×1×1>  P(E(Dilatesh×sw(OL))))

---------

这式子也太复杂了!

但它至少很全面

所以到这里,插一段:

(4)对特殊情况进行验证

我发现很多篇文章比如本篇开头那篇引用的博客,以及这篇文章,等等等等,很多点赞收藏比较多的文章 对于卷积核参数的求导,给出了这个式子:

∂ J ∂ W l = a l − 1 ∗ δ l \cfrac{\partial J}{\partial W^l}=a^{l-1} * \delta^l WlJ=al1δl (我们不考虑激活层,即假设前向传播里 W l W^l Wl没有激活,就算激活也无非就是多一个导数的哈达玛乘积,而我们想更专注于卷积层的BP,因此就不写出来了)

其实这里的 J ,   W l ,   a l − 1 ,   δ l J,\ W^{l},\ a^{l-1}, \ \delta^l J, Wl, al1, δl 分别就是本篇的 L ,   K ,   A ,   ∂ L ∂ O L,\ K,\ A,\ \cfrac{\partial L}{\partial O} L, K, A, OL,

然而这个式子并没有包含多通道,更没有考虑图像填充,卷积核膨胀,卷积步长 等必要操作

不过我们可以通过对我们的公式取特殊情况,来验证上面公式 在这个特殊情况下是正确的:

p h = p w = 0 , d h = d w = 1 , s h = s w = 1 ph=pw=0, dh=dw=1,sh=sw=1 ph=pw=0,dh=dw=1,sh=sw=1 且此时 A A A 为单通道图, K i K_i Ki 为单个卷积核,则有:

∂ L ∂ K = D i l a t e 1 × 1 − 1 ( C u t ( P ( P a d 0 × 0 ( A ) ) )    < ∗ 1 × 1 × 1 >    P ( E ( D i l a t e 1 × 1 ( ∂ L ∂ O ) ) ) ) \cfrac{\partial L}{\partial K}= Dilate_{1\times 1}^{-1}(Cut(P(Pad_{0 \times 0}(A)))\ \ <*_{1\times 1\times 1}> \ \ P(E(Dilate_{1 \times 1}(\cfrac{\partial L}{\partial O})))) KL=Dilate1×11(Cut(P(Pad0×0(A)))  <1×1×1>  P(E(Dilate1×1(OL))))

= C u t ( P ( A ) ) < ∗ 1 × 1 × 1 > P ( E ( ∂ L ∂ O ) ) =Cut(P(A))<*_{1\times 1 \times 1}> P(E(\cfrac{\partial L}{\partial O})) =Cut(P(A))<1×1×1>P(E(OL))【步长为1时,BP不存在空洞卷积】

= P ( A ) < ∗ 1 × 1 × 1 > P ( E ( ∂ L ∂ O ) ) =P(A)<*_{1\times 1 \times 1}> P(E(\cfrac{\partial L}{\partial O})) =P(A)<1×1×1>P(E(OL))【步长为1的卷积不存在“裁剪”的情况】

于是 ∂ L ∂ K i = A < ∗ 1 × 1 > ∂ L ∂ O 于是 \cfrac{\partial L}{\partial K_i}=A <*_{1\times 1}> \cfrac{\partial L}{\partial O} 于是KiL=A<1×1>OL【因为 A A A是单通的并且只有一个卷积核,所以前两个维度都是1,直接消掉】

                  = A    ∗   ∂ L ∂ O _\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =A\ \ * \ \cfrac{\partial L}{\partial O}                 =A   OL ,完全一致!

可以发现之所以这个式子可以用二维卷积表示反向传播的导数,是因为:
1.卷积步长是1, 所以可以消掉内层 D i l a t e Dilate Dilate
2.卷积膨胀是1(普通卷积,非空洞卷积),所以可以消掉外层 D i l a t e Dilate Dilate
3.图像填充是0 (没有图像填充),所以可以消掉 P a d Pad Pad
4.由于卷积步长是1,所以图像的每个地方都可以被卷积核访问到,所以可以消掉 C u t Cut Cut
5.输出图像是单通道的(只有一个卷积核),所以可以化三维为二维

先不说其它要点,在绝大多数情况下,图像都不是单通道的。

由此可见,上面那个公式忽略了很多重要的信息

我们现在终于完成了对卷积核参数的求导的推导和深入理解。

接下来我们进行最最最最重要的部分——————


4.反向传播-------误差对上一个图像层求导

[但是写不下了…系统让我分成几篇进行发布…]
在这里插入图片描述

hhhhhh

【更新与勘误】

2023.10.7 :修改了适用于编程的公式的位置,在这里,因为torch和numpy都不能计算当矩阵乘法里的第二个矩阵维度超过2的矩阵乘法,因此对于编程而言,不能忽略 F , F − 1 F,F^{-1} F,F1

2023.10.8 :更新了目录缩进

欢迎交流…

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
CNN卷积神经网络)是一种常用的深度学习模型,用于图像识别、目标检测等任务。而反向传播CNN中用于训练网络的关键步骤之一。 反向传播(Backpropagation)是指通过计算误差(即预测值与真实值的差异)来调整神经网络的权重和偏置,以提高模型的预测准确度。在CNN中,反向传播的实现主要包括两个步骤:前向传播和反向传播。 首先,进行前向传播。首先将输入数据通过卷积层进行卷积运算,提取出图像的特征。然后,通过激活函数(如ReLU)来引入非线性。接下来,利用池化层来减小特征图的尺寸,并保留更显著的特征。最后,将处理后的特征输入到全连接层中,进行分类或回归等任务的预测。 其次,进行反向传播。首先,计算预测值与真实值之间的误差。然后,通过链式法则,将误差从输出层向输入层反向传播,并更新每个连接权重和偏置的数值。这样,网络中每个神经元的梯度都可以通过反向传播得到,从而调整网络参数,使其逐渐逼近真实值。此过程可以利用梯度下降等优化算法来完成。 具体地讲,反向传播过程主要分为四个步骤:计算损失函数对输出层的输入的偏导数、计算损失函数对输出层的权重的偏导数、计算损失函数对输入层的加权和的偏导数、计算损失函数对输入图像的偏导数。通过不断迭代这四个步骤,不断更新参数,从而提高网络的训练效果。 综上所述,CNN中的反向传播通过计算误差来调整网络的权重和偏置,以提高模型的准确度。这个过程主要包括前向传播和反向传播两个步骤,通过不断地更新参数,使得网络逐渐逼近真实值,从而达到优化模型的目的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值