深度学习笔记023 NiN 网络中的网络


在这之前,在好好学一下1x1卷积层的知识:

其实就是改变维度和增加非线性性

https://blog.csdn.net/yaochunchu/article/details/95527760?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7EHighlightScore-3.queryctrv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7EHighlightScore-3.queryctrv2&utm_relevant_index=2

NiN,用得不多,但是它提出了很多被其他网络用到的概念。

三个网络的全连接层的参数个数:

 全连接层:参数非常多,基本上一个网络的绝大多数参数都分布在全连接层,参数多不仅占用很多内存和带宽,(不断访问内存占用了大量的时间),同时容易带来非常严重的过拟合问题。

 NiN思想:我不要全连接层,我要用卷积层替代掉全连接层。

NiN块:一个卷积层,跟着两个1x1的卷积层(可以认为1x1的卷积层就是全连接层)

 NiN架构:

  1、没有全连接层。

  2、交替使用NiN块和步幅为2的最大池化层,逐步减少高宽并增大通道数。

  3、最后使用全局的平均池化层得到输出,其输出通道是类别数。

 全局平均池化层的高宽 = = 输入的高宽 (我对每一个通道,拿出最大值)

总结:

  NiN块使用卷积层和两个1x1的卷积层,后者对于每个像素增加了非线性性;

  NiN使用全局平均池化层来代替VGG和AlexNet的全连接层。(全局平均:是因为会将原高宽变为1x1,如果选最大,会损失的信息实在是太多了)

  因为使用的参数更少,不容易过拟合。

Q&A:

没学到什么东西感觉。

结果:可以看到基本没有过拟合的问题,另外还不如AlexNet准确率高,而且还没有AlexNet快,所以NiN一开始说的就是,NiN最大的贡献是对1x1卷积层的利用,而不是这个网络本身有多大能力,这个网络本身用的并不是很多。

 总之一件事,要么更宽,要么更深,MLP看起来更宽的极端,NiN看起来更深的极端,而VGG比较中庸。

代码

import torch
from torch import nn
from d2l import torch as d2l


def nin_block(in_channels, out_channels, kernel_size, strides, padding):
    return nn.Sequential(
        nn.Conv2d(in_channels, out_channels, kernel_size, strides, padding),
        nn.ReLU(),
        # 用来当全连接层的1x1卷积
        nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU(),
        nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU())

net = nn.Sequential(
    # 可以看到,通道数是完全基于AlexNet写的
    nin_block(1, 96, kernel_size=11, strides=4, padding=0),# 因为用的灰度图,所以输入通道数为1
    nn.MaxPool2d(3, stride=2),
    nin_block(96, 256, kernel_size=5, strides=1, padding=2),
    nn.MaxPool2d(3, stride=2),
    nin_block(256, 384, kernel_size=3, strides=1, padding=1),
    nn.MaxPool2d(3, stride=2),
    nn.Dropout(0.5),  # 到这里,大小是1x384x高x宽,1是批量大小
    # 标签类别数是10
    nin_block(384, 10, kernel_size=3, strides=1, padding=1),# 到这里,大小是1x10x高x宽
    nn.AdaptiveAvgPool2d((1, 1)), # 全局平均池化层,高宽都会变成1,大小就成了1x10x1x1
    # 将四维的输出转成二维的输出,其形状为(1,10)
    nn.Flatten())


# 查看每个块的输出形状
X = torch.rand(size=(1, 1, 224, 224))
for layer in net:
    X = layer(X)
    print(layer.__class__.__name__,'output shape:\t', X.shape)

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