论文分析与复现-VGG:Very Deep Convolutional Networks for Large-scale Image Recognition

论文阅读方法

三遍论文法

第一遍(摘要+简介+结论)

在这里插入图片描述
初步结论:由于大量开放的数据图像库(ImgNet)以及好性能的计算系统(GPU)的存在,目前卷积神经网络在大尺度图像和视频分类取得了很大的成功。这篇论文主要探索了‘深度’对神经网络性能的影响,并且验证了在卷积核大小为3x3的网络上,把网络层数叠加到16-19层会使得网络性能得到显著的提升。这种方法也能推广到其他数据集上。

第二遍(分段阅读)

Part 2:Convnet Configurations

在这里插入图片描述
其实网络的基本配置和AlexNet差不多,只是相比于AlexNet,使用的卷积核更小(3x3)并且没有应用LRN(局部相应归一化)。关于ALexNet的具体网络配置可以看我另一篇博文:AlexNet
在这里插入图片描述
基于上面的网络配置,作者建立了A-E几个模型,图中省略了ReLU层。
在这里插入图片描述
然后作者就配置进行了讨论:
1)7x7的卷积和3个3x3的卷积感受野实际上是一样的,那为什么要用小卷积来代替大卷积呢?

  • 首先,增加了非线性单元,因为每个卷积核后面都会接一个ReLU层,这会使得判别函数更具有判断性;
  • 其次,减少了参数量一个7x7卷积的参数量为:77,而3个33的卷积为3 * 3 * 3;
  • 这样的操作相当于对7x7的卷积强行加了正则化,迫使其分解。
    2)1x1的卷积用来干嘛的?
  • 在之前1x1卷积都是用来在不改变视图的情况下增加非线性的,但是我们为了对比多一层ReLU的作用,所以仅仅作为线性映射,非线性又ReLU来提供。
  • 实际上在后面的应用中,1x1的卷积通常用来融合通道间的信息并改变通道数。
Part3. Classification Framework

在这里插入图片描述
这里主要就是讲训练和测试的细节了,首先是训练

  • 相比于ALexNet,VGG所需要的训练epoch更少,作者认为有两点原因:主要是用了更深的网络和更小的卷积核;其次就是作者的训练策略,使得某些层用了预训练参数(模型A网络不够深,所以使用随机初始化训练,在训练更深的网络之前,前四层卷积层和后三层全连接层使用A的参数来代替)。
  • 在训练时,令图像的最小边长为S,使用两种方法来设定,一个是固定其大小:256/384,另一个方法是从[Smin, Smax]中随机采样。

接来下是预测

  • 预测时,作者将全连接层全部改为了卷积层(第一个卷积层为7x7卷积,后两个卷积层为1x1卷积),输出将会得到一个score map得分图,对得分图做平均从而得到最后的类别概率。
  • 这个地方我一开始有点不明白:在测试的时候才把全连接层改成了卷积层,那么卷积层的参数哪里来的呢? 其实,卷积层的参数就是来自于全连接层,第一个全连接层得到7x7x512的feature map,然后参数应该是7x7x512x4096,将其改为7x7x512卷积(4096个filters),参数也是7x7x512x4096,这时卷积相当于执行一个全连接操作,直接将全连接层对应的参数复制到卷积层即可。后面的两个层也是类似的思路。
  • 接下来作者还提到了一个dense evaluation和multi-crop evaluation两种方法,并认为这两个方法是互补的:multi-crop的卷积特征图是由0填充的,然而dense是来自图像上相邻位置的自然填充,这增加了感受野,捕获了更多上下文。
  • multi-crop的卷积特征图是由0填充的,然而dense是来自图像上相邻位置的自然填充,这增加了感受野,捕获了更多上下文;dense evaluation 就是利用FCN得到一个score map对其平均,也就是上面介绍的方法。
Part4. Classification Experiments

在这里插入图片描述
这一段主要就是Show Time了,实验对比,主要介绍在ILSVRC数据集上的结果:

  • 首先是单规模实验,实验结果说明了三点:1. LRN局部响应归一化的确没用,还平白浪费计算资源;2. 随着网络深度的增加错误率下降(引入额外非线性单元,提取空间特征的卷积层能提高,并且两个3x3优于一个5x5);训练时的尺度抖动有助于提高精度。

在这里插入图片描述

  • 多尺度实验说明,测试时候的尺度抖动也有助于精度的提升;
  • Multi-crop实验说明,Multi-crop和Dense两种方案确实是互补的,两者的组合好于任何一个单个方法;
  • Convnet fustion模型融合实验,就是把几个模型的结果融合在一起做平均;
    在这里插入图片描述
    与其他的SOTA模型做对比。

第三遍

VGG是牛津大学的VGG视觉组的产物,所以命名为VGG。虽然它没有获得那年ILSVRC分类组的冠军,但他获得了定位的冠军和分类的亚军。对后面的研究也很有影响:引入小卷积核 && 在网络的深度上探索。
3x3的卷积核在之后的网络基本上成为了标配,为什么不是2x2?或者4x4呢?因为3x3是一个捕捉局部信息的最小单元,它能捕捉区域中心以及四周的信息。
但VGG绝大多数的参数都是来自于第一个全连接层,并且如果只是单纯的增加神经网络的深度,会给训练带来困难,会出现梯度消失、梯度爆炸、不收敛等问题。

代码复现:

基于Pytorch 1.0.0

import torch
import torch.nn as nn


class VGG19(nn.Module):
    def __init__(self, num_classes, init_weights=True):
        super().__init__()
        self.features = nn.Sequential(
            # Block 1
            nn.Conv2d(3, 64, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(64, 64, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, stride=2),
            # Block 2
            nn.Conv2d(64, 128, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(128, 128, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, stride=2),
            # Block 3
            nn.Conv2d(128, 256, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, stride=2),
            # Block 4
            nn.Conv2d(256, 512, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, stride=2),
            # Block 5
            nn.Conv2d(512, 512, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, stride=2),
        )
        self.avgpool = nn.AdaptiveAvgPool2d((7, 7))
        self.classifier = nn.Sequential(
            nn.Linear(512*7*7, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
        )
        # 因为前面可以用预训练模型参数,所以单独把最后一层提取出来
        self.classifier2 = nn.Linear(4096, num_classes)
        if init_weights:
            self._initialize_weights()

    def forward(self, x):
        x = self.features(x)
        x = self.avgpool(x)
        # torch.flatten 推平操作
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        x = self.classifier2(x)
        return x

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)

应用实例:使用VGG实现分类(以猫狗数据集为例)

VGG19实现猫狗分类

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值