Pytorch 含并行连结的网络 GoogLeNet

Pytorch 含并行连结的网络 GoogLeNet

0. 环境介绍

环境使用 Kaggle 里免费建立的 Notebook

教程使用李沐老师的 动手学深度学习 网站和 视频讲解

小技巧:当遇到函数看不懂的时候可以按 Shift+Tab 查看函数详解。

1. GoogLeNet

1.1 简介

GoogLeNet 吸收了 NiN 中串联网络的思想,并在此基础上做了改进。 这篇论文的一个重点是解决了什么样大小的卷积核最合适的问题。GoogLeNet 的一个观点是,有时使用不同大小的卷积核组合是有利的。

GoogLeNet 论文地址:https://arxiv.org/abs/1409.4842

1.2 GoogLeNet 结构

在GoogLeNet 中,基本的卷积块被称为 Inception 块(Inception block)。这很可能得名于电影《盗梦空间》(Inception),因为电影中的一句话“我们需要走得更深”(“We need to go deeper”)。

Inception 块(小学生才做选择,我全都要):

  • 4 个路径从不同层面抽取信息,然后在输出通道维合并
  • 使用不同窗口大小的卷积层
  • 1 × 1 1 \times 1 1×1 的卷积块只抽取通道信息,不抽取空间信息
  • 每条路上通道数可能不同

Pytorch 含并行连结的网络 GoogLeNet_第1张图片
Inception 块跟单 3 × 3 3 \times 3 3×3 5 × 5 5 \times 5 5×5 的卷积层相比有更少的参数个数和设计复杂度。
Pytorch 含并行连结的网络 GoogLeNet_第2张图片
:问为什么这么设计?调出来的!

GoogLeNet 简化版本:
Pytorch 含并行连结的网络 GoogLeNet_第3张图片
5 5 5 段, 9 9 9 个 Inception 块。
1 , 2 1,2 1,2

  • 更小的宽口
  • 更多的通道 Pytorch 含并行连结的网络 GoogLeNet_第4张图片

3 3 3
Pytorch 含并行连结的网络 GoogLeNet_第5张图片
4 , 5 4,5 4,5
Pytorch 含并行连结的网络 GoogLeNet_第6张图片

1.3 Inception 后续变种

Inception-BN(V2):使用了 batch normalization
Inception-V3:修改了 Inception 块

  • 替换 5 × 5 5 \times 5 5×5 为多个 3 × 3 3 \times 3 3×3 卷积层
  • 替换 5 × 5 5 \times 5 5×5 1 × 7 1 \times 7 1×7 7 × 1 7 \times 1 7×1 卷积层
  • 替换 5 × 5 5 \times 5 5×5 1 × 3 1 \times 3 1×3 3 × 1 3 \times 1 3×1 卷积层
  • 更深
    Inception-V4:使用残差连接

2. 代码实现

2.1 Inception 块

!pip install -U d2l
import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l


class Inception(nn.Module):
    # c1--c4是每条路径的输出通道数
    def __init__(self, in_channels, c1, c2, c3, c4, **kwargs):
        super(Inception, self).__init__(**kwargs)
        # 线路1,单1x1卷积层
        self.p1_1 = nn.Conv2d(in_channels, c1, kernel_size=1)
        # 线路2,1x1卷积层后接3x3卷积层
        self.p2_1 = nn.Conv2d(in_channels, c2[0], kernel_size=1)
        self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)
        # 线路3,1x1卷积层后接5x5卷积层
        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)
        # 线路4,3x3最大汇聚层后接1x1卷积层
        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(self.p4_1(x)))
        # 在通道维度上连接输出
        return torch.cat((p1, p2, p3, p4), dim=1)

2.2 GoogLeNet 网络结构

第一个模块使用 64 64 64 个通道、 7 × 7 7 \times 7 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))

第二个模块使用两个卷积层:第一个卷积层是 64 64 64 个通道、 1 × 1 1 \times 1 1×1 卷积层;第二个卷积层使用将通道数量增加三倍的 3 × 3 3 \times 3 3×3 卷积层:
Pytorch 含并行连结的网络 GoogLeNet_第7张图片

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

第三个模块串联两个完整的 Inception 块, 第一个Inception 块的输出通道数为 64 + 128 + 32 + 32 = 256 64+128+32+32=256 64+128+32+32=256,四个路径之间的输出通道数量比为 64 : 128 : 32 : 32 = 2 : 4 : 1 : 1 64:128:32:32=2:4:1:1 64:128:32:32=2:4:1:1,第二个 Inception 块的输出通道数增加到 128 + 192 + 96 + 64 = 480 128+192+96+64=480 128+192+96+64=480,四个路径之间的输出通道数量比为 128 : 192 : 96 : 64 = 4 : 6 : 3 : 2 128:192:96:64 = 4:6:3:2 128:192:96:64=4:6:3:2
在这里插入图片描述

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))

第四模块更加复杂, 它串联了 5 5 5 个 Inception 块,其输出通道数分别是:

  • 192 + 208 + 48 + 64 = 512 192+208+48+64=512 192+208+48+64=512
  • 160 + 224 + 64 + 64 = 512 160+224+64+64=512 160+224+64+64=512
  • 128 + 256 + 64 + 64 = 512 128+256+64+64=512 128+256+64+64=512
  • 112 + 288 + 64 + 64 = 528 112+288+64+64=528 112+288+64+64=528
  • 256 + 320 + 128 + 128 = 832 256+320+128+128=832 256+320+128+128=832

Pytorch 含并行连结的网络 GoogLeNet_第8张图片

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))

第五模块包含输出通道数为 256 + 320 + 128 + 128 = 832 256+320+128+128=832 256+320+128+128=832 384 + 384 + 128 + 128 = 1024 384+384+128+128=1024 384+384+128+128=1024 的两个 Inception 块,后面紧跟输出层,该模块同 NiN 一样使用全局平均池化层,将每个通道的高和宽变成 1 1 1。 最后我们将输出变成二维数组,再接上一个输出个数为标签类别数的全连接层:
Pytorch 含并行连结的网络 GoogLeNet_第9张图片

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())

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

GoogLeNet 模型的计算复杂,而且不如 VGG 那样便于修改通道数。 为了使 Fashion-MNIST 上的训练短小精悍,我们将输入的高和宽从 224 224 224 降到 96 96 96,这简化了计算。下面演示各个模块输出的形状变化:

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

在这里插入图片描述

2.3 训练

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, d2l.try_gpu())

Pytorch 含并行连结的网络 GoogLeNet_第10张图片

你可能感兴趣的:(#,CV,pytorch)