5. 9 多路并行的GoogLeNet

并行连接网络GoogLeNet

GoogLeNet名字的由来。 它是由Google研发,对LeNet表示致敬的。所以命名为GooLeNet


前言

在2014年的ImageNet图像识别挑战赛中,一个名叫GoogLeNet的网络结构大放异彩 [1]。它虽然在名字上向LeNet致敬,但在网络结构上已经很难看到LeNet的影子。GoogLeNet吸收了NiN中网络串联网络的思想,并在此基础上做了很大改进。在随后的几年里,研究人员对GoogLeNet进行了数次改进,本节将介绍这个模型系列的第一个版本。

提示:以下是本篇文章正文内容,下面案例可供参考

一、 Inception块

1. Inception块的结构图

设计的目的: 1 × 1 1 \times 1 1×1 可以得到小细节东西 . 5 × 5 5 \times5 5×5可以得到大东西的信息。结构图设计目的是把大小信息都拿到。然后再用 1 × 1 1 \times1 1×1的核降低维度减少参数

输入
1*1卷积层
1*1卷积层
3*3卷积层
1*1卷积层
5*5卷积层
3*3最大池化层
1*1卷积层
合并通道

2.Inception代码块(以下代码在Colab上调试过)

代码如下(示例):

pip install d2l
from d2l import torch as d2l
import torch
from torch import nn
from torch.nn import function as F

class Inception(nn.Module):
  def __init__(self,in_channels,c1,c2,c3,c4,**kwargs):
    super(Inception,self).__init__(**kwargs)
     # path 1
    self.p1_1 = nn.Conv2d(in_channels,c1,kernel_size=1)
     # path 2
    self.p2_1 = nn.Conv2d(in_channels,c2[0],kernel_size=1)
    # 添加padding=1 保证图片大小不变。如果大小变化了,不同尺寸的图片会导致concate失败
    self.p2_2 = nn.Conv2d(c2[0],c2[1],kernel_size=3,padding=1)
   # path 3
    self.p3_1 = nn.Conv2d(in_channels,c3[0],kernel_size=1)
    self.p3_2 = nn.Conv2d(c3[0],c3[1],kernel_size=5,padding=2)
    # path 4, stride=1 写出来是因为默认stride=2
    self.p4_1 = nn.MaxPool2d(kernel_size=3,stride=1,padding=1)
    self.p4_2 = nn.Conv2d(in_channels,c4,kernel_size=1)
  
  def forward(self,x):
    p1 = F.relu(self.p1_1(x))
    p2 = F.relu(self.p2_2( F.relu(self.p2_1(x))))
    p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))
    p4 = F.relu(self.p4_2(F.relu(self.p4_1(x))))
    # dim =1 是因为输入是(batch,channel, height,weight)
    return torch.cat((p1,p2,p3,p4),dim=1)
      

二、GoogLeNet模型

GoogLeNet和VGG一样,主体有5个Bolock, 每个模块之间使用步幅为2的 3×3 最大池化层来减小输出高宽。

1. 第一模块使用一个64通道的 7×7 卷积层。

b1 = nn.Sequential(nn.Conv2d(1,64,kernel_size=7,stride=2,padding=3),
          nn.ReLU(),
          nn.MaxPool2d(kernel_size=3,stride=2,padding=1))

2. 第二模块使用2个卷积层

首先是64通道的 1×1 卷积层,然后是将通道增大3倍的 3×3 卷积层。它对应Inception块中的第二条线路。

b2 = nn.Sequential(nn.Conv2d(64,64,kernel_size=1),
                   nn.ReLU(),
                   nn.Conv2d(64,192,kernel_size=3,padding=1),
                   nn.MaxPool2d(kernel_size=3,stride=2,padding=1))

3. 第三模块串联2个完整的Inception块。

