【论文】GoogleNet V1+V2+V3+V4

 

写在前面

googlenet是由google团队在2014年在ilsvrc时提出的,并获得了多项冠军。googlenet v1[1]版本发表在CVPR2015上。由Hebbian principle 和多尺度Gabor滤波器提取特征[2]提出了inception模块。训练时通过辅助损失,模型达到了22层超过了vgg,但参数只有它的1/12,主要是减少在全连接层。

 

GoogleNet v1

Inception 通过多尺度卷积得到了更丰富的特征,同时在提出inception模块后,进行了改进加入了1*1卷积进行降维,减少参数和计算。

 

 

naive 版本的inception ,3*3/5*5卷积计算时参数大,池化结果参数多。所以,改进版本inception通过1*1卷积进行降维:1.3*3/5*5卷积计算前进行降维,减少计算量 2.对3*3 池化后参数进行降维 减少传递到下一层的参数量。

 

模型结构

模型上分为三个阶段,四个部分组成

前期

输入数据进行快速降维 ,因为多尺度卷积会增加计算量等于同一层计算多次,所以要把原图降参数。

中期

9个连续的inception 模块多尺度提取特征。辅助损失模块辅助分类进行loss反向传播,防止梯度消失。

后期

inception 模块输出的结果 -》avgpooling-》fc(分类结果)

为什么只有一层全连接层,在vgg中有三层

全连接层主要是用来做分类的,也就是将之前提取到的分布式特征映射到标签空间,vgg前面的特征提取的泛化性不是很强,相比于googlenet和resnet来说,后两者网络的深度够深,泛化性足够好,特征对于位置的依赖性不明显,vgg则需要通过多层全连接来处理非线性的问题。

 

GoogleNet v2

googlenet v2 [3]结构上与v1版本区别不大。主要工作引入了BN,推动了深度学习训练的发展。

为什么要引入BN?

数据的饱和阶段(数据偏向0或者1)会引起梯度消失,它不仅仅发生在数据输入阶段,它也发生在数据的训练阶段(隐藏层),什么是批标准化 (Batch Normalization)

BN算法简述
减少均值,除以标准差,乘gamma,加beta。均值和标准差是通过指数滑动平均得来的。

1.mini - batch上计算均值

2.mini-batch上计算标准差

3.减均值除以标准差(\epsilon = 1*e^{-5},是一个极小的参数防止分母为0)

4.线性变换,乘\gamma\beta,实现缩放和平移(此阶段为反向工程,其中\gamma\beta是超参数神经网络自己学习,根据效果自动调整平移大小)

 BN的效果及代码

此处引用Batch Normalization 批标准化,这里模拟全连接层与接入BN层后数据的对比,后两行是前两行经过tanh激活层后的参数变换。

 

相对于v1版本的改进:

1.激活函数前加入BN

2.5*5卷积替换为2个3*3卷积(vgg中提出)

3.第一个Inception 模块增加一个Inception结构

4.增加多个“5*5”卷积核

5.尺寸变化采用stride = 2 的卷积

6.增加9层(10-1层)到31层(10表示inception数量)

实验:

1.实验一:速度

参数设置:初始学习率=0.0015

图中 x5表示学习率=0.0015*5=0.0075

1.加BN更快:BN-Baseline比Inception快一倍

2.可用大学习率:BN-x5 比Inception 快14倍

3.加BN精度更高:BN-x30比x5慢,但精度更高

4.Sigmoid时,加BN精度更高

2.实验二:

GoogleNet v3

提出4个网络模型设计准则

  • 非对称卷积

在vgg中为了减少大卷积参数,用多个3*3卷积替换5*5/7*7卷积达到减少参数的效果。在本文中提出非对称卷积让卷积替换贯彻到底。

 

  • 辅助分类层
  1. 辅助分类层再初期起不到任何作用,再后期才能提升网络性能,所以移除第一个辅助分类层,精度不影响。
  2. 辅助分类层可以辅助低层提取特征(v1的观点)是不正确的
  3. 辅助分类层对模型起到正则的作用(v1的观点)是正确的
  4. googlenet-v3在17*17特征图结束接入辅助分类层
  • 池化策略

池化操作,比如35*35*320进行直接池化(比如2*2 max pooling),那么就为 17*17*320,那么就会损失一部分信息造成信息表征瓶颈。传统用池化后进行卷积还原,或者先卷积再池化,那么会造成计算量太大,能不能跳过池化操作。于是提出了再卷积时候步长设置为2替代池化。

 

  • 标签平滑(label smoothing)

