注:书中对代码的讲解并不详细,本文对很多细节做了详细注释。另外,书上的源代码是在Jupyter Notebook上运行的,较为分散,本文将代码集中起来,并加以完善,全部用vscode在python 3.9.18下测试通过,同时对于书上部分章节也做了整合。
Chapter7 Modern Convolutional Neural Networks
7.3 Network in Networks: NiN
NiN的想法是在每个像素位置(针对每个高度和宽度)应用一个全连接层。如果我们将权重连接到每个空间位置,我们可以将其视为 1 × 1 1\times 1 1×1卷积层,或作为在每个像素位置上独立作用的全连接层。从另一个角度看,即将空间维度中的每个像素视为单个样本,将通道维度视为不同特征(feature)。NiN块以一个普通卷积层开始,后面是两个 1 × 1 1 \times 1 1×1的卷积层(充当带有ReLU激活函数的逐像素全连接层)。NiN和AlexNet之间的一个显著区别是NiN完全取消了全连接层而使用NiN块,其输出通道数等于标签类别的数量,且在最后用一个全局平均汇聚层(global average pooling layer),生成一个对数几率(logits)。NiN设计的一个优点是显著减少了模型所需参数的数量,然而在实践中,这种设计有时会增加训练模型的时间。
import torch
from torch import nn
from d2l import torch as d2l
import matplotlib.pyplot as plt
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(),
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(
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,设置输出通道为10使得输出通道数等于标签数
nin_block(384, 10, kernel_size=3, strides=1, padding=1),
nn.AdaptiveAvgPool2d((1, 1)),
#全局平均汇聚后每个输出值都代表了对应通道整个输入的平均值,这导致网络更加关注图像中重要的特征,而不关注它们的位置
nn.Flatten())#将四维的输出转成二维的输出,其形状为(批量大小,10)
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())
plt.show()
训练结果: