简介

一些关于卷积的笔记

从MLP到CNN

网络结构

Figure1

图1所示,一个卷积神经网络由若干卷积层Pooling层全连接层组成。你可以构建各种不同的卷积神经网络,它的常用架构模式为:

1
INPUT -> [[CONV]*N -> POOL?]*M -> [FC]*K

也就是N个卷积层叠加,然后(可选)叠加一个Pooling层,重复这个结构M次,最后叠加K个全连接层。

对于图1展示的卷积神经网络:

1
INPUT -> CONV -> POOL -> CONV -> POOL -> FC -> FC

按照上述模式可以表示为:

1
INPUT -> [[CONV]*1 -> POOL]*2 -> [FC]*2

也就是:N=1, M=2, K=2

三维的层结构

图1我们可以发现卷积神经网络的层结构和全连接神经网络的层结构有很大不同。全连接神经网络每层的神经元是按照一维排列的,也就是排成一条线的样子;而卷积神经网络每层的神经元是按照三维排列的,也就是排成一个长方体的样子,有宽度高度深度

对于图1展示的神经网络,我们看到输入层的宽度和高度对应于输入图像的宽度和高度,而它的深度为1。接着,第一个卷积层对这幅图像进行了卷积操作(后面我们会讲如何计算卷积),得到了三个Feature Map。这里的"3"可能是让很多初学者迷惑的地方,实际上,就是这个卷积层包含三个Filter,也就是三套参数,每个Filter都可以把原始输入图像卷积得到一个Feature Map,三个Filter就可以得到三个Feature Map。至于一个卷积层可以有多少个Filter,那是可以自由设定的。也就是说,卷积层的Filter个数也是一个超参数。我们可以把Feature Map可以看做是通过卷积变换提取到的图像特征,三个Filter就对原始图像提取出三组不同的特征,也就是得到了三个Feature Map,也称做三个通道(channel)

继续观察图1,在第一个卷积层之后,Pooling层对三个Feature Map做了下采样(后面我们会讲如何计算下采样),得到了三个更小的Feature Map。接着,是第二个卷积层,它有5个Filter。每个Fitler都把前面下采样之后的3个**Feature Map卷积在一起,得到一个新的Feature Map。这样,5个Filter就得到了5个Feature Map。接着,是第二个Pooling,继续对5个Feature Map进行下采样**,得到了5个更小的Feature Map。

图1所示网络的最后两层是全连接层。第一个全连接层的每个神经元,和上一层5个Feature Map中的每个神经元相连,第二个全连接层(也就是输出层)的每个神经元,则和第一个全连接层的每个神经元相连,这样得到了整个网络的输出。

Forward计算

假设有一个5×55\times5的图像,使用一个3×33\times3的filter进行卷积,想得到一个3×33\times3的Feature Map,如下所示:

5-2256672-318017ad134effc5
符号 说明 符号 说明
xi,jx_{i,j} Image第 ii 行第 jj 列元素 wm,nw_{m,n} Filter第 mm 行第 nn 列权重
ai,ja_{i,j} Feature Map的第 ii 行第 jj 列元素 wbw_b Filter的偏置项
f()f(\cdot) 激活函数, 本例ff为relu函数

使用下列公式计算卷积:

ai,j=f(m=02n=02wm,nxi+m,j+n+wb)a_{i,j}=f(\sum_{m=0}^{2}\sum_{n=0}^{2}w_{m,n}x_{i+m,j+n}+w_b)

对于Feature Map左上角元素a0,0a_{0,0}来说,其卷积计算方法为:

