卷积神经网络是一种前馈型神经网络, 受生物自然视觉认知机制启发而来的. 现在, CNN 已经成为众多科学领域的研究热点之一, 特别是在模式分类领域, 由于该网络避免了对图像的复杂前期预处理, 可以直接输入原始图像, 因而得到了更为广泛的应用. 可应用于图像分类, 目标识别, 目标检测, 语义分割等等. 本文介绍可用于图像分类的卷积神经网络的基本结构.
深度学习是一种特殊的机器学习,通过学习将世界使用嵌套的概念层次来表示并实现巨大的功能和灵活性,其中每个概念都定义为与简单概念相关联,而更为抽象的表示则以较不抽象的方式来计算。
1. CNN 结构介绍
上面是一个简单的 CNN 结构图, 第一层输入图片, 进行卷积(Convolution)操作, 得到第二层深度为 3 的特征图(Feature Map). 对第二层的特征图进行池化(Pooling)操作, 得到第三层深度为 3 的特征图. 重复上述操作得到第五层深度为 5 的特征图, 最后将这 5 个特征图, 也就是 5 个矩阵, 按行展开连接成向量, 传入全连接(Fully Connected)层, 全连接层就是一个 BP 神经网络. 图中的每个特征图都可以看成是排列成矩阵形式的神经元, 与 BP神经网络中的神经元大同小异. 下面卷积和池化的计算过程.
卷积
对于一张输入图片, 将其转化为矩阵, 矩阵的元素为对应的像素值. 假设有一个 的图像,使用一个 的卷积核进行卷积,可得到一个 的特征图. 卷积核也称为滤波器(Filter).
具体进行的操作过程如下图所示:
黄色的区域表示卷积核在输入矩阵中滑动, 每滑动到一个位置, 将对应数字相乘并求和, 得到一个特征图矩阵的元素. 注意到, 动图中卷积核每次滑动了一个单位, 实际上滑动的幅度可以根据需要进行调整. 如果滑动步幅大于 1, 则卷积核有可能无法恰好滑到边缘, 针对这种情况, 可在矩阵最外层补零, 补一层零后的矩阵如下图所示:
可根据需要设定补零的层数. 补零层称为 Zero Padding, 是一个可以设置的超参数, 但要根据卷积核的大小, 步幅, 输入矩阵的大小进行调整, 以使得卷积核恰好滑动到边缘.
一般情况下, 输入的图片矩阵以及后面的卷积核, 特征图矩阵都是方阵, 这里设输入矩阵大小为 , 卷积核大小为 , 步幅为 , 补零层数为 , 则卷积后产生的特征图大小计算公式为:
上图是对一个特征图采用一个卷积核卷积的过程, 为了提取更多的特征, 可以采用多个卷积核分别进行卷积, 这样便可以得到多个特征图. 有时, 对于一张三通道彩色图片, 或者如第三层特征图所示, 输入的是一组矩阵, 这时卷积核也不再是一层的, 而要变成相应的深度.
上图中, 最左边是输入的特征图矩阵, 深度为 3, 补零(Zero Padding)层数为 1, 每次滑动的步幅为 2. 中间两列粉色的矩阵分别是两组卷积核, 一组有三个, 三个矩阵分别对应着卷积左侧三个输入矩阵, 每一次滑动卷积会得到三个数, 这三个数的和作为卷积的输出. 最右侧两个绿色的矩阵分别是两组卷积核得到的特征图.
池化
池化又叫下采样(Dwon sampling), 与之相对的是上采样(Up sampling). 卷积得到的特征图一般需要一个池化层以降低数据量. 池化的操作如下图所示:
和卷积一样, 池化也有一个滑动的核, 可以称之为滑动窗口, 上图中滑动窗口的大小为 , 步幅为 2, 每滑动到一个区域, 则取最大值作为输出, 这样的操作称为 Max Pooling. 还可以采用输出均值的方式, 称为 Mean Pooling.
全连接
经过若干层的卷积, 池化操作后, 将得到的特征图依次按行展开, 连接成向量, 输入全连接网络.
2. 公式
输入
输出
上面的输入输出公式是对每一个卷积层而言的, 每一个卷积层都有一个不同的权重矩阵 , 并且 , , 是矩阵形式.对于最后一层全连接层, 设为第 层, 输出是向量形式的 , 期望输出是 , 则有总误差公式
总误差
conv2() 是 Matlab 中卷积运算的函数, 第三个参数 valid 指明卷积运算的类型, 前面介绍的卷积方式就是 valid 型. 是卷积核矩阵, 是输入矩阵, 是偏置, 是激活函数. 总误差中的 , 分别是期望输出和网络输出的向量. 表示向量 的 2-范数, 计算表达式为 . 全连接层神经元的输入输出计算公式与 BP网络完全相同. 是一种激活函数.
3. 梯度下降和反向传播算法
与 BP神经网络一样, CNN 也是通过梯度下降和反向传播算法进行训练的, 则全连接层的梯度公式与 BP网络完全一样, 这里就不重复了. 下面介绍卷积层和池化层的梯度公式.
现在的目标是求出 和 的表达式. 首先求 , 从一个简单情况开始.
设输入是 3×3 的矩阵, 卷积核是 2×2的矩阵.
(1) 当步长为 1 时, 则可得到 2×2的特征图矩阵. 如下图所示:
绿色矩阵是第 层神经元, 红色的是第 层, 黄色的是第 层的卷积核, 图中省略掉了第 层的卷积核. 每个矩阵的元素可以看成一个神经元, 于是和 BP网络一样, 可以对每个神经元定义局部梯度, 为了看着清楚, 把矩阵的元素换成 . 神经网络中数值的传递也可以看成导数的传递. 假设已经求出了 , 则 的计算公式为
这是一个递归公式. , , 是矩阵形式, 公式中 rot180() 函数表示将矩阵逆时针旋转 180 度, 参数 full 表示进行的完全的卷积运算, 这种运算形象的解释如下:
首先将特征图矩阵补一圈零, 然后用权重矩阵对补零后的特征图矩阵进行 vaild 型卷积运算. 这里补零的层数等于卷积核矩阵的大小减去 1, full型 卷积的内涵在于使卷积从边缘开始, 即先计算 , 然后是 , 以此类推. 关于 递归公式的推导, 请看文末补充的内容.
(2) 当滑动步幅大于 1 时
上图分别是步长为 1, 2 时的卷积过程, 可以发现步长为 1 是一个比较完全的卷积, 当步长增大时, 会跳过某些区域, 因此可以通过对特征图补零的方式将步幅为 2 时生成的特征图转换为步幅 1 的特征图, 然后直接利用前面推导的公式即可求出 . 补零如下图所示
(3) 当卷积核数目为 N 时, 与 BP 网络隐藏层神经元局部梯度计算类似, 每一个权重的改变, 都会影响到下一层每一个神经元输入的改变, 所以误差的反响传递需要把误差之和传到前一层, 则公式可简单地修改为
(4) 对于池化层的梯度传递, 情况就简单了一些, 下面以 Max Pooling 为例
图中滑动窗口大小为 2×2, 步幅为 2, 则得到一个 2×2 的特征图, Max Pooling 方法是选择最大的数值作为输出, 由于过程中没有任何运算, 不存在梯度的变化, 所以误差可以直接由第 层传递到第 层, 如下图所示
图中假设四个角上的元素值最大, 则对应位置的局部梯度可直接反向传递, 其它位置由于没有连接, 则梯度设为 0.
如果池化类型是 Mean Pooling, 即取滑动窗口内的均值作为输出, 则将 层的梯度的 反向传递到 层, 如下图所示
到此为止已经推导出了不同情况下的 的递归公式, 下面推导 的表达式. 下图所示, 为了表达清楚, 将符号做一些替换, 相对于第 层, 第 层的输出变量符号可由 变为 .
根据卷积的原理, 可以得到
可以发现, 由于共享权重, 一个权重 的改变, 会影响所有的 . 因而对某一个权重求梯度时, 需要运用全微分公式. 现在以 为例, 求得表达式
同理可得
根据得到的结果, 可以发现计算 的规律:
首先将前面的图中卷积核和特征图调换一下位置, 将特征图矩阵的元素替换为 , 将卷积核矩阵的元素替换为 对 的偏导. 根据前面得到的偏导公式, 可以发现特征图对输入矩阵卷积可得到右边黄色的偏导矩阵. 即
公式中 , , 是以矩阵形式表达的. 同时, 可得到
4. CNN 的特点
一个 CNN 是为了识别二维形状而特殊设计的多层感知器, 对二维形状的缩放, 倾斜或其它形式的变形具有高度不变性. 每一个神经元从上一层的局部区域得到输入, 这迫使神经元提取局部特征. 一旦一个特征被提取出来, 它相对于其它特征的位置被近似保留下来, 而忽略掉精确的位置. 每个卷积层后面跟着一个池化, 使得特征图的分辨率降低, 而有利于降低对二维图形的平移或其他形式的敏感度.
权值共享是 CNN 的一大特点, 每一个卷积核滑遍整个输入矩阵, 而参数的数目等于卷积核矩阵元素的数目加上一个偏置, 相对于 BP 网络大大减少了训练的参数. 例如对于一张 300×300 的彩色图片, 如果第一层网络有25个神经元, 使用 BP网络, 参数的数目可达 675万个(300×300×3×25+1300×300×3×25+1), 而卷积网络只有76个(25x3+125x3+1).
下图是将卷积核可视化的结果
每一个卷积核就是一个特征提取器, 可以提取出输入图片或特征图中形状, 颜色等特征. 当卷积核滑动到具有这种特征的位置时, 便会产生较大的输出值, 从而达到激活的状态.
递归公式的推导
CNN 是一种前馈型神经网络, 每一个神经元只与前一层神经元相连, 接受前一层的输出, 经过运算后输出给下一层, 各层之间没有反馈. 因此对于计算局部梯度, 可以根据后一层神经元的梯度, 递归地向前传递. 首先根据前面演示过的一张图
局部梯度的定义公式
现在我们求出几项 来寻找规律, 首先假设图中第 层中的 已知, 根据卷积运算的原理可得
同理可得
则可以发现 的计算公式可以表达为上图中黄色卷积核在补零后的特征图卷积, 步幅为 1.
代入局部梯度公式得
其它形式的卷积
a. 卷积
定义下卷积层的结构参数
卷积核大小(Kernel Size): 定义了卷积操作的感受野. 在二维卷积中, 通常设置为 3, 即卷积核大小为 3×3.
步幅(Stride): 定义了卷积核遍历图像时的步幅大小. 其默认值通常设置为 1, 也可将步幅设置为 2 后对图像进行下采样, 这种方式与最大池化类似.
边界扩充(Padding): 定义了网络层处理样本边界的方式. 当卷积核大于1且不进行边界扩充, 输出尺寸将相应缩小; 当卷积核以标准方式进行边界扩充, 则输出数据的空间尺寸将与输入相等.
输入与输出通道(Channels): 构建卷积层时需定义输入通道 I, 并由此确定输出通道 O. 这样, 可算出每个网络层的参数量为 I×O×K, 其中 K 为卷积核的参数个数. 某个网络层有 64 个大小为 3×3 的卷积核,则对应K值为 3×3=9.
b. 空洞卷积(atrous convolutions)又名扩张卷积(dilated convolutions), 向卷积层引入了一个称为 扩张率(dilation rate) 的新参数,该参数定义了卷积核处理数据时各值的间距.
一个扩张率为 2 的 3×3 卷积核, 感受野与 5×5 的卷积核相同, 而且仅需要 9 个参数. 你可以把它想象成一个 5×5 的卷积核, 每隔一行或一列删除一行或一列.
在相同的计算条件下, 空洞卷积提供了更大的感受野. 空洞卷积经常用在实时图像分割中. 当网络层需要较大的感受野, 但计算资源有限而无法提高卷积核数量或大小时, 可以考虑空洞卷积.
c. 转置卷积(Transposed Convolutions)又名反卷积(Deconvolution)或是分数步长卷积(Fractially Straced Convolutions).
反卷积(deconvolutions)这种叫法是不合适的,因为它不符合反卷积的概念. 在深度学习中,反卷积确实存在,但是并不常用. 实际上, 反卷积是卷积操作的逆过程. 你可以这么理解这个过程, 将某个图像输入到单个卷积层, 取卷积层的输出传递到一个黑盒子中, 这个黑盒子输出了原始图像. 那么可以说, 这个黑盒子完成了一个反卷积操作, 也就是卷积操作的数学逆过程.
转置卷积与真正的反卷积有点相似, 因为两者产生了相同的空间分辨率. 然而, 这两种卷积对输入数据执行的实际数学运算是不同的. 转置卷积层只执行了常规的卷积操作, 但是恢复了其空间分辨率.
举个例子, 假如将一张 5×5 大小的图像输入到卷积层, 其中步幅为 2, 卷积核为 3×3, 无边界扩充. 则卷积层会输出 2×2 的图像。
若要实现其逆过程, 需要相应的数学逆运算, 能根据每个输入像素来生成对应的 9 个值. 然后, 将步幅设为 2, 遍历输出图像, 这就是反卷积操作.
转置卷积和反卷积的唯一共同点在于两者输出都为 5×5 大小的图像, 不过转置卷积执行的仍是常规的卷积操作. 为了实现扩充目的, 需要对输入以某种方式进行填充。
你可以理解成, 至少在数值方面上, 转置卷积不能实现卷积操作的逆过程.
转置卷积只是为了重建先前的空间分辨率,执行了卷积操作。这不是卷积的数学逆过程,但是用于编码器-解码器结构中,效果仍然很好. 这样, 转置卷积可以同时实现图像的粗粒化和卷积操作,而不是通过两个单独过程来完成。
d. 可分离卷积(Separable Convolution)中, 可将卷积核操作拆分成多个步骤. 卷积操作用 来表示,其中输出图像为 , 输入图像为 , 卷积核为 . 接着, 假设 可以由下式计算得出: . 这就实现了一个可分离卷积操作, 因为不用 执行二维卷积操作, 而是通过 和 分别实现两次一维卷积来取得相同效果.
Sobel 算子通常被用于图像处理中, 这里以它为例. 你可以分别乘以矢量 [1,0,−1][1,0,-1] 和 [1,2,1][1,2,1] 的转置矢量后得到相同的滤波器. 完成这个操作, 只需要 6 个参数, 而不是二维卷积中的 9 个参数.
这个例子说明了什么叫做空间可分离卷积, 这种方法并不应用在深度学习中, 只是用来帮你理解这种结构.
在神经网络中, 我们通常会使用深度可分离卷积结构(Depthwise Separable Convolution). 这种方法在保持通道分离的前提下, 接上一个深度卷积结构, 即可实现空间卷积. 接下来通过一个例子让大家更好地理解.
假设有一个 3×3 大小的卷积层, 其输入通道为 16, 输出通道为 32. 具体为, 32 个 3×3 大小的卷积核会遍历 16 个通道中的每个数据, 从而产生 16×32=512 个特征图谱.进而通过叠加每个输入通道对应的特征图谱后融合得到1个特征图谱. 最后可得到所需的 32 个输出通道.
针对这个例子应用深度可分离卷积, 用 1 个 3x3 大小的卷积核遍历 16 通道的数据, 得到了16个特征图谱. 在融合操作之前, 接着用 32 个 1×1 大小的卷积核遍历这16 个特征图谱, 进行相加融合. 这个过程使用了 16×3×3+16×32×1×1=656 个参数, 远少于上面的 16×32×3×3=4608 个参数.
这个例子就是深度可分离卷积的具体操作, 其中上面的深度乘数(depth multiplier)设为 1, 这也是目前这类网络层的通用参数.
这么做是为了对空间信息和深度信息进行去耦. 从Xception模型的效果可以看出, 这种方法是比较有效的. 由于能够有效利用参数, 因此深度可分离卷积也可以用于移动设备中.
更多卷积动画: https://github.com/vdumoulin/conv_arithmetic
建议查看原文获得更好的阅读体验!
[阅读原文]