Lable Smoothing是分类问题中错误标注的一种解决方法。

对于分类问题,特别是多分类问题,常常把向量转换成one-hot-vector(独热向量:比如分类结果为[0,0,0,0,0,0,0,1,0,0,0],如果概率为1,其他均为0就称为one-hot)
one-hot带来的问题:
对于损失函数,我们需要用预测概率去拟合真实概率,而拟合one-hot的真实概率函数会带来两个问题:
1)无法保证模型的泛化能力,容易造成过拟合;
2) 全概率和0概率鼓励所属类别和其他类别之间的差距尽可能加大,而由梯度有界可知,这种情况很难适应。会造成模型过于相信预测的类别

标签平滑通过公式,将最大概率值匀给其他label,达到防止过拟合的效果。

交叉熵:

H(q,p)=-\sum _{k=1}^Klog(p_k)q_k

标签平滑:

{q}'(k|x)=(1-\varepsilon )\delta _{k,y}+\varepsilon u(k),这里的u(k)为均值概率分布所以,{q}'(k|x)=(1-\varepsilon )\delta _{k,y}+\frac{\varepsilon}{k}

改编后的交叉熵:

H(q,p)=-\sum _{k=1}^Klog(p_k)q_k=-\sum _{k=1}^Klog(p_k)\left [ (1-\varepsilon )\delta _{k,y}+\frac{\varepsilon}{k} \right ]

=-\sum _{k=1}^Klog(p_k) (1-\varepsilon )\delta _{k,y}+\left [ -\sum _{k=1}^Klog(p_k)\frac{\varepsilon}{k} \right ]

=(1-\varepsilon )\left [ -\sum _{k=1}^Klog(p_k) \delta _{k,y} \right ]+\varepsilon\left [ -\sum _{k=1}^Klog(p_k)\frac{1}{k} \right ]

=(1-\varepsilon )H(q,p)+\varepsilon\varepsilonH({q}',p)

 

结构上改进

针对v1:

1.采用3个3*3卷积替换1个7*7卷积,并且在第一个卷积就采用stride=2来降低分辨率

2.第二个3个3*3卷积,在第2个卷积才下降分辨率

3.第一个block增加一个inception-module,第一个inception-module只是将5*5卷积替换成为2个3*3卷积

4.第二个block,处理17*17特征图,采用非对称卷积

5.第三个block,处理8*8特征图,提出扩展的卷积

6.最后输出2048个神经元

针对V2:

1.采用RMSProp优化方法(原本SGD)

2.采用Label Smoothing 正则化方法

3.采用非对称卷积提取17*17特征图

4.采用带BN的辅助分类层

Performance on Lower Resolution Input  

低分辨率图片输入后,提高识别率的策略:

1.将第一个卷积层stride=2改为stride=1,用于151*151的图像

2.将第一个卷积层stride=2改为stride=1,移除第一个池化层,用于79*79的图像

修改思路:修改网络模型头部stride和池化,来处理低分辨率图片,可尽可能的保留原网络模型结构,不损失网络精度。

代码

由于googlenet代码是一代代迭代和升级的,所以在这里举例市场上比较常用的googlenet v3的代码

  • 主干
class Inception3(nn.Module):

    def __init__(self, num_classes=1000, aux_logits=True, transform_input=False):
        super(Inception3, self).__init__()
        self.aux_logits = aux_logits
        self.transform_input = transform_input
        self.Conv2d_1a_3x3 = BasicConv2d(3, 32, kernel_size=3, stride=2)
        self.Conv2d_2a_3x3 = BasicConv2d(32, 32, kernel_size=3)
        self.Conv2d_2b_3x3 = BasicConv2d(32, 64, kernel_size=3, padding=1)
        self.Conv2d_3b_1x1 = BasicConv2d(64, 80, kernel_size=1)
        self.Conv2d_4a_3x3 = BasicConv2d(80, 192, kernel_size=3)
        self.Mixed_5b = InceptionA(192, pool_features=32)
        self.Mixed_5c = InceptionA(256, pool_features=64)
        self.Mixed_5d = InceptionA(288, pool_features=64)
        self.Mixed_6a = InceptionB(288)
        self.Mixed_6b = InceptionC(768, channels_7x7=128)
        self.Mixed_6c = InceptionC(768, channels_7x7=160)
        self.Mixed_6d = InceptionC(768, channels_7x7=160)
        self.Mixed_6e = InceptionC(768, channels_7x7=192)
        if aux_logits:
            self.AuxLogits = InceptionAux(768, num_classes)
        self.Mixed_7a = InceptionD(768)
        self.Mixed_7b = InceptionE(1280)
        self.Mixed_7c = InceptionE(2048)
        self.fc = nn.Linear(2048, num_classes)

        for m in self.modules():
            if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear):
                import scipy.stats as stats
                stddev = m.stddev if hasattr(m, 'stddev') else 0.1
                X = stats.truncnorm(-2, 2, scale=stddev)
                values = torch.Tensor(X.rvs(m.weight.numel()))
                values = values.view(m.weight.size())
                m.weight.data.copy_(values)
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)

    def forward(self, x):
        if self.transform_input:
            x_ch0 = torch.unsqueeze(x[:, 0], 1) * (0.229 / 0.5) + (0.485 - 0.5) / 0.5
            x_ch1 = torch.unsqueeze(x[:, 1], 1) * (0.224 / 0.5) + (0.456 - 0.5) / 0.5
            x_ch2 = torch.unsqueeze(x[:, 2], 1) * (0.225 / 0.5) + (0.406 - 0.5) / 0.5
            x = torch.cat((x_ch0, x_ch1, x_ch2), 1)
        # N x 3 x 299 x 299
        x = self.Conv2d_1a_3x3(x)
        # N x 32 x 149 x 149
        x = self.Conv2d_2a_3x3(x)
        # N x 32 x 147 x 147
        x = self.Conv2d_2b_3x3(x)
        # N x 64 x 147 x 147
        x = F.max_pool2d(x, kernel_size=3, stride=2)
        # N x 64 x 73 x 73
        x = self.Conv2d_3b_1x1(x)
        # N x 80 x 73 x 73
        x = self.Conv2d_4a_3x3(x)
        # N x 192 x 71 x 71
        x = F.max_pool2d(x, kernel_size=3, stride=2)
        # N x 192 x 35 x 35
        x = self.Mixed_5b(x)
        # N x 256 x 35 x 35
        x = self.Mixed_5c(x)
        # N x 288 x 35 x 35
        x = self.Mixed_5d(x)
        # N x 288 x 35 x 35
        x = self.Mixed_6a(x)
        # N x 768 x 17 x 17
        x = self.Mixed_6b(x)
        # N x 768 x 17 x 17
        x = self.Mixed_6c(x)
        # N x 768 x 17 x 17
        x = self.Mixed_6d(x)
        # N x 768 x 17 x 17
        x = self.Mixed_6e(x)
        # N x 768 x 17 x 17
        if self.training and self.aux_logits:
            aux = self.AuxLogits(x)
        # N x 768 x 17 x 17
        x = self.Mixed_7a(x)
        # N x 1280 x 8 x 8
        x = self.Mixed_7b(x)
        # N x 2048 x 8 x 8
        x = self.Mixed_7c(x)
        # N x 2048 x 8 x 8
        # Adaptive average pooling
        x = F.adaptive_avg_pool2d(x, (1, 1))
        # N x 2048 x 1 x 1
        x = F.dropout(x, training=self.training)
        # N x 2048 x 1 x 1
        x = x.view(x.size(0), -1)
        # N x 2048
        x = self.fc(x)
        # N x 1000 (num_classes)
        if self.training and self.aux_logits:
            return x, aux
        return x

GoogleNet V4

googlenet v4[5]有六大模块,同时把残差网络的思想引用过来。六大模块分为Stem主干,inceptionA/B/C对每个inception都进行了独特的设计(所以v4版本很复杂),reductionA/B降维度,avg pooling,droup out(0.8),softmax。

 

stem

inception

reduction

主要功能是降低维度

残差设计

引入resnet思想,收敛更快。

Reference:

[1] Szegedy C, Liu W, Jia Y, et al. "Going deeper with convolutions"[J]. arXiv preprint arXiv:1409.4842, 2014. googlenet v1

[2] T Serre,L Wolf,S Bileschi,M Riesenhuber,T Poggio "Robust Object Recognition with Cortex-Like Mechanisms" .2007

[3] S Ioffe,C Szegedy “Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift” .2015 v2

[4] C Szegedy,V Vanhoucke,S Ioffe,J Shlens,Z Wojna "Rethinking the Inception Architecture for Computer Vision" .2015 v3

[5] C Szegedy,S Ioffe,V Vanhoucke,A Alemi "Inception-v4, Inception-ResNet and the Impact of Residual Connections on Learning" . 2016 v4

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wL魔法师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值