CNN 卷积神经网络【更新中】
前置基础知识
convolution operator 卷积运算
输入矩阵循环取子矩阵跟filter(kernal)按位乘后加和作为输出矩阵对应位置的值。
convolution与cross correlation
上面操作实际是cross correlation操作,两者之间的唯一区别是卷积操作需要在开始计算之前将卷积核进行翻转。但是在CNN领域都把互相关操作记为卷积操作了,因为这对模型没有任何影响并且计算量更小。
在一些信号处理场景中,真正的卷积(即带翻转)可以使卷积操作满足结合律,但这在CNN模型中没用。
发现边
使用下图中的filter可以发现竖直边。原因是边的两侧数值是不一样的,分别取正取负会是非0值,而没有边的地方两侧数值基本相等,分别取正取负是0值,因此非0值可以代表有竖直线。
同时值的正负可以代表两侧的颜色差异,是从暗到明,还是从明到暗,如果不关注明暗变化的话可以取绝对值。
使用不同的filter矩阵可以实现不同的效果。随着深度学习的出现可以使用可更新参数,在训练中反向传播更新,可以达到更好的效果。
padding
在上面的卷积运算中有两个问题:
1. 输出维度会缩小
2. 边缘的像素被使用到的次数比中心的点少
所以在进行卷积操作之前先将原始输入增加padding,可以规避上面两个问题
strided convolutions 跨步卷积
即卷积运算时不是一个格子一个移动,而是每次移动stride个格子。
convolution on volume
卷积核的层数与输入层数一致,每层分别计算卷积后加和作为最终输出,最终输出还是一层。
如果使用多个卷积核进行计算,则可以得到多层的输出。不同的卷积核可以发现不同方向的边
Pooling 池化
池化的操作跟卷积类似,圈选跟核同样的区域块并移动,在区域内与核进行操作,比如最大池化的操作变成了取区域内最大值,而不是按位乘加和。
池化用的最多的是最大池化,其次是平均池化。
通常不会padding后池化,偶尔也会。
平均池化就是区域内取平均值。
Networks in Networks(1×1 convolution)
池化用于减小网络Volume中的height和width,1×1卷积可以用来减小Volume中的channel数量。如下图6×6×32的网络层经过1×1×32的卷积核组成的卷积层,会输出6×6×#卷积核数量。也就是可以通过控制1×1 convolution的卷积核数量来缩放channel数量。并且可以引入非线性。
卷积神经网络模型结构
单层卷积神经网络
卷积神经网络的一层中,卷积核卷积操作类似于标准神经网络中的参数,之后加一个
参数,然后使用激活函数激活得到输出。
维度分析如下:
深度卷积神经网络
简单卷积网络
最后一层输出将三个维度的数值展开为一个一维向量并输入到逻辑回归单元或者Softmax单元进行结果输出。
实际应用中一般会让宽度和高度逐步降低,channel数(厚度)变大。
常规卷积网络
卷积层后通常会带池化层,不过一般会把两者成为真正的一层,因为池化层只有超参,而没有需要训练的参数一般不统计在层数之内。
几层卷积层之后接入几层全连接层,然后接入Softmax层输出数字预测。
下面是在模型中每一层输出的shape、大小以及参数大小情况。
一般输出的大小是会下降的,但是要逐步下降,如果猛烈下降效果可能会不太好。
主要的参数量还是在全连接层。
卷积神经网络优点
参数共享
如下图的一个卷积层,参数量:(5*5+1)*6=156。
而如果使用全连接映射3072维到4704维,则需要3072*4704=14M参数。
卷积神经网络通过参数共享大幅降低参数量,而能参数共享的原因是图像的不同部分会存在相同的特征,比如竖直边、横边等。也就是能识别一些具有平移不变性的特征。
稀疏连接
输出中的一个元素只跟输入中的部分元素相关,不是全连接的。这样可以使模型能够捕捉图片中的局部特征,更高效地处理图像的空间结构。
Case Study
在CNN模型中有非常多的超参,如果设置这些超参是个问题。通常不需要你全部从头调试,而是可以尝试从论文中或者其他人项目中参考其他人的参数即可。在CV里面如果其他人的效果比较好,那么大概率在你的项目也会不错。
经典网络
LeNet-5
跟之前的例子相似,只是原文由于历史原因有一些方式跟现在不同。比如池化使用的平均池化,闲杂一般使用最大池化;输出层不是使用的Softmax激活函数;隐藏层的激活函数用的SIGMOD/tanh,而非ReLU;当时算力不够,一个卷积层为了处理不同channel有复杂的处理方式;等等
AlexNet
在AlexNet出现之前深度学习在语音识别等领域已经很好用,但在CV领域影响力不大。2012年在ImageNet大规模视觉识别挑战赛中表现优异,使得深度学习在CV以及其他领域也开始有超强的影响力。
更复杂的模型,深度更深,60M的参数。
使用了两张GPU联合训练。
使用了ReLU激活函数。
VGGNet
VGG-16代表有16层带参数的网络,即不包含池化层。
大幅减少了超参数量,因为都是使用相同的卷积核(数量在变)、池化层。
138M参数。
ResNet
由于梯度消失或者爆炸之类的问题,很深的网络很难训练成功。Residual network避免了这个问题,让我们能够训练深达比如100层的网络。
通过将前序的隐藏层输出到隔一层的网络层实现。普通神经网络:
ResNet网络结构如下图,状态转移转移方程:
为什么奏效
,展开
得到
,
如果及
都等于0,可以得到
,由于我们使用的ReLU激活函数计算得到的
,
大于等于0,再套一层ReLU函数值不变,即
。
如果的维度跟
不一致,可以在
前再乘一个矩阵转换维度到一致。
也就是说如果在l+2层出现了梯度消失或者学习出来这一层参数就是接近0,也能使输出维持在第l层,相当于第l+1和l+2层不存在,这不会影响我们的模型效果。
但是我们不仅希望不影响模型效果,我们是希望提高模型效果。在很深的模型中,有些层可能会产生坏的影响,添加残差网络后,可以使得模型能学习到这些恒等的层,让一些层不发挥坏作用,然后其他好的层就能更好的发挥作用。
应用了残差网络的CNN网络如图:
Inception Network
Inception模块
原理图版本
对一个输入,分别使用1×1、3×3、5×5卷积核进行卷积操作,以及一个最大池化操作,每个操作都会输出一个Volume,保证每个Volume的width和height一致,然后将其拼接起来获得一个最终输出。
优化版本
上面的版本存在一个问题就是计算量巨大,比如我们看下其中的5×5卷积核的卷积操作计算量:
一个卷积核一个框计算量 5*5,192个channel再*192,框需要移动28*28次,一共32个卷积核,总计算量5*5*192*28*28*32≈120M。
使用1×1卷积核降低计算量:
即先使用1×1卷积核降维,然后再使用正常卷积升维,这个1×1卷积层一般称为"bottleneck layer"瓶颈层。计算量降低为1*1*192*28*28*16 + 5*5*16*28*28*32≈12.4M。从原先的120M降低到12M,下降为原先的10%
并且,从实际的效果来看,使用1×1卷积层降维对于模型效果本身的效果并没有明显降低,可能的原因如下:
1. 增加非线性:1×1卷积后通常会接一个非线性激活函数(如ReLU),这可以引入额外的非线性能力,增强模型的表达能力;
2. 跨通道信息融合:1×1卷积可以融合不同通道的信息,从而提取更丰富的特征;
3. 防止过拟合:减少参数量可以降低模型的复杂度,从而在一定程度上防止过拟合。
最终结构
池化层不影响channel数量,所以再跟一个1×1卷积降低channel维度。
完整模型结构
下图是Inception V1版本,也叫做GoogleNet,后续还衍生成V2、V3、V4、Inception-ResNet等版本。
模型中有不少重复的Inception模块,除此之外还有两个中间的输出层保障前面的预测结果不会太差,这个被证明有正则化的作用。
inception的命名来源是《盗梦空间》里面的台词"we need to go deeper"。
MobileNet
出现原因
MobileNet出现的原因是前面提到的CNN网络往往计算量都非常大,不适合在计算能力低的手机等移动设备运行。因此逐步提出了对计算性能要求更低的MobileNet。
基本原理
Normal Convolution
普通卷积每个卷积核的channel数跟输入channel数对齐,然后通过卷积核的个数控制输出channel数,原理及计算量如下图:
Depthwise Convolution
depthwise卷积是每个卷积核的channel数都是1,然后卷积核的个数跟输入的channel数一致,这样每个卷积核只处理输出的一个channel,得到一个跟输出channel数一样的输出。原理及计算量如下图:
Pointwise Convolution
Pointwise卷积其实就是1×1的Normal卷积,每个卷积核都在处理输入的一个Point。其原理和计算量如下图:
Depthwise Separable Convolution
Depthwise Separable卷积就是把输入先进行Depthwise卷积,再接一个Pointwise卷积。
值得注意的是Pointwise卷积层的输入是Depthwise卷积层输出,而Depthwise卷积层的输出channel数跟其输入channel数一致,所以这三者的channel数都是一致的。而Pointwise卷积层卷积核的个数可以控制最终输出层的channel数。
在这个操作中计算量大幅下降,在上面图中给的例子里面计算量降低为Normal卷积的31%,在论文中作者给出的计算量下降如下图右侧,典型的场景中计算量下降为普通卷积的10%
模型结构
V1版本
使用上面提到的Depthwise separable卷积,重复13次
V2版本
如上图下半部分,跟V1有两个主要区别:
1. 引入了残差连接
2. Depthwise卷积前面增加了一个Expansion层。
中间的整个模块叫做Bottleneck模块,其内容如下。Expansion层其实就是一个1×1的Normal卷积层,然后卷积核的个数大于输入的channel数实现channel数放大。然后在Pointwise卷积层再通过减小卷积核个数将channel数缩小到原来的大小。
另外在这个版本中残差块的输出是通过线性激活函数激活的,没有使用ReLU,ChatGPT的解释是避免了激活函数可能带来的信息丢失,尤其是在低维度特征中。
EfficientNet
在不同算力的设备上你可能想根据算力选择不同的模型结构,通常可以通过输入的分辨率r、模型的深度d、模型每一层的宽度d影响模型的算力要求,如何选择合适的参数,可以参考下面论文,没有展开讲。
CNN应用的建议
使用开源实现
即使对于一个相关专业的博士生来说,仅通过阅读论文来复现他们的模型效果也是很困难的。幸运的事有很多研究者会将论文的实现开源在网络上,可能是论文作者,也可能是其他研究人员。因此第一个建议就是你想使用一篇论文的模型时,可以先在网络上搜索开源实现。
迁移学习
在CNN网络的应用中,迁移学习是非常广泛的,几乎你想实现任何基于CNN的应用都应该首先尝试进行迁移学习。根据你训练集的大小可以选择不同的迁移学习方式:
比如你的数据集很小,可以使用其他人的网络结构和参数,只把输出层替换为你自己需要的,比如你想三分类则替换为一个三分类Softmax输出层,然后锁住前序所有weight,只使用反向传播更新输出层的参数;同时你可以针对每个数据集将前序固定了的层的输出计算好之后作为缓存,因为参数不变输出不变,然后使用缓存结果在多轮迭代中更新输出层参数。
如果你的数据集中等大小,可以尝试下载其他人的网络和参数,锁定前面几层的参数,训练后面几层及你自己的输出层,也可以把后面几层替换为你自己的网络结构,从头训练后面的网络结构。
如果你的数据集非常大,则可以下载别人的模型,仅使用下载的参数作为初始化,全部重新训练。
数据增强
在CV领域,模型对于训练集数据量的需求是非常大的,数据增强在CV模型训练里面是十分常用的方式去提示模型的性能。以为数据增强的方式很多,超参也很多,也是建议参考网上现成的实现。
常用手段:镜像、随机裁剪、旋转、剪切变换、局部变形等。前两个最常用。
第二类:色彩偏移,还可以使用PCA color augmentation,分析主色彩,然后对主色彩进行大幅度的调整,在AlexNet论文中有详细描述。
Computer Vision现状
当你有足够的数据的时候,你可以使用更简单成熟的算法,而不需要很多hand engineering,当你数据很少时,往往意味着你需要很多hand engineering。数据、hand engineering是两种可以提供给模型的知识来源。数据少的时候也可以使用迁移学习。
课程还给了几个提高打榜成绩的方式,但是在生产中不怎么会用到,看看就好。