a0,0=f(m=02n=02wm,nxm+0,n+0+wb)=relu(w0,0x0,0+w0,1x0,1+w0,2x0,2+w1,0x1,0+w1,1x1,1+w1,2x1,2+w2,0x2,0+w2,1x2,1+w2,2x2,2+wb)=relu(1+0+1+0+1+0+0+0+1+0)=relu(4)=4\begin{align} a_{0,0}&=f(\sum_{m=0}^{2}\sum_{n=0}^{2}w_{m,n}x_{m+0,n+0}+w_b)\\ &={\rm relu}\left( \begin{array}{l} w_{0,0}x_{0,0}+w_{0,1}x_{0,1}+w_{0,2}x_{0,2}+\\ w_{1,0}x_{1,0}+w_{1,1}x_{1,1}+w_{1,2}x_{1,2}+\\ w_{2,0}x_{2,0}+w_{2,1}x_{2,1}+w_{2,2}x_{2,2}+w_b \end{array} \right) \\ &={\rm relu}\left( \begin{array}{l} 1+0+1+\\ 0+1+0+\\ 0+0+1+0 \end{array} \right)\\ &={\rm relu}(4)\\ &=4 \end{align}

a00

接下来,Feature Map的元素a0,1a_{0,1}的卷积计算方法为:

a0,0=f(m=02n=02wm,nxm+0,n+1+wb)=relu(w0,0x0,1+w0,1x0,2+w0,2x0,3+w1,0x1,1+w1,1x1,2+w1,2x1,3+w2,0x2,1+w2,1x2,2+w2,2x2,3+wb)=relu(1+0+0+0+1+0+0+0+1+0)=relu(3)=3\begin{align} a_{0,0}&=f(\sum_{m=0}^{2}\sum_{n=0}^{2}w_{m,n}x_{m+0,n+1}+w_b)\\ &={\rm relu}\left( \begin{array}{l} w_{0,0}x_{0,1}+w_{0,1}x_{0,2}+w_{0,2}x_{0,3}+\\ w_{1,0}x_{1,1}+w_{1,1}x_{1,2}+w_{1,2}x_{1,3}+\\ w_{2,0}x_{2,1}+w_{2,1}x_{2,2}+w_{2,2}x_{2,3}+w_b \end{array} \right) \\ &={\rm relu}\left( \begin{array}{l} 1+0+0+\\ 0+1+0+\\ 0+0+1+0 \end{array} \right)\\ &={\rm relu}(3)\\ &=3 \end{align}

a01

可以依次计算出Feature Map中所有元素的值。下面的动画显示了整个Feature Map的计算过程:

8-2256672-19110dee0c54c0b2

步幅

上面的计算中, 步幅(Stride)为1, 步幅可以设为大于1的数, 例如, 当步幅为2时, Feature Map计算如下:

9-2256672-273e3d9cf9dececb 10-2256672-7f362ea9350761d9 11-2256672-f5fa1e904cb0287e 12-2256672-7919cabd375b4cfd

Feature Map的WF×HFW_F\times H_F 由下面式子计算

WF=(WIWK+2P)/S+1HF=(HIHK+2P)/S+1\begin{align} W_F &= (W_I - W_K + 2P)/S + 1\\ H_F &= (H_I - H_K + 2P)/S + 1 \end{align}

输入图像 输出图像 Kernel大小 步幅 Padding
WI×HIW_I\times H_I WF×HFW_F\times H_F WK×HKW_K\times H_K SS PP

Zero Padding 是指在原始图像周围补几圈0, 如果P是1,那么就补1圈0

深度(通道数)

卷积前的图像深度为D,那么相应的filter的深度也必须为D。我们扩展一下式1,得到了深度大于1的卷积计算公式:

ai,j=f(d=0D1m=0F1n=0F1wd,m,nxd,i+m,j+n+wb)(4)a_{i,j}=f(\sum_{d=0}^{D-1}\sum_{m=0}^{F-1}\sum_{n=0}^{F-1}w_{d,m,n}x_{d,i+m,j+n}+w_b)\qquad(式4)

DD是深度, FF是卷积核大小

注意, 输入图像的深度是D, 卷积核的深度也对应是D, 但是1个卷积核的输出只有1层. 例如下图中演示的输入是深度为2的图像, 对应的卷积核深度也是2, 最后输出深度为1的图像