第一个Inception块的输出通道数为 64+128+32+32=256 ,其中4条线路的输出通道数比例为 64:128:32:32=2:4:1:1 。其中第二、第三条线路先分别将输入通道数减小至 96/192=1/2 和 16/192=1/12 后,再接上第二层卷积层。第二个Inception块输出通道数增至 128+192+96+64=480 ,每条线路的输出通道数之比为 128:192:96:64=4:6:3:2 。其中第二、第三条线路先分别将输入通道数减小至 128/256=1/2 和 32/256=1/8 。

b3 = nn.Sequential(Inception(192,64,(96,128),(16,32),32),
           Inception(256,128,(128,192),(32,96),64),
           nn.MaxPool2d(kernel_size=3,stride=2,padding=1))

4. 第四模块更加复杂, 它串联了5个Inception块

其输出通道数分别是 192+208+48+64=512 、 160+224+64+64=512 、 128+256+64+64=512 、 112+288+64+64=528 和 256+320+128+128=832 。这些线路的通道数分配和第三模块中的类似,首先是含 3×3 卷积层的第二条线路输出最多通道,其次是仅含 1×1 卷积层的第一条线路,之后是含 5×5 卷积层的第三条线路和含 3×3 最大池化层的第四条线路。其中第二、第三条线路都会先按比例减小通道数。这些比例在各个Inception块中都略有不同。

b4 = nn.Sequential(Inception(480,192,(96,208),(16,48),64),
                   Inception(512,160,(112,224),(24,64),64),
                   Inception(512,128,(128,256),(24,64),64),
                   Inception(512,112,(144,288),(32,64),64),
                   Inception(528,256,(160,320),(32,128),128),
                   nn.MaxPool2d(kernel_size=3,stride=2,padding=1))

5. 第五模块有输出通道数为 256+320+128+128=832 和 384+384+128+128=1024 的两个Inception块。

其中每条线路的通道数的分配思路和第三、第四模块中的一致,只是在具体数值上有所不同。需要注意的是,第五模块的后面紧跟输出层,该模块同NiN一样使用全局平均池化层来将每个通道的高和宽变成1。最后我们将输出变成二维数组后接上一个输出个数为标签类别数的全连接层。

b5 = nn.Sequential(Inception(832,256,(160,320),(32,128),128),
                   Inception(832,384,(192,384),(48,128),128),
                   nn.AdaptiveAvgPool2d((1,1)),
                                        nn.Flatten())

6. 合并总结。

GoogLeNet模型的计算复杂,而且不如VGG那样便于修改通道数。本节里我们将输入的高和宽从224降到96来简化计算。下面演示各个模块之间的输出的形状变化

net = nn.Sequential(b1,b2,b3,b4,b5,nn.Linear(1024,10))

X = torch.randn((1,1,224,224))
for layer in net:
  X = layer(X)
  print(layer.__class__.__name__, 'output shape: \t', X.shape)

输出

Sequential output shape: 	 torch.Size([1, 64, 56, 56])
Sequential output shape: 	 torch.Size([1, 192, 28, 28])
Sequential output shape: 	 torch.Size([1, 480, 14, 14])
Sequential output shape: 	 torch.Size([1, 832, 7, 7])
Sequential output shape: 	 torch.Size([1, 1024])
Linear output shape: 	 torch.Size([1, 10])

三、训练模型

我们使用高和宽均为96像素的图像来训练GoogLeNet模型。训练使用的图像依然来自Fashion-MNIST数据集。

lr, num_epochs, batch_size = 0.1, 10, 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=96)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr)

总结

  • Inception块相当于一个有4条线路的子网络。它通过不同窗口形状的卷积层和最大池化层来并行抽取信息,并使用 1×1 卷积层减少通道数从而降低模型复杂度。
  • GoogLeNet将多个设计精细的Inception块和其他层串联起来。其中Inception块的通道数分配之比是在ImageNet数据集上通过大量的实验得来的。
  • GoogLeNet和它的后继者们一度是ImageNet上最高效的模型之一:在类似的测试精度下,它们的计算复杂度往往更低。

引用: http://zh.gluon.ai/chapter_convolutional-neural-networks/googlenet.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值