归山深浅去,须尽丘壑美。
莫学武陵人,暂游桃源里。
--裴迪《送崔九》中唐
上一次,在
神经网络的基本结构
上,增加了隐藏层,得以提取非线性可分的高层特征,并介绍了一种过拟合的缓解方法,在MNIST的验证数据集上,得到>98%的预测准确率。现在,不借助深度学习框架,继续为这个模型引入卷积处理,使模型进化为卷积神经网络(ConvolutionalNeuronNetwork),通过抽取愈丰富的高层特征,实现更精准的预测识别。
挑战
引入隐藏层,使模型通过抽取高层特征,具备了处理非线性可分样本的能力,也带来新的挑战:一个具有784维特征的样本,网络中每增加一层500个节点的隐藏层,模型需要引入 784 * 500 = 392,000 个权值w参数项和 500个偏置项b,对彩色或更大尺寸的输入图片,则需要引入更多参数,提高了模型的过拟合风险,也需要更大计算量,使更多层(更深)神经网络的训练成本上升,直至不再可行。
卷积神经网络(CNN),是应对这一挑战的有效方法。
结构
卷积神经网络(CNN)在模型中引入了新的结构:卷积层(Convolution Layer)和池化层(Pooling Layer)。
网络模型由各个处理层叠加构成,构成的模式如下:
输入层 -->{+ -->?} + -->+ -->输出层
一个或多个卷积层,可选搭配池化层,组成Conv-Pool 单元,多个Conv-Pool单元串联(如LeNet) , 或并联(如GoogLeNet)组合在一起,置于输入层和全连接层(FC Layer)之间,一起构成整个卷积神经网络。
下图例举的CNN结构,包含两组Conv_Pool单元。
输入层的图片数据不再是一阶向量(Vector),而是n阶张量(Tensor),一张RGB色彩模式的图片,可以看作深度(channel)为3的矩阵,每个深度上的矩阵元素,表达当前颜色通道下,不同位置的亮度。
与全连接层不同,卷积层与池化层相邻的节点,只有部分相互连接。输入数据经过一系列Conv-Pool单元,提取出高层特征,再由全连接层完成分类,最后通过softmax得到图像归属于各个类别的概率分布。
卷积层
Convolutional neural nets are based on the simple fact that a vision system needs to use the sameknowledge at all locations in the image. --Geoffrey Hinton 2018
卷积神经网络立足于一个简单的事实:视觉系统在图像的不同区域上,使用了相同的理解机制。
Geoffrey Hinton, at age 8, enjoying adventures with python.
权值共享
某一个特征在图片的不同位置是同等重要的,基于这个假设前提,卷积层用一套共享的权值参数 -- "过滤器(Filter)",来抽取图像所有通道的高层特征,将输入数据转换为下一层的输出,CNN中卷积过滤器也被称为“卷积核(Kernel)”。过滤器的个数也被称为卷积核的深度。
下图卷积计算的例子中,过滤器个数(Fdepth)为1,过滤器权值参数w有三个分量矩阵,分别与输入张量x的3个通道(channel)矩阵做运算。
在每个输入通道的矩阵上,依次用过滤器同尺寸(Fheight x Fwidth)的数据块(block), 与对应的w分量矩阵分别做内积运算,3个内积结果和偏置b相加,得到输出矩阵Out上对应位置的元素。
在输入矩阵上,从左到右,自上而下,依次移动选取数据块(block),完成上述运算,得到输出矩阵Out的全部元素。
步长(strides)
在输入矩阵上选取输入数据块(block)时,可以在宽(input_width)和高(input_height)两个方向上逐元素“顺序移动”,也可以用特定步长(strides>1)”跳跃移动“,压缩输出尺寸,换取计算速度提升。
为了确保所有输入元素不遗漏地参与计算,在处理之前,可能需要先对输入矩阵,做边缘填充(padding)。
边缘填充(padding)
边缘填充可以使用就近元素值,也可以像上面的例子一样,使用全零填充(zero-padding)。
是否需要填充,以及填充的尺寸padding,可以用下面的公式判断和推算:
例如:
当输入矩阵为7x7, 卷积核为3x3,步长stride=1, 输出尺寸为5 x 5 时,padding= 0, 不需要做填充。
当输入矩阵为3x3, 卷积核为2x2,步长stride=1, 输出尺寸为4 x 4 时,padding= 1,需要做一层边缘填充。
多个过滤器
为抽取更丰富的特征,一个卷积层往往有多个过滤器,即Fdepth > 1,此时,输出结果Out会有Fdepth个分量矩阵,或者说卷积层的输出深度为D = Fdepth。
输入数据与过滤器后经过上述卷积运算后,在输出矩阵某个输出深度d上,位于第i行j列的元素值为:
其中CH为输入数据通道(Channel),R和C分别为过滤器在高度和宽度上的尺寸。
运算结果经过ReLU激活函数,得到的当前卷积层在深度d上激活后的输出:
多个输出深度上的矩阵,共同构成当前卷积层输出a,同时也作为CNN下一层的输入数据。
CNN中的卷积,本质上是互相关(Cross-Correlation)运算,与数学上卷积的原始定义不同,两种运算用于CNN模型参数训练是等效的。
你可以进一步了解卷积和互相关,也可以跳过这一节,从池化层继续阅读,不影响对卷积神经网络的整体理解和实现。
再深一点:卷积和互相关
数学意义上的原始卷积运算,是通过两个函数f和g生成第三个函数S的运算,S表征函数f与经过翻转和平移的函数g的乘积的积分。
一阶连续形式:
回忆积分的几何意义,它是乘积函数S所围成的曲边梯形的面积(Ref:wiki)。
二阶离散形式:
对上一节的(式1),如果不考虑输入通道channel这个维度跟输出深度d,再拿掉偏置项b, 可以简化为(式1'):
比较原始卷积(Convolution)和互相关(Cross-correlation),发现仅仅是运算符号有差异,使得输入数据x,与过滤器权值矩阵w做内积运算时,x数据块(block)中元素,与w中的元素是逆序对应的,如果把w旋转180°作为过滤器,卷积运算就成了互相关运算。
这个差异,使原始卷积运算满足结合律(associative):
Fa*(Fb*G) = (Fa*Fb)*G
结合率,在需要连续多次原始卷积的场景下非常实用:你可以先把各个卷积核做卷积运算,得到新的叠加卷积核,再与输入数据做一次卷积得到结果;如果这些卷积核的权值参数都是已知常数,则可以更进一步:预先计算叠加卷积核并存储起来,成倍提高运算效率。
互相关运算不满足结合律,目前成熟的CNN模型,也不需要做多个过滤器直接叠加的互相关运算;互相关运算另有效果拔群的优化方法,实现部分会做具体介绍。
通常,互相关运算用于图像模式匹配(template matching ),原始卷积运算用于图像柔化处理(smoothing)。CNN模型训练的时候,参数不是预先固定的常量,而是通过反向传播误差损失,迭代优化得到的,所以前向传播时过滤器w无论翻转与否,对模型参数训练是等效的。
池化层
池化层改变输入张量中,各个分量矩阵的长和宽尺寸,通常仅缩小矩阵的大小,不改变三维矩阵的深度;池化层减少了全连接层中的节点个数,也通过降低整个神经网络的参数量,缓解了过拟合风险。
池化处理也称为降采样(sub-sampling),可以直观理解为,降低了图片的分辨率,同时保留图像的一部分特征。
池化层处理的做法,同样是采用固定尺寸的过滤器,在输入矩阵上依次移动,摘取对应block像素上的最大值(max-pooling)或平均值(mean-pooling),构成输出矩阵的元素,作为采样结果。
例如:图示的max-pooling处理,采用尺寸为 2x2 的过滤器,对所有深度上的节点矩阵,以步长(strides)2,在长和宽两个维度跳跃移动,摘取4像素block上的最大值作为采样结果,从而将节点矩阵尺寸压缩到原来的25%。
若size_i分别为池化层输入矩阵的尺寸,F为池化过滤器尺寸,S为步长Strides, 则可以推算输出矩阵的尺寸。
全连接层和Softmax层
经过卷积层和池化层处理,抽取得到更高层特征后,经过若干全连接层完成分类,最后由softmax层将分类结果转换为标准概率分布。
这部分的处理可参考之前的介绍,这里重点介绍CNN的学习算法。
学习算法
首先,统一本文中的标识符和特定运算符含义:
再来回顾全连接层对误差δ的反向传播。
第L层(全连接层)原始输出:
该层经过函数f激活后的输出:
第L-1层的原始输出误差 δ 可以由L层的输出误差反推得到:
参数的梯度,由该层的激活前输出误差和上一层激活后输出推算:
池化层和卷积层由于节点间是局部连接,误差传递不同于全连接层,下面分别来看。
池化层反向传播
池化层对本层输入数据,同样移动过滤器定位数据块,逐数据块(block)做获取最大值或均值的固定处理,只有步长(Strides)和过滤器尺寸(Filter_size)超参数,没有权值参数需要训练,只需要将误差 δ 反向传播至上一层。这个过程是下采样的逆处理,也称为上采样(up-sampling);最大池化层和平均池化层的上采样过程分别来看:
对最大池化层(max-pooling),由于池化处理时,输出矩阵的每组数据块(block),只有max value元素被采样,所以每个数据块,max _value元素的梯度为1,其它元素不参与误差传递,梯度为0。
为了让最大池化层的误差 δ 回传时对号入座,在max-pooling处理时,输入数据每个深度上各个数据块max value的位置索引,需要在采样后保存下来,反向传播时直接复用。
对平均池化层(mean-pooling),更简单些,由于池化处理时,输出矩阵的每个数据块(block),各元素的均值被采样,所以误差 δ 反向传播,只要等权重平均分配到误差矩阵各个数据块对应元素位置即可。
结合两种上采样处理,池化层对误差的反向传播可以表示为:
卷积层反向传播
步长strides为 1时 , 一个输入通道channel上,一个过滤器filter的卷积层误差δ传递 :
其中第一部分,结合cross-correlation的定义,对误差元素逐项求导可以观察到,上一层误差矩阵,是本层误差矩阵padding后,与旋转180度的filter做cross-correlation运算的结果:
说明:此处*表示互相关(cross-correlation)运算。
即:
展开为逐项累加形式:
δ 的数据块元素与过滤器w的元素,逆序对应再做内积运算 ,这是原始定义的卷积运算,与前向预测的互相关运算不同。
第二部分:
是激活函数f的导函数,两部分合在一起:
或Cross-correlation形式:
步长Strides 大于 1 时,前向卷积结果较Strides=1的情况,跳过了部分元素后构成卷积输出,所以先扩展误差矩阵,补全跳过部分的元素位置,这部分数据不在网络中传递,所以在增补位置填梯度0,问题就成了步长为1时的误差矩阵求解,仍然用(式3) 计算上一层误差。
输入通道Channel和过滤器Filter个数Depth都大于1时,把D层深度误差矩阵的每一层,逐个矩阵与该层的C个过滤器矩阵做卷积,得到C个上一层误差矩阵分量,所有D深度上的误差矩阵做同样运算,得到D组,每组C个,合计DxC个误差矩阵分量;在D这个维度上将各分量按元素相加,就合并成C个误差矩阵分量,它的维度规格和channel个通道的输入数据完全一致,这就是传导到上一层误差张量 δ 。
计算filter的权值参数梯度▽w:
对第二部分,由于z是 由w作为过滤器,做cross-correlation运算得出的:
对运算逐项展开求导可以观察到,本层过滤器权值参数梯度,是以本层误差张量 δ 作为过滤器,和上一层激活后输出做cross-correlation运算的结果:
展开为逐项累加形式:
计算filter的偏置梯度▽b:
有D个过滤器的卷积核,偏置项梯度同样有D个,顺位d的这个卷积核偏置项梯度,是该网络层误差张量δ 在d这个分量矩阵上各个元素的和:
以上,是CNN模型中,全连接层,以及新引入的卷积层、池化层反向传播的具体算法,也是支撑各大CNN模型的基础构件。
实现的考量
基于上述算法,可以从底层完整实现一个多层卷积神经网络;然而从工程实践考量,又迎来新的挑战:
首先,CNN较之前的多层神经网络,虽然通过权值共享和降采样处理,压缩了参数量和运算量,可是需要通过增加过滤器深度,来抽取更丰富的高层图像特征,加上新引入的多样迭代运算,使原始算法的训练成本高企。
另一方面,输入包含了多通道,使数据量倍增;反向传播过程中,除了需要缓存各层级权值参数,还需要保持反向传播的误差张量和max-pooling索引矩阵,内存开销制约mini-batch的容量上限,训练模型参数时,各方向上的更新梯度容易相互抵消,模型收敛缓慢。
下一次,将分享几种加速计算的方法,通过改进原始的池化和卷积算法,使正向和反向传播,大幅提速到工程可行级别。再为批次梯度下降优化算法,引入动量因子和自适应方法,显著提高优化效率,使模型快速收敛,将MNIST数据集上的识别准确率,进一步提高到99%以上。
(完)
索引
从0到1:神经网络实现图像识别
1.目标问题:MNIST手写数字识别数据集
3.第一个神经网络:从二分类到多分类
5.卷积神经网络:卷积与池化
(五) CNN卷积经网络(本篇)
参考
[1] 斯坦福大学 Unsupervised Feature Learning and Deep Learning tutorial :UFLDL Tutorial.
[2] 斯坦福大学 class CS231n:The Stanford CS class CS231n.
[3] Y. LeCun, L. Bottou, Y. Bengio and P. Haffner: Gradient-Based Learning Applied to Document Recognition, *Proceedings of the IEEE, 86(11):2278-2324, November 1998.
长按订阅,获得更新
可以通过“原文” 查看文中链接和Github源码。
领取专属 10元无门槛券
私享最新 技术干货