image-20230308111916961

多个卷积核

一个卷积核对应一层输出, 多个卷积核对应多层输出, 卷积后Feature Map的深度和卷积核的个数是相同的.

image-20230308160731614

卷积

数学中的卷积

对于函数f:RnRf:\R^n\rightarrow\Rg:RnRg:\R^n\rightarrow\R, 定义 ffgg 的卷积如下

(fg)(x)=f(t)g(xt)dt(f * g)(\bold{x}) =\int f(t)g(\bold{x}-t)dt

对于离散情况有

(fg)(n)=kf(k)g(nk)(f*g)(n) = \sum_{k}f(k)g(n-k)

对于二维张量有

(fg)(i,j)=mnf(m,n)g(im,jn)(f*g)(i,j) = \sum_{m}\sum_{n} f(m,n)g(i-m,j-n)

CNN中的卷积

CNN中的卷积在数学中叫做互相关(cross-correlation)

对于函数f:RnRf:\R^n\rightarrow\Rg:RnRg:\R^n\rightarrow\R, 定义 ffgg 的互相关函数如下

(fg)(x)=f(t)g(x+t)dt(f \star g)(\bold{x}) =\int f(t)g(\bold{x}+t)dt

对于离散情况有

(fg)(n)=kf(k)g(n+k)(f\star g)(n) = \sum_{k}f(k)g(n+k)

对于二维张量有

(fg)(i,j)=mnf(m,n)g(i+m,j+n)(f\star g)(i,j) = \sum_{m}\sum_{n} f(m,n)g(i+m,j+n)

与CNN的卷积对应, 上式中 ff 对应于卷积核(filter), gg 对应于输入图像.

Pooling

Pooling(池化)的主要作用是下采样, 通过去掉Feature Map中不重要的样本, 进一步减少参数数量. Pooling的方法很多, 常用的有 Max Pooling, Mean Pooling

Max Pooling

与卷积层类似,Pooling运算符由⼀个固定形状的窗⼝组成,该窗⼝根据其步幅⼤⼩在输⼊的所有区域上滑动, 为固定形状窗⼝(有时称为汇聚窗⼝)遍历的每个位置计算⼀个输出。

ai,j=max{xi+0,j+0,xi+0,j+1,,xi+0,j+N,xi+1,j+0,xi+1,j+1,,xi+1,j+N,xi+M,j+0,xi+M,j+1,,xi+M,j+N}a_{i,j} = \max\left\{ \begin{array}{llll} x_{i+0,j+0},&x_{i+0,j+1},&\cdots,&x_{i+0,j+N},\\ x_{i+1,j+0},&x_{i+1,j+1},&\cdots,&x_{i+1,j+N},\\ \vdots&\vdots&\ddots&\vdots\\ x_{i+M,j+0},&x_{i+M,j+1},&\cdots,&x_{i+M,j+N} \end{array} \right\}

其中 M×NM\times N 是固定窗口的大小

Note: 与卷积(互相关)操作不同的是, 池化操作是对Feature Maps的每一层分别进行池化, 如果Feature Maps有n层, 那么池化得到的结果也是n层.

例如在下图中, 输入是一个单层的4×44\times4的图像, 经过窗口大小为2×22\times2, 步长为22的池化操作后得到一个单层的输出.

Max Pooling

池化操作的输入和输出的大小也满足前面卷积(互相关)的输入输出的公式

WF=(WIWw+2P)/S+1HF=(HIHw+2P)/S+1\begin{align} W_F &= (W_I - W_w + 2P)/S + 1\\ H_F &= (H_I - H_w + 2P)/S + 1 \end{align}

输入图像 输出图像 窗口大小 步幅 Padding
WI×HIW_I\times H_I WF×HFW_F\times H_F Ww×HwW_w\times H_w SS PP

参数训练

