1 背景
AlexNet由多伦多大学的Alex Krizhevsky、Ilya Sutskever和Geoffrey Hinton在2012年的ImageNet图像分类竞赛中提出,并以优异成绩获得第一名。在此之前,虽然上一节介绍的LeNet获得了一定影响力,但由于当时的算力不足和数据集较小,卷积神经网络并没有得到广泛应用。ImageNet数据集和AlexNet的出现改变了这一切,开启了卷积神经网络的时代。
2 原理
为了增加算力,AlexNet实际设计了两个GPU并行计算的结构,如下图所示

为了方便理解本质, 书中忽略了AlexNet模型在双GPU上运行的特点,并将其结构和LetNet进行了对比:

图中可以看到AlexNet基于LeNet的几个改进:1.输入数据规模更大了,通道数、高度、宽度都增加了。2.多了3个卷积层和一个汇聚层,网络更深了。3.卷积层的卷积核和全连接层的节点数更多了,卷积和汇聚窗口也有所调整,总体来看,除了汇聚层,每一层参数变多了。
除了图中能看到的改进,还有一些没有画出来的改进:1.AlexNet将sigmoid激活函数更改为ReLU激活函数,ReLU激活函数的计算更简单,而且能有效避免梯度消失问题。2.AlexNet通过暂退法控制全连接层的模型复杂度,而LeNet只使用了权重衰减。3.为了进一步扩充数据,AlexNet在训练时增加了大量的图像增强数据,如翻转、裁切和变色。 这使得模型更健壮,更大的样本量有效地减少了过拟合。
有一点需要注意,虽然书中提到了LeNet和AlexNet都用了权重衰减,但是实现的d2l.train_ch6()函数中的SGD优化器中没有指定衰减率,似乎没有进行权重衰减。
3 实现
3.1 模型定义
由于数据集还是采用之前的Fashion-MNIST数据集,在模型的输入层通道数从原来的3改为1,且最后一层输出长度从原来的1000修改为10。
python
import torch
from torch import nn
from d2l import torch as d2l
net = nn.Sequential(
# 这里使用一个11*11的更大窗口来捕捉对象。
# 同时,步幅为4,以减少输出的高度和宽度。
# 另外,输出通道的数目远大于LeNet
nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
# 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
# 使用三个连续的卷积层和较小的卷积窗口。
# 除了最后的卷积层,输出通道的数量进一步增加。
# 在前两个卷积层之后,汇聚层不用于减少输入的高度和宽度
nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),
nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Flatten(),
# 这里,全连接层的输出数量是LeNet中的好几倍。使用dropout层来减轻过拟合
nn.Linear(6400, 4096), nn.ReLU(),
nn.Dropout(p=0.5),
nn.Linear(4096, 4096), nn.ReLU(),
nn.Dropout(p=0.5),
# 最后是输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
nn.Linear(4096, 10))
下面展示了每一层输出的形状(B,C,H,W):
python
X = torch.randn(1, 1, 224, 224)
for layer in net:
X=layer(X)
print(layer.__class__.__name__,'output shape:\t',X.shape)

3.2 模型训练
由于Fashion-MNIST数据集中的图像大小为28*28需要通过resize参数将其缩放为224*224的图像(只指定一个参数时为等比缩放)。
python
batch_size = 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
python
lr, num_epochs = 0.01, 10
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

这次训练耗时较长,在我的电脑上使用RTX3050GPU训练耗时达到13分多,而上一章的LeNet训练只花费了一分钟左右。
参考文献
1\]《动手学深度学习》,https://zh-v2.d2l.ai/ \[2\] Alex Krizhevsky, Ilya Sutskever, and Geoffrey E. Hinton. 2017. ImageNet classification with deep convolutional neural networks. Commun. ACM 60, 6 (June 2017), 84--90. https://doi.org/10.1145/3065386