计算机视觉知识点-基础网络-GoogleNet

2014年,GoogLeNet赢得了ImageNet挑战赛的冠军,提出了一种结合了NiN的优势和重复块范例的结构,论文的重点是解决哪种大小的卷积核最好的问题。 以前的流行网络采用的选择范围小至1×1,大至11×11,GoogleNet认为结合使用各种大小的kernel是有利的。

使用mxnet进行一下代码演示。mxnet的安装方法

pip install d2l==0.14.3
pip install -U mxnet-cu101mkl==1.6.0.post0  
pip install gluoncv

一个GoogleNet中的标准块

from d2l import mxnet as d2l
from mxnet import np, npx
from mxnet.gluon import nn
npx.set_np()

class Inception(nn.Block):
    # `c1`--`c4` are the number of output channels for each path
    def __init__(self, c1, c2, c3, c4, **kwargs):
        super(Inception, self).__init__(**kwargs)
        # Path 1 is a single 1 x 1 convolutional layer
        self.p1_1 = nn.Conv2D(c1, kernel_size=1, activation='relu')
        # Path 2 is a 1 x 1 convolutional layer followed by a 3 x 3
        # convolutional layer
        self.p2_1 = nn.Conv2D(c2[0], kernel_size=1, activation='relu')
        self.p2_2 = nn.Conv2D(c2[1], kernel_size=3, padding=1,
                              activation='relu')
        # Path 3 is a 1 x 1 convolutional layer followed by a 5 x 5
        # convolutional layer
        self.p3_1 = nn.Conv2D(c3[0], kernel_size=1, activation='relu')
        self.p3_2 = nn.Conv2D(c3[1], kernel_size=5, padding=2,
                              activation='relu')
        # Path 4 is a 3 x 3 maximum pooling layer followed by a 1 x 1
        # convolutional layer
        self.p4_1 = nn.MaxPool2D(pool_size=3, strides=1, padding=1)
        self.p4_2 = nn.Conv2D(c4, kernel_size=1, activation='relu')

    def forward(self, x):
        p1 = self.p1_1(x)
        p2 = self.p2_2(self.p2_1(x))
        p3 = self.p3_2(self.p3_1(x))
        p4 = self.p4_2(self.p4_1(x))
        # Concatenate the outputs on the channel dimension
        return np.concatenate((p1, p2, p3, p4), axis=1)

标准块由四个路径组成,前三个路径使用窗口大小为1×1、3×3和5×5的卷积层从不同的空间大小中提取信息.中间的两条路径对输入执行1×1卷积以减少通道数,降低了模型的复杂性。 第四个路径使用3×3最大池化层,然后使用1×1卷积层来更改通道数。 四个路径都使用适当的填充以使输入和输出具有相同的高度和宽度。 最后沿着每个路径的输出沿着通道尺寸连接在一起,并构成块的输出。 标准块的超参数是每层输出通道的数量。不同kernel的filter,增加了网络的特征提取能力。

GoogleNet结构

GoogLeNet使用总共9个初始块和全局平均池的堆栈来生成其估计值。 块之间的最大池化会降低维数,第一个模块类似于AlexNet和LeNet。框架使用了1)类似VGG的块堆叠形式2)类似NiNNet的全局平均层替代FC层。

 第一个块的代码

b1 = nn.Sequential()
b1.add(nn.Conv2D(64, kernel_size=7, strides=2, padding=3, activation='relu'),
       nn.MaxPool2D(pool_size=3, strides=2, padding=1))

第二个块的代码

b2 = nn.Sequential()
b2.add(nn.Conv2D(64, kernel_size=1, activation='relu'),
       nn.Conv2D(192, kernel_size=3, padding=1, activation='relu'),
       nn.MaxPool2D(pool_size=3, strides=2, padding=1))

 第三个块的代码

b3 = nn.Sequential()
b3.add(Inception(64, (96, 128), (16, 32), 32),
       Inception(128, (128, 192), (32, 96), 64),
       nn.MaxPool2D(pool_size=3, strides=2, padding=1))

第三个块串联连接两个完整的Inception模块。 第一个Inception块的输出通道数为64 + 128 + 32 + 32 = 256,四个路径之间的输出通道数比为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。 

第四个块的代码

b4 = nn.Sequential()
b4.add(Inception(192, (96, 208), (16, 48), 64),
       Inception(160, (112, 224), (24, 64), 64),
       Inception(128, (128, 256), (24, 64), 64),
       Inception(112, (144, 288), (32, 64), 64),
       Inception(256, (160, 320), (32, 128), 128),
       nn.MaxPool2D(pool_size=3, strides=2, padding=1))

第四个模块更复杂。 它串联了五个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最大池化层。 第二和第三路径将首先根据比率减少通道数。 在不同的起始块中,这些比率略有不同。

第五个块的代码和整个网络

b5 = nn.Sequential()
b5.add(Inception(256, (160, 320), (32, 128), 128),
       Inception(384, (192, 384), (48, 128), 128),
       nn.GlobalAvgPool2D())

net = nn.Sequential()
net.add(b1, b2, b3, b4, b5, nn.Dense(10))

第五个模块具有两个Inception模块,分别具有256 + 320 + 128 + 128 = 832和384 + 384 + 128 + 128 = 1024个输出通道。 分配给每个路径的通道数与第三和第四模块中的通道数相同,但具体值不同。 应当注意,第五块后面是输出层。 与NiN一样,此块使用全局平均池化层将每个通道的高度和宽度更改为1。 最后,我们将输出转换为二维数组,然后是一个完全连接的层,其输出数量为标签类的数量。 

为了方便测试,输入大小改为96,测试一下输出

X = np.random.uniform(size=(1, 1, 96, 96))
net.initialize()
for layer in net:
    X = layer(X)
    print(layer.name, 'output shape:\t', X.shape)
sequential0 output shape:    (1, 64, 24, 24)
sequential1 output shape:    (1, 192, 12, 12)
sequential2 output shape:    (1, 480, 6, 6)
sequential3 output shape:    (1, 832, 3, 3)
sequential4 output shape:    (1, 1024, 1, 1)
dense0 output shape:         (1, 10)

 训练

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)

训练结果

loss 0.255, train acc 0.903, test acc 0.894
2272.2 examples/sec on gpu(0)

 

最后的话:

这篇文章发布在CSDN/蓝色的杯子, 没事多留言,让我们一起爱智求真吧.我的邮箱wisdomfriend@126.com.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值