1
INPUT -> [[CONV]*N -> POOL?]*M -> [FC]*K

需要训练的部分是

  1. 卷积层中的卷积核的参数
  2. 全连接层中的变换矩阵

LeNet-5

LeNet是最早发布的卷积神经网络之⼀, 这个模型是由AT&T贝尔实验室的研究员Yann LeCun在1989年提出的(并以其命名), 目的是识别图像中的手写数字.

LeNet-5

经过多年的努力, 1998年在论文Gradient-Based Learning Applied to Document Recognition中正式提出的LeNet-5成为第一个广为人知的CNN

LeNet-5

卷积的矩阵乘法

普通卷积的计算, 移动窗口

[012345678][1234]=[27375767]inputkerneloutput\begin{array}{} \begin{bmatrix} 0&1&2\\3&4&5\\6&7&8 \end{bmatrix} &* &\begin{bmatrix} 1&2\\3&4 \end{bmatrix} &= &\begin{bmatrix} 27&37\\57&67 \end{bmatrix} \\ \rm input && \rm kernel && \rm output \end{array}

卷积可以转换成矩阵乘法

[27375767]=[120340000012034000000120340000012034][012345678]outputDoubly Block-Toeplitz matrixinput\begin{array}{} \begin{bmatrix} 27\\37\\57\\67 \end{bmatrix} &= &\left[\begin{array}{ccc|ccc|ccc} 1&2&0&3&4&0&0&0&0\\ 0&1&2&0&3&4&0&0&0\\ 0&0&0&1&2&0&3&4&0\\ 0&0&0&0&1&2&0&3&4\\ \end{array}\right] &\begin{bmatrix} 0\\1\\2\\-\\3\\4\\5\\-\\6\\7\\8 \end{bmatrix} \\ \rm output&& \text{Doubly Block-Toeplitz matrix} & \rm input \end{array}

Doubly Block-Toeplitz (DBT) matrix

Toepliz matrix

构造 Toepliz 矩阵

[012345678][1234]=[2737475767]inputkerneloutput\begin{array}{} \begin{bmatrix} 0&1&\textcolor{red}{2}\\\textcolor{blue}{3}&4&\textcolor{red}{5}\\\textcolor{blue}{6}&7&8 \end{bmatrix} &* &\begin{bmatrix} \textcolor{red}{1}&\textcolor{blue}{2}\\\textcolor{red}{3}&\textcolor{blue}{4} \end{bmatrix} &= &\begin{bmatrix} 27&37&\textcolor{green}{47}\\57&67& \end{bmatrix} \\ \rm input && \rm kernel && \rm output \end{array}

增加一行

[2737475767]=[120340000012034000001203400000120340000012034][012345678]outputDoubly Block-Toeplitz matrixinput\begin{array}{} \begin{bmatrix} 27\\37\\\textcolor{green}{47}\\57\\67 \end{bmatrix} &= &\left[\begin{array}{ccc|ccc|ccc} 1&2&0&3&4&0&0&0&0\\ 0&1&2&0&3&4&0&0&0\\ 0&0&\textcolor{red}{1}&\textcolor{blue}{2}&0&\textcolor{red}{3}&\textcolor{blue}{4}&0&0\\ 0&0&0&1&2&0&3&4&0\\ 0&0&0&0&1&2&0&3&4\\ \end{array}\right] &\begin{bmatrix} 0\\1\\2\\-\\3\\4\\5\\-\\6\\7\\8 \end{bmatrix} \\ \rm output&& \text{Doubly Block-Toeplitz matrix} & \rm input \end{array}

关于卷积的计算复杂度

in_channels×kernel_sizenumber of multiplications for one output pixel×out_size×out_chennelsnumber of output pixels\rm \underset{\text{number of multiplications for one output pixel}}{\underline{in\_channels \times kernel\_size}} \times \underset{\text{number of output pixels}}{\underline{out\_size \times out\_chennels}}