© 2023 yanghn. All rights reserved. Powered by Obsidian
7.3 网络中的网络(NiN)
要点
- NiN 用来替代全连接层,最后的通道数就是输出类别数,现在不常用,但影响了[[7.4 含并行连结的网络(GoogLeNet)]]
- 主要作用:显著减少参数个数,防止过拟合
- 相对于 VGG、AlexNet 这种包含全连接层的网络相比,收敛速度慢,往往需要多个 epoch
7.2 使用块的网络(VGG)、7.1 深度卷积神经网络(AlexNet)这些网络最后都有全连接层,占绝大部分参数:
- 卷积层只需要较少的参数:
- 但卷积层后的第一个全连接层的参数
- LeNet
- AlexNet
- VGG
- LeNet
网络中的网络(NiN)通过减少全连接层来减少这些参数个数,而且可以有效防止过拟合
1. NiN 块
一个卷积层后面跟两个 1 x 1 的卷积层,这些 1 x 1 卷积不会改变图像大小,只会改变通道数
NiN 块示意图,1x 1 卷积层通道数保持一致
具体实现:
import torch
from torch import nn
from d2l import torch as d2l
def nin_block(in_channels, out_channels, kernel_size, strides, padding):
# in_channels 是第一个卷积层输入通道大小,out_channels 是 1x1卷积输出通道
return nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size, strides, padding),
nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU())
1 x 1 的卷积层作用是用来替代全连接层:
2. NiN 架构
交替使用 NiN 块和步幅为 2 的最大池化层,逐步减少图片尺寸,增大通道数,最后使用全局平均池化层得到输出:
net = nn.Sequential(
# 输入是1,还是灰度图
nin_block(1, 96, kernel_size=11, strides=4, padding=0),
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),
# 标签类别数是10
nin_block(384, 10, kernel_size=3, strides=1, padding=1),
nn.AdaptiveAvgPool2d((1, 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)
Sequential output shape: torch.Size([1, 96, 54, 54])
MaxPool2d output shape: torch.Size([1, 96, 26, 26])
Sequential output shape: torch.Size([1, 256, 26, 26])
MaxPool2d output shape: torch.Size([1, 256, 12, 12])
Sequential output shape: torch.Size([1, 384, 12, 12])
MaxPool2d output shape: torch.Size([1, 384, 5, 5])
Dropout output shape: torch.Size([1, 384, 5, 5])
Sequential output shape: torch.Size([1, 10, 5, 5])
AdaptiveAvgPool2d output shape: torch.Size([1, 10, 1, 1])
Flatten output shape: torch.Size([1, 10])
- 经过第一层后张量大小 (224-11+4)/4 = 54 (向下取整,参考[[6.3 填充和步幅]])
- 最后的通道数表示分类的个数,
AdaptiveAvgPool2d
把 5x5 的图像转化为 1x1 用作分类 AdaptiveAvgPool2d
的参数就是输出图片大小,会自动计算池化窗口的大小和步长,以便于输出特征图的大小与预设的目标输出大小相匹配- 后面还有softmax 转化为概率,这个函数写在 训练函数里了([[6.6 卷积神经网络(LeNet)#^f57180]] 的
CrossEntropyLoss
里)
3. 训练
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())
loss 0.563, train acc 0.786, test acc 0.790
3087.6 examples/sec on cuda:0