GoogleNet



一 论文导读

 

一 LeNet 如下图:
GoogleNet_ide
LeNet 是整个卷积神经网络的开山之作,是卷积神经网络的现代雏形,1998年LeCun提出
缺点是:网络层数浅,无激活层

二 AlexNet
GoogleNet_卷积神经网络_02
AlexNet:2012年在ImageNet竞赛中取得了冠军,这是ImageNet竞赛史上第一次基于卷积神经网络模型得到冠军,AlexNet相对于LeNet,网络更深,同时第一次引入ReLu激活层,在全连接层引入Dropout层防止过拟合。
补充:Relu激活层标志着深度神经网络的出现

当时限于GPU运算量有限,使用两个GPU并行运算。

三 VGG

GoogleNet_卷积_03
VggNet是第一个真正意义上的深层网络结构,是ImageNet2014年的亚军,使用了更小的滤波器,更深的网络结构

VGGNet与AlexNetb比较:AlexNet只有8层,VGGNet有16-19层,AlexNet使用了1111卷积滤波器,VGGNet使用了33卷积滤波器和2*2的最大池化层,层叠小的滤波器和大的滤波器感受野是相同的,还能减少参数,因而有更深的网络。

四 GoogleNet
GoogleNet_卷积_04
GoogleNet也叫InceptionNet,是2014年ImageNet比赛的冠军,相比于VGGNet有更深的网络,但是网络参数却比AlexNet少12倍,计算效率非常高,因为GoogleNet采用了Inception模块,GoogleNet可以看作是很多个inception模块的串联,并且模型没有全连接。

GoogleNet_卷积神经网络_05
Inception 模块设计了一种局部的网络拓扑结构,然后将这些模块堆叠在一起形成一个抽象的网络结构,运行及各个并行的滤波器,对输入进行卷积和池化,这些滤波器有着不同的感受野,最后将输出结果拼接在一起输出。

最原始Inception的基本结构:
GoogleNet_ide_06
一方面增加了网络宽度,另一方面也增加了网络对尺度的适应性。
网络卷积层中的网络能够提取输入的每一个细节信息,同时5*5的滤波器也能够覆盖大部分接受层的输入。还可以进行一个池化操作,以减少空间大小,降低多度拟合。在这些层之上,在每一个卷积层后都要做一个Relu操作,以增加网络的非线性特征。

InceptionV2:
GoogleNet_卷积_07
Inception原始版本,所有的卷积核都在上一层的所有输出上来做,而5*5的卷积核所需的计算量很大,造成特征图的厚度很大,为了避免这种情况,在3*3前,5*5前、max pooling后分别加上1*1的卷积核,已起到了降低特征图厚度的作用,这也就形成了Inception V1的网络结构。

InceptionV3:在不改变感受野同时减少参数的情况下,采用1*n和n*1的卷积核代替InceptionV1-V2中的n*n的卷积核。

GoogleNet_2d_08

GoogleNet_卷积神经网络_09

InceptionV4:

GoogleNet_卷积核_10
InceptionV4采用了inception模块于残差连接相结合,V4主要利用残差连接来改进V3结构,得到Inception-ResNet-V2,Inception-ResNet-V1的网络

五 ResNet
GoogleNet_ide_11
GoogleNet_卷积神经网络_12

  • ResNet是2015年ImageNet竞赛的冠军
  • ResNet有效地解决了深度神经网络难以训练的问题,可以训练高达1000层的卷积神经网络
  • ResNet通过引入了跨层链接解决了梯度回传消失的问题
  • 使用普通的连接,上层的梯度必须要一层一层传回来,而采用残差连接,相当于中间有了一条更短的路,梯度能够从这条更短的路传回来,避免了梯度过小的情况。

论文的核心思想:

1*1Conv

-在

二 论文精读

 

三 代码实现

 


GoogleNet_卷积_13


GoogleNet_卷积核_14


'''GoogLeNet with PyTorch.'''
import torch
import torch.nn as nn
import torch.nn.functional as F

# 卷积+bn+relu模块
class BasicConv2d(nn.Module):
    def __init__(self, in_channels, out_channals, **kwargs):
        super(BasicConv2d, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channals, **kwargs)
        self.bn = nn.BatchNorm2d(out_channals)

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        return F.relu(x)

# Inception模块
class Inception(nn.Module):
    def __init__(self, in_planes,
                 n1x1, n3x3red, n3x3, n5x5red, n5x5, pool_planes):
        super(Inception, self).__init__()
        # 1x1 conv branch
        self.b1 = BasicConv2d(in_planes, n1x1, kernel_size=1)

        # 1x1 conv -> 3x3 conv branch
        self.b2_1x1_a = BasicConv2d(in_planes, n3x3red,
                                    kernel_size=1)
        self.b2_3x3_b = BasicConv2d(n3x3red, n3x3,
                                    kernel_size=3, padding=1)

        # 1x1 conv -> 3x3 conv -> 3x3 conv branch
        self.b3_1x1_a = BasicConv2d(in_planes, n5x5red,
                                    kernel_size=1)
        self.b3_3x3_b = BasicConv2d(n5x5red, n5x5,
                                    kernel_size=3, padding=1)
        self.b3_3x3_c = BasicConv2d(n5x5, n5x5,
                                    kernel_size=3, padding=1)

        # 3x3 pool -> 1x1 conv branch
        self.b4_pool = nn.MaxPool2d(3, stride=1, padding=1)
        self.b4_1x1 = BasicConv2d(in_planes, pool_planes,
                                  kernel_size=1)

    def forward(self, x):
        y1 = self.b1(x)
        y2 = self.b2_3x3_b(self.b2_1x1_a(x))
        y3 = self.b3_3x3_c(self.b3_3x3_b(self.b3_1x1_a(x)))
        y4 = self.b4_1x1(self.b4_pool(x))
        # y的维度为[batch_size, out_channels, C_out,L_out]
        # 合并不同卷积下的特征图
        return torch.cat([y1, y2, y3, y4], 1)


class GoogLeNet(nn.Module):
    def __init__(self):
        super(GoogLeNet, self).__init__()
        self.pre_layers = BasicConv2d(3, 192,
                                      kernel_size=3, padding=1)

        self.a3 = Inception(192,  64,  96, 128, 16, 32, 32)
        self.b3 = Inception(256, 128, 128, 192, 32, 96, 64)

        self.maxpool = nn.MaxPool2d(3, stride=2, padding=1)

        self.a4 = Inception(480, 192,  96, 208, 16,  48,  64)
        self.b4 = Inception(512, 160, 112, 224, 24,  64,  64)
        self.c4 = Inception(512, 128, 128, 256, 24,  64,  64)
        self.d4 = Inception(512, 112, 144, 288, 32,  64,  64)
        self.e4 = Inception(528, 256, 160, 320, 32, 128, 128)

        self.a5 = Inception(832, 256, 160, 320, 32, 128, 128)
        self.b5 = Inception(832, 384, 192, 384, 48, 128, 128)

        self.avgpool = nn.AvgPool2d(8, stride=1)
        self.linear = nn.Linear(1024, 5)

    def forward(self, x):
        out = self.pre_layers(x)
        out = self.a3(out)
        out = self.b3(out)
        out = self.maxpool(out)
        out = self.a4(out)
        out = self.b4(out)
        out = self.c4(out)
        out = self.d4(out)
        out = self.e4(out)
        out = self.maxpool(out)
        out = self.a5(out)
        out = self.b5(out)
        out = self.avgpool(out)
        out = out.view(out.size(0), -1)
        out = self.linear(out)
        return out


四 问题思索