如今深度学习发展火热,但很多优秀的文章都是基于经典文章,经典文章中的一句一词都值得推敲和分析.此外,深度学习虽然一直被人诟病缺乏足够令人信服的理论,但不代表我们不能感性分析理解,下面我们将对 2014 年夺得 ImageNet 的定位第一和分类第二的 VGG 网络进行分析,在此过程中更多的是对这篇经典文章的感性分析,希望和大家共同交流产生共鸣,如果有理解不到位的也真诚期待指出错误.
Simonyan, Karen, and Andrew Zisserman. "Very deep convolutional networks for large-scale image recognition." arXiv preprint arXiv:1409.1556 (2014).
论文下载地址: https://arxiv.org/pdf/1409.1556.pdf
这篇文章是以比赛为目的——解决 ImageNet 中的 1000 类图像分类和定位问题.在此过程中,作者做了六组实验,对应 6 个不同的网络模型,这六个网络深度逐渐递增的同时,也有各自的特点.实验表明最后两组,即深度最深的两组 16 和 19 层的 VGGNet 网络模型在分类和定位任务上的效果最好.作者因此斩获 2014 年分类第二(第一是 GoogLeNet),定位任务第一.
其中,模型的名称——"VGG" 代表了牛津大学的 Oxford Visual Geometry Group,该小组隶属于 1985 年成立的 Robotics Research Group,该 Group 研究范围包括了机器学习到移动机器人.下面是一段来自知乎对同年 GoogLeNet 和 VGG 的描述:
GoogLeNet 和 VGG 的 Classification 模型从原理上并没有与传统的 CNN 模型有太大不同.大家所用的 Pipeline 也都是:训练时候:各种数据 Augmentation(剪裁,不同大小,调亮度,饱和度,对比度,偏色),剪裁送入 CNN 模型,Softmax,Backprop.测试时候:尽量把测试数据又各种 Augmenting(剪裁,不同大小),把测试数据各种 Augmenting 后在训练的不同模型上的结果再继续 Averaging 出最后的结果.
需要注意的是,在 VGGNet 的 6 组实验中,后面的 4 个网络均使用了 pre-trained model A 的某些层来做参数初始化.虽然作者没有提该方法带来的性能增益,但我认为是很大的.不过既然是开篇,先来看看 VGG 的特点:
小卷积核.作者将卷积核全部替换为 3x3(极少用了 1x1);
小池化核.相比 AlexNet 的 3x3 的池化核,VGG 全部为 2x2 的池化核;
层数更深特征图更宽.基于前两点外,由于卷积核专注于扩大通道数,池化专注于缩小宽和高,使得模型架构上更深更宽的同时,计算量的增加放缓;
全连接转卷积.网络测试阶段将训练阶段的三个全连接替换为三个卷积,测试重用训练时的参数,使得测试得到的全卷积网络因为没有全连接的限制,因而可以接收任意宽或高为的输入.
最后我会再次引用 CS231n 对于 VGG 的中肯评价进行总结,不过还是先从当时的任务和历史背景开始说明.
任务背景
自从 2012 年 AlexNet 将深度学习的方法应用到 ImageNet 的图像分类比赛中并取得 state of the art 的惊人结果后,大家都竞相效仿并在此基础上做了大量尝试和改进,先从两个性能提升的例子说起:
小卷积核.在第一个卷积层用了更小的卷积核和卷积 stride(Zeiler & Fergus, 2013; Sermanet et al., 2014);
多尺度.训练和测试使用整张图的不同尺度(Sermanet et al., 2014; Howard, 2014).
作者也是看到这两个没有谈到深度的工作,因而受到启发,不仅将上面的两种方法应用到自己的网络设计和训练测试阶段,同时想再试试深度对结果的影响.
小卷积核
说到网络深度,这里就不得不提到卷积,虽然 AlexNet 有使用了 11x11 和 5x5 的大卷积,但大多数还是 3x3 卷积,对于 stride=4 的 11x11 的大卷积核,我认为在于一开始原图的尺寸很大因而冗余,最为原始的纹理细节的特征变化用大卷积核尽早捕捉到,后面的更深的层数害怕会丢失掉较大局部范围内的特征相关性,后面转而使用更多 3x3 的小卷积核(和一个 5x5 卷积)去捕捉细节变化.
而 VGGNet 则清一色使用 3x3 卷积.因为卷积不仅涉及到计算量,还影响到感受野.前者关系到是否方便部署到移动端,是否能满足实时处理,是否易于训练等,后者关系到参数更新,特征图的大小,特征是否提取的足够多,模型的复杂度和参数量等等.
计算量
在计算量这里,为了突出小卷积核的优势,我拿同样 conv3x3,conv5x5,conv7x7,conv9x9 和 conv11x11,在 224x224x3 的 RGB 图上(设置 pad=1,stride=4,output_channel=96)做卷积,卷积层的参数规模和得到的 feature map 的大小如下:
从上表可以看出,大卷积核带来的特征图和卷积核得参数量并不大,无论是单独去看卷积核参数或者特征图参数,不同 kernel 大小下这二者加和的结构都是 30 万的参数量,也就是说,无论大的卷积核还是小的,对参数量来说影响不大甚至持平.
增大的反而是卷积的计算量,在表格中列出了计算量的公式,最后要乘以 2,代表乘加操作.为了尽可能证一致,这里所有卷积核使用的 stride 均为 4,可以看到,conv3x3,conv5x5,conv7x7,conv9x9,conv11x11 的计算规模依次为:1600 万,4500 万,1.4 亿,2 亿,这种规模下的卷积,虽然参数量增长不大,但是计算量是惊人的.
总结一下,我们可以得出两个结论:
同样 stride 下,不同卷积核大小的特征图和卷积参数差别不大;
越大的卷积核计算量越大.
其实对比参数量,卷积核参数的量级在十万,一般都不会超过百万.相比全连接的参数规模是上一层的 feature map 和全连接的神经元个数相乘,这个计算量也就更大了.其实一个关键的点——多个小卷积核的堆叠比单一大卷积核带来了精度提升,这也是最重要的一点.
感受野
说完了计算量我们再来说感受野.这里给出一张 VGG 作者的 PPT,作者在 VGGNet 的实验中只用了两种卷积核大小:1x1 和 3x3.作者认为两个 3x3 的卷积堆叠获得的感受野大小,相当一个 5x5 的卷积;而 3 个 3x3 卷积的堆叠获取到的感受野相当于一个 7x7 的卷积.
见下图,输入的 8 个元素可以视为 feature map 的宽或者高,当输入为 8 个神经元经过三层 conv3x3 的卷积得到 2 个神经元.三个网络分别对应 stride=1,pad=0 的 conv3x3,conv5x5 和 conv7x7 的卷积核在 3 层,1 层,1 层时的结果.因为这三个网络的输入都是 8,也可看出 2 个 3x3 的卷积堆叠获得的感受野大小,相当 1 层 5x5 的卷积;而 3 层的 3x3 卷积堆叠获取到的感受野相当于一个 7x7 的卷积.
input=8,3 层 conv3x3 后,output=2,等同于 1 层 conv7x7 的结果;
input=8,2 层 conv3x3 后,output=2,等同于 2 层 conv5x5 的结果.
或者我们也可以说,三层的 conv3x3 的网络,最后两个输出中的一个神经元,可以看到的感受野相当于上一层是 3,上上一层是 5,上上上一层(也就是输入)是 7.
此外,倒着看网络,也就是 backprop 的过程,每个神经元相对于前一层甚至输入层的感受野大小也就意味着参数更新会影响到的神经元数目.在分割问题中卷积核的大小对结果有一定的影响,在上图三层的 conv3x3 中,最后一个神经元的计算是基于第一层输入的 7 个神经元,换句话说,反向传播时,该层会影响到第一层 conv3x3 的前 7 个参数.从输出层往回 forward 同样的层数下,大卷积影响(做参数更新时)到的前面的输入神经元越多.
优点
既然说到了 VGG 清一色用小卷积核,结合作者和自己的观点,这里整理出小卷积核比用大卷积核的三点优势:
更多的激活函数,更丰富的特征,更强的辨别能力.卷积后都伴有激活函数,更多的卷积核的使用可使决策函数更加具有辨别能力,此外就卷积本身的作用而言,3x3 比 7x7 就足以捕获特征的变化:3x3 的 9 个格子,最中间的格子是一个感受野中心,可以捕获上下左右以及斜对角的特征变化.主要在于 3 个堆叠起来后,三个 3x3 近似一个 7x7,网络深了两层且多出了两个非线性 ReLU 函数,(特征多样性和参数参数量的增大)使得网络容量更大(关于 model capacity,AlexNet 的作者认为可以用模型的深度和宽度来控制 capacity),对于不同类别的区分能力更强(此外,从模型压缩角度也是要摒弃 7x7,用更少的参数获得更深更宽的网络,也一定程度代表着模型容量,后人也认为更深更宽比矮胖的网络好);
卷积层的参数减少.相比 5x5,7x7 和 11x11 的大卷积核,3x3 明显地减少了参数量,这点可以回过头去看上面的表格.比方 input channel 数和 output channel 数均为 C,那么 3 层 conv3x3 卷积所需要的卷积层参数是:3x(Cx3x3xC)=27C^2,而一层 conv7x7 卷积所需要的卷积层参数是:Cx7x7xC=49C^2.conv7x7 的卷积核参数比 conv3x3 多了 (49-27)/27x100% ≈ 81%;
小卷积核代替大卷积核的正则作用带来性能提升.作者用三个 conv3x3 代替一个 conv7x7,认为可以进一步分解(decomposition)原本用 7x7 大卷积核提到的特征,这里的分解是相对于同样大小的感受野来说的.关于正则的理解我觉得还需要进一步分析.
其实最重要的还是多个小卷积堆叠在分类精度上比单个大卷积要好.
小池化核
这里的 "小" 是相对于 AlexNet 的 3x3 的池化核来说的.不过在说池化前,先说一下 CS231n 的博客里的描述网络结构的 layer pattern,一般常见的网络都可以表示为:INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC 的形式,其中,? 表示 pool 是一个可选项.这样的 pattern 因为可以对小卷积核堆叠,很自然也更适合描述深层网络的构建,例如 INPUT -> FC 表示一个线性分类器.
不过从 layer pattern 中的 [[CONV -> RELU]*N -> POOL?]*M 部分,可以看出卷积层一般后面接完激活函数就紧跟池化层.对于这点我的理解是,池化做的事情是根据对应的 max 或者 average 方式进行特征筛选,还是在做特征工程上的事情.
2012 年的 AlexNet,其 pooling 的 kernel size 全是奇数,里面所有池化采用 kernel size 为 3x3,stride 为 2 的 max-pooling.而 VGGNet 所使用的 max-pooling 的 kernel size 均为 2x2,stride 为 2 的 max-pooling.pooling kernel size 从奇数变为偶数.小 kernel 带来的是更细节的信息捕获,且是 max-pooling 更见微的同时进一步知躇.
在当时也有 average pooling,但是在图像任务上 max-pooling 的效果更胜一筹,所以图像大多使用 max-pooling.在这里我认为 max-pooling 更容易捕捉图像上的变化,梯度的变化,带来更大的局部信息差异性,更好地描述边缘,纹理等构成语义的细节信息,这点尤其体现在网络可视化上.
概述全连接和特征图
全连接
VGG 最后三个全连接层在形式上完全平移 AlexNet 的最后三层,VGGNet 后面三层(三个全连接层)为:
FC4096-ReLU6-Drop0.5,FC 为高斯分布初始化(std=0.005),bias 常数初始化(0.1)
FC4096-ReLU7-Drop0.5,FC 为高斯分布初始化(std=0.005),bias 常数初始化(0.1)
FC1000(最后接 SoftMax1000 分类),FC 为高斯分布初始化(std=0.005),bias 常数初始化(0.1)
超参数上只有最后一层 fc 有变化:bias 的初始值,由 AlexNet 的 0 变为 0.1,该层初始化高斯分布的标准差,由 AlexNet 的 0.01 变为 0.005.超参数的变化,我的理解是,作者自己的感性理解指导认为,我以贡献 bias 来降低标准差,相当于标准差和 bias 间 trade-off,或许作者实验 validate 发现这个值比之前 AlexNet 设置的(std=0.01,bias=0)要更好.
特征图
网络在随层数递增的过程中,通过池化也逐渐忽略局部信息,特征图的宽度高度随着每个池化操作缩小 50%,5 个池化 l 操作使得宽或者高度变化过程为:224->112->56->28->14->7,但是深度 depth(或说是 channel 数),随着 5 组卷积在每次增大一倍:3->64->128->256->512->512.特征信息从一开始输入的 224x224x3 被变换到 7x7x512,从原本较为 local 的信息逐渐分摊到不同 channel 上,随着每次的 conv 和 pool 操作打散到 channel 层级上.
特征图的宽高从 512 后开始进入全连接层,因为全连接层相比卷积层更考虑全局信息,将原本有局部信息的特征图(既有 width,height 还有 channel)全部映射到 4096 维度.也就是说全连接层前是 7x7x512 维度的特征图,估算大概是 25000,这个全连接过程要将 25000 映射到 4096,大概是 5000,换句话说全连接要将信息压缩到原来的五分之一.VGGNet 有三个全连接,我的理解是作者认为这个映射过程的学习要慢点来,太快不易于捕捉特征映射来去之间的细微变化,让 backprop 学的更慢更细一些(更逐渐).
换句话说,维度在最后一个卷积后达到 7x7x512,即大概 25000,紧接着压缩到 4096 维,可能是作者认为这个过程太急,又接一个 fc4096 作为缓冲,同时两个 fc4096 后的 relu 又接 dropout0.5 去过渡这个过程,因为最后即将给 1k-way softmax,所以又接了一个 fc1000 去降低 softmax 的学习压力.
feature map 维度的整体变化过程是:先将 local 信息压缩,并分摊到 channel 层级,然后无视 channel 和 local,通过 fc 这个变换再进一步压缩为稠密的 feature map,这样对于分类器而言有好处也有坏处,好处是将 local 信息隐藏于 / 压缩到 feature map 中,坏处是信息压缩都是有损失的,相当于 local 信息被破坏了(分类器没有考虑到,其实对于图像任务而言,单张 feature map 上的 local 信息还是有用的).
但其实不难发现,卷积只增加 feature map 的通道数,而池化只减少 feature map 的宽高.如今也有不少做法用大 stride 卷积去替代池化,未来可能没有池化.
卷积组
说到特征图的变化,我们可以进一步切分网络观察整体结构,再次拿出 CS231n 的博客里的描述网络结构的 layer pattern:INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC,以 pooling 操作为切分点对整个网络分组的话,我们会得到五组卷积,五组卷积中有 2 种卷积组的形式,切分后的 VGG 网络可以描述成下面这样:
前两组卷积形式一样,每组都是:conv-relu-conv-relu-pool;
中间三组卷积形式一样,每组都是:conv-relu-conv-relu-conv-relu-pool;
最后三个组全连接 fc 层,前两组 fc,每组都是:fc-relu-dropout;最后一个 fc 仅有 fc.
虽然 CS231n 里将这种形式称为 layer pattern,但我更喜欢把以卷积起始池化为止的最短结构称之为 "卷积组".
不难发现 VGG 有两种卷积组,第二种([conv-relu]-[conv-relu]-[conv-relu]-pool)比第一种([conv-relu]-[conv-relu]-pool) 多了一个 [conv-relu].我的理解是:
多出的 relu 对网络中层进一步压榨提炼特征.结合一开始单张 feature map 的 local 信息更多一些,还没来得及把信息分摊到 channel 级别上,那么往后就慢慢以增大 conv filter 的形式递增地扩大 channel 数,等到了网络的中层,channel 数升得差不多了(信息分摊到 channel 上得差不多了),那么还想抽 local 的信息,就通过再加一个 [conv-relu] 的形式去压榨提炼特征.有点类似传统特征工程中,已有的特征在固定的模型下没有性能提升了,那就用更多的非线性变换对已有的特征去做变换,产生更多的特征的意味;
多出的 conv 对网络中层进一步进行学习指导和控制不要将特征信息漂移到 channel 级别上.
上一点更多的是 relu 的带来的理解,那么多出的 [conv-relu] 中 conv 的意味就是模型更强的对数据分布学习过程的约束力 / 控制力,做到信息 backprop 可以回传回来的学习指导.本身多了 relu 特征变换就加剧(权力释放),那么再用一个 conv 去控制(权力回收),也在指导网络中层的收敛;
其实 conv 本身关注单张 feature map 上的局部信息,也是在尝试去尽量平衡已经失衡的 channel 级别(depth)和 local 级别(width,height)之间的天平.这个 conv 控制着特征的信息量不要过于向着 channel 级别偏移.
关于 Layer pattern,CS231n 的博客给出如下观点:
串联和串联中带有并联的网络架构.近年来,GoogLeNet 在其网络结构中引入了 Inception 模块,ResNet 中引入了 Residual Block,这些模块都有自己复杂的操作.换句话说,传统一味地去串联网络可能并不如这样串联为主线,带有一些并联同类操作但不同参数的模块可能在特征提取上更好. 所以我认为这里本质上依旧是在做特征工程,只不过把这个过程放在 block 或者 module 的小的网络结构里,毕竟 kernel,stride,output 的大小等等超参数都要自己设置,目的还是产生更多丰富多样的特征.
用在 ImageNet 上 pre-trained 过的模型.设计自己模型架构很浪费时间,尤其是不同的模型架构需要跑数据来验证性能,所以不妨使用别人在 ImageNet 上训练好的模型,然后在自己的数据和问题上在进行参数微调,收敛快精度更好. 我认为只要性能好精度高,选择什么样的模型架构都可以,但是有时候要结合应用场景,对实时性能速度有要求的,可能需要多小网络,或者分级小网络,或者级联的模型,或者做大网络的知识蒸馏得到小网络,甚至对速度高精度不要求很高的,可以用传统方法.
层维度
要说到 layer pattern,不得不提到 sizing pattern,其实这里相当于前面 feature map 维度变化的补充,这也是 CS231n 里所讲到的.对于每种层,有不同的默认设定:
输入层
大都是 2 的 N 次方,这和网络中卷积或者池化层出现的 stride 为 2 的次数有关,比方 VGGNet 中每个 pattern 的卷积不会对 feature map 的宽度和高度有改变,而每个 pattern 结束前总会做一个 stride 为 2 的下采样,因为有 5 组,那么做 5 次就是 32,所以 VGGNet 网络 input 大小一般都是 32 的倍数,即,n 是下采样的次数,a 是最终卷积和池化得到的 feature map 大小,如 224 或者 384.
卷积层
现在常用的是小卷积核如 3x3 或者 1x1.卷积为了保留 feature map 不变,通常会采取 pad 为 1 的操作,其实具体来说应该是:为了保证卷积后的 feature map 的宽度和高度不变,那么有 pad=(F-1)/2,但我觉得这个有点问题,可以改成更一般的形式,不过首先可以看看计算下一层 feature map 宽高的公式:
因为要保证和一样,有,那么可以导出:
当 Stride=1 时,那么 pad=(F-1)/2.因为现在 stride=1 的 3x3 卷积用的多,所以大家会默认说是 pad=1(关于这点上,也是由于实验发现这样保留 feature map 的宽高情况下,性能好的缘故,我认为填补主要是针对 stride 大于 1 的情况带来的边界问题,如果 input 尺寸不是事先设定的,那么就会有边界无法卷积到的问题带来信息丢失.不过这种填补我认为也有一定问题,就是说原本 conv3x3 去计算对应位置的 3x3,而填补后为 0,这样相当于少算了一些值,这肯定还是有影响的).但若 stride 不是 1,那么要保证前后 feature map 的宽高一样,就要根据上面的公式计算得出.
另一个点是通常与 Input 比较接近的 conv 会采用大卷积核.关于接近 input 层使用较大的卷积核这点,我认为先是考虑到后面的操作,先尽可能用大的卷积核 cover 更多的原始信息(虽然经过了卷积有一些变换),第二点在于大卷积核带来的大感受野,后面的卷积层能的一个神经元能看到更大的 input,第三点是 GPU 的显存受限,经典的例子就是 AlexNet 使用 stride=4 的 conv11x11,目的就是从一开始就减少显存占用,其实这里的大 stride,我觉得起到了一些正则的作用.但缺点也很明显,因为卷积核变大,矩阵乘法实现卷积时,若没有大 stride,那么第一个矩阵的列数,也就是第二个矩阵的行数,会变大,带来大的计算量.所以在 AlexNet 中,大卷积核也对应使用了大的 stride 值.
池化层
常见 2x2 的 max-pooling,少见 3x3 或者更大的 kernel.更大的 kernel 带来的问题是信息丢失带来的信息损失,此外,stride 通常为 2;
其实按照以上的设定看来,也是有好处的.卷积专注于保留空间信息前提下的 channel 变换,而池化则专注于空间信息的变换(下采样).
全连接转卷积
VGG 比较神奇的一个特点就是 "全连接转卷积",下面是作者原文 test 小节中的一句:
Namely, the fully-connected layers are first converted to convolutional layers (the first FC layer to a 7 × 7 conv. layer, the last two FC layers to 1 × 1 conv. layers).
也就是说,作者在测试阶段把网络中原本的三个全连接层依次变为 1 个 conv7x7,2 个 conv1x1,也就是三个卷积层.改变之后,整个网络由于没有了全连接层,网络中间的 feature map 不会固定,所以网络对任意大小的输入都可以处理,因而作者在紧接着的后一句说到: The resulting fully-convolutional net is then applied to the whole (uncropped) image.
上图是 VGG 网络最后三层的替换过程,上半部分是训练阶段,此时最后三层都是全连接层(输出分别是 4096,4096,1000),下半部分是测试阶段(输出分别是 1x1x4096,1x1x4096,1x1x1000),最后三层都是卷积层.下面我们来看一下详细的转换过程(以下过程都没有考虑 bias,略了):
先看训练阶段,有 4096 个输出的全连接层 FC6 的输入是一个 7x7x512 的 feature map,因为全连接层的缘故,不需要考虑局部性, 可以把 7x7x512 看成一个整体,25508(=7x7x512)个输入的每个元素都会与输出的每个元素(或者说是神经元)产生连接,所以每个输入都会有 4096 个系数对应 4096 个输出,所以网络的参数(也就是两层之间连线的个数,也就是每个输入元素的系数个数)规模就是 7x7x512x4096.对于 FC7,输入是 4096 个,输出是 4096 个,因为每个输入都会和输出相连,即每个输出都有 4096 条连线(系数),那么 4096 个输入总共有 4096x4096 条连线(系数),最后一个 FC8 计算方式一样,略.
再看测试阶段,由于换成了卷积,第一个卷积后要得到 4096(或者说是 1x1x4096)的输出,那么就要对输入的 7x7x512 的 feature map 的宽高(即 width,height 维度)进行降维,同时对深度(即 Channel/depth 维度)进行升维.要把 7x7 降维到 1x1,那么干脆直接一点,就用 7x7 的卷积核就行,另外深度层级的升维,因为 7x7 的卷积把宽高降到 1x1,那么刚好就升高到 4096 就好了,最后得到了 1x1x4096 的 feature map.这其中卷积的参数量上,把 7x7x512 看做一组卷积参数,因为该层的输出是 4096,那么相当于要有 4096 组这样 7x7x512 的卷积参数,那么总共的卷积参数量就是:
[7x7x512]x4096,这里将 7x7x512 用中括号括起来,目的是把这看成是一组,就不会懵.
第二个卷积依旧得到 1x1x4096 的输出,因为输入也是 1x1x4096,三个维度(宽,高,深)都没变化,可以很快计算出这层的卷积的卷积核大小也是 1x1,而且,通道数也是 4096,因为对于输入来说,1x1x4096 是一组卷积参数,即一个完整的 filter,那么考虑所有 4096 个输出的情况下,卷积参数的规模就是 [1x1x4096]x4096.第三个卷积的计算一样,略.
其实 VGG 的作者把训练阶段的全连接替换为卷积是参考了 OverFeat 的工作,如下图是 OverFeat 将全连接换成卷积后,带来可以处理任意分辨率(在整张图)上计算卷积,而无需对原图 resize 的优势.
不过可以看到,训练阶段用的是 crop 或者 resize 到 14x14 的输入图像,而测试阶段可以接收任意维度,如果使用未经 crop 的原图作为输入(假设原图比 crop 或者 resize 到训练尺度的图像要大),这会带来一个问题:feature map 变大了.比方 VGG 训练阶段用 224x224x3 的图作为模型输入,经过 5 组卷积和池化,最后到 7x7x512 维度,最后经过无论是三个卷积或者三个全连接,维度都会到 1x1x4096->1x1x4096->1x1x1000,而使用 384x384x3 的图做模型输入,到五组卷积和池化做完(即),那么 feature map 变为 12x12x512,经过三个由全连接变的三个卷积,即 feature map 经历了 6x6x4096->6x6x4096->6x6x1000 的变化过程后,再把这个 6x6x1000 的 feature map 进行 average,最终交给 SoftMax 的是 1x1x1000 的 feature map 进行分类.
以上便是将全连接转换成卷积以及将转换后的全卷积网络应用到测试阶段的方式.其实进一步来看卷积与全连接,二者最明显的差异不外乎一个前者是局部连接,但其实二者都有用到全局信息,只是卷积是通过层层堆叠来利用的,而全连接就不用说了,全连接的方式直接将上一层的特征图全部用上,稀疏性比较大,而卷积从网络深度这一角度,基于输入到当前层这一过程逐级逐层榨取的方式利用全局信息.
1x1 卷积
VGG 在最后的三个阶段都用到了 1x1 卷积核,选用 1x1 卷积核的最直接原因是在维度上继承全连接,然而作者首先认为 1x1 卷积可以增加决策函数(decision function,这里的决策函数我认为就是 softmax)的非线性能力,非线性是由激活函数 ReLU 决定的,本身 1x1 卷积则是线性映射,即将输入的 feature map 映射到同样维度的 feature map.作者还提到 "Network in Network" architecture of Lin et al. (2014). 这篇文章就大量使用了 1x1 卷积核.
此外,查了知乎简单总结下 1x1 卷积的特点(就不说加入非线性这个 conv 自带的特点了):
专注于跨通道的特征组合:conv1x1 根本不考虑单通道上像素的局部信息(不考虑局部信息),专注于那一个卷积核内部通道的信息整合.conv3x3 既考虑跨通道,也考虑局部信息整合;
对 feature map 的 channel 级别降维或升维:例如 224x224x100 的图像(或 feature map)经过 20 个 conv1x1 的卷积核,得到 224x224x20 的 feature map.尤其当卷积核(即 filter)数量达到上百个时,3x3 或 5x5 卷积的计算会非常耗时,所以 1x1 卷积在 3x3 或 5x5 卷积计算前先降低 feature map 的维度.
关于小卷积核前人就有使用,如 Ciresan et al. (2011) 还有 Goodfellow et al. (2014),后者使用 11 层的网络解决街道数量的识别问题(street number classification,我也没看懂是回归还是分类),结果显示更深的网络可以带来更好地网络性能.而作者在小卷积核的基础上使用了更多层数,2014 年 ImageNet 分类比赛的第一名使用 GoogLeNet,Szegedy et al., (2014) 也使用了更小的卷积核,更深达到 22 层的网络,使用了 5x5,3x3 和 1x1 卷积(实际还用到了 7x7 的卷积,第一层卷积).但 GoogLeNet 的拓扑结构比较复杂,上图是 Inception module 的结构图,可以看到 module 内直接使用了常见的三种卷积核进行并联,并将最后的结果 feature map 直接 concate 到一起,而 VGGNet 则是使用传统卷积核串联的方式.
然而,分类性能上同样的单模型,VGGNet 比 GoogLeNet 在 top5 的错分率要低,虽然不确定是否是因为 GoogLeNet 没做 multi-crop 和 dense eval.,但假设他们都做了,这样看来似乎 VGG 从实验结果上表现出其结构设计上比 GoogLeNet 更适合解决分类问题.
但总之,这种将全连接转成卷积的方式还是很有意思的.但转换后是直接拿来用先前的参数好还是否需要做参数微调转换后的卷积层,还需要实验说明.
实验结论和评价
12 年到 14 年的挑战赛都使用的是 1000 个类别的 ILSVRC-2012 数据集(Large Scale Visual Recognition Challenge),其中:
训练集:130 万张图片;
验证集:5 万张图片;
测试集:10 万张图片,这组数据的 label 没有给出(with held-out class labels).
两个性能评估准则:top-1 和 top-5 error.前一个是多类分类错误率,错分的图像的比率.后一个是 ILSVRC 中主要的评估指标,计算的是预测出来的 top5 的类别里没有 ground truth 的比率,即 top-5 error.
实验结论
因为作者自己在下面实验的缘故,当然没有测试集的 ground truth 类别,所以作者就用验证集当做测试集来观察模型性能.这里作者使用两种方式来评估模型在测试集(实际的验证集)的性能表现:single scale evaluation 和 multi-scale evaluation.实验结论:
LRN 层无性能增益(A 和 A-LRN).作者通过网络 A 和 A-LRN 发现 AlexNet 曾经用到的 LRN 层(local response normalization,LRN 是一种跨通道去 normalize 像素值的方法)没有性能提升,因此在后面的 4 组网络中均没再出现 LRN 层. 当然我也感觉没啥用,想到 max-pooling 比 average-pooling 效果好,我就感觉这个 LRN 没啥用,不过如果把 LRN 改成跨通道的 max-normal,我感觉说不定会有性能提升.特征得到 retain 更明显.
深度增加,分类性能提高(A,B,C,D,E).从 11 层的 A 到 19 层的 E,网络深度增加对 top1 和 top5 的 error 下降很明显,所以作者得出这个结论,但其实除了深度外,其他几个网络宽度等因素也在变化,depth matters 的结论不够 convincing.
conv1x1 的非线性变化有作用(C 和 D).C 和 D 网络层数相同,但 D 将 C 的 3 个 conv3x3 换成了 conv1x1,性能提升.这点我理解是,跨通道的信息交换 / 融合,可以产生丰富的特征易于分类器学习.conv1x1 相比 conv3x3 不会去学习 local 的局部像素信息,专注于跨通道的信息交换 / 融合,同时为后面全连接层(全连接层相当于 global 卷积)做准备,使之学习过程更自然.
多小卷积核比单大卷积核性能好(B).作者做了实验用 B 和自己一个不在实验组里的较浅网络比较,较浅网络用 conv5x5 来代替 B 的两个 conv3x3.多个小卷积核比单大卷积核效果好,换句话说当考虑卷积核大小时:depths matters.
评价
最后贴出 CS231n 的评价:
The runner-up in ILSVRC 2014 was the network from Karen Simonyan and Andrew Zisserman that became known as the VGGNet. Its main contribution was in showing that the depth of the network is a critical component for good performance. Their final best network contains 16 CONV/FC layers and, appealingly, features an extremely homogeneous architecture that only performs 3x3 convolutions and 2x2 pooling from the beginning to the end. Their pretrained model is available for plug and play use in Caffe. A downside of the VGGNet is that it is more expensive to evaluate and uses a lot more memory and parameters (140M). Most of these parameters are in the first fully connected layer, and it was since found that these FC layers can be removed with no performance downgrade, significantly reducing the number of necessary parameters.
不难提炼出如下结论:
深度提升性能;
最佳模型:VGG16,从头到尾只有 3x3 卷积与 2x2 池化.简洁优美;
开源 pretrained model.与开源深度学习框架 Caffe 结合使用,助力更多人来学习;
卷积可代替全连接.整体参数达 1 亿 4 千万,主要在于第一个全连接层,用卷积来代替后,参数量下降(这里的说法我认为是错的,替代前后用同样的输入尺寸,网络参数量,feature map,计算量三者没有变化)且无精度损失.
参考
以下是一些参考文献,虽然不少地方引用了,但是偷懒没有在文中具体标明.老实说,有时间能看原汁原味的东西就不要看别人吃过的,即使是我写的这篇,看原版的东西我觉得收获更大一些.
ILSVRC-2014 presentation http://www.robots.ox.ac.uk/~karen/pdf/ILSVRC_2014.pdf
http://cs231n.stanford.edu/slides/2017/cs231n_2017_lecture9.pdf
Convolutional neural networks on the iPhone with VGGNet http://machinethink.net/blog/convolutional-neural-networks-on-the-iphone-with-vggnet/
A Matlab Toolkit for Distance Metric Learning http://www.cs.cmu.edu/~liuy/distlearn.htm
图像处理中的 L1-normalize 和 L2-normalize - CSDN 博客 注:公式写错了 http://blog.csdn.net/a200800170331/article/details/21737741
Feature Visualization https://distill.pub/2017/feature-visualization/#enemy-of-feature-vis
TensorFlow 教程 #14 - DeepDream(多图预警) https://zhuanlan.zhihu.com/p/27546601
caffe/pooling_layer.cpp at 80f44100e19fd371ff55beb3ec2ad5919fb6ac43 · BVLC/caffe https://github.com/BVLC/caffe/blob/80f44100e19fd371ff55beb3ec2ad5919fb6ac43/src/caffe/layers/pooling_layer.cpp
VGG 网络中测试时为什么全链接改成卷积? - 知乎 https://www.zhihu.com/question/53420266
pooling mean max 前向和反向传播 - CSDN 博客 http://blog.csdn.net/junmuzi/article/details/53206600
caffe/pooling_layer.cpp at 80f44100e19fd371ff55beb3ec2ad5919fb6ac43 · BVLC/caffe https://github.com/BVLC/caffe/blob/80f44100e19fd371ff55beb3ec2ad5919fb6ac43/src/caffe/layers/pooling_layer.cpp
Deep learning:四十七 (Stochastic Pooling 简单理解) - tornadomeet - 博客园 https://www.cnblogs.com/tornadomeet/p/3432093.html
Convolutional Neural Networks - Basics · Machine Learning Notebook https://mlnotebook.github.io/post/CNN1/
在 Caffe 中如何计算卷积? - 知乎 https://www.zhihu.com/question/28385679
High Performance Convolutional Neural Networks for Document Processing Kumar Chellapilla, Sidd Puri, Patrice Simard https://hal.archives-ouvertes.fr/file/index/docid/112631/filename/p1038112283956.pdf
作者简介:开心的派大星,初级高性能计算工程师,目前就职于一家人工智能创业公司,目前从事于移动端深度学习性能优化.喜欢动漫,骑车,画画.博客地址:yuenshome.cn.
来源: http://blog.csdn.net/qq_40027052/article/details/79015827