目录
一、AlexNet介绍
1、历史背景
AlexNet赢得了2012年ImageNet竞赛的冠军。AlexNet本质上相当于一个更深更大的LeNet,相比于LeNet的主要改进有下面三个:
- 丢弃法: AlexNet通过丢弃法控制全连接层的模型复杂度,在多个全连接层组成的多层感知机里面使用了丢弃法(Dropout),而LeNet只使用了权重衰减。
- **ReLU:**将激活函数从LeNet的Sigmoid改成了ReLU,ReLU相对于Sigmoid的梯度更大。
- **MaxPooling:**将平均池化改成了最大池化,使得输出的值比较大,梯度相对来说就比较大,训练更加容易。
- **数据增强:**AlexNet在训练时增加了大量的图像增强数据,如翻转、裁切和变色。这使得模型更加健壮,更大的样本量有效地减少了过拟合。
2、AlexNet与LeNet模型对比
(1)第一层卷积
(2)中间卷积层
(3)多层感知机
3、总结
二、代码实现
1、设计逻辑
在AlexNet网络的最底层,模型学习到了一些类似于传统滤波器的特征抽取器。下图是从AlexNet论文`Krizhevsky.Sutskever.Hinton.2012`复制的,描述了底层图像特征。
AlexNet的更高层建立在这些底层表示的基础上,以表示更大的特征,如眼睛、鼻子、草叶等等。而更高的层可以检测整个物体,如人、飞机、狗或飞盘。最终的隐藏神经元可以学习图像的综合表示,从而使属于不同类别的数据易于区分。尽管一直有一群执着的研究者不断钻研,试图学习视觉数据的逐级表征,然而很长一段时间里这些尝试都未有突破。深度卷积神经网络的突破出现在2012年。突破可归因于两个关键因素:数据和硬件。
2、模型搭建
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(), # 本文使用了Fashion-MNIST数据集,因此对模型进行了一些修改,输入通道数变为了1
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))
我们构造一个高度和宽度都为224的单通道数据,来观察每一层输出的形状。它与中的AlexNet架构相匹配。
python
X = torch.randn(1, 1, 224, 224)
for layer in net:
X=layer(X)
print(layer.__class__.__name__,'output shape:\t',X.shape)
python
Conv2d output shape: torch.Size([1, 96, 54, 54])
ReLU output shape: torch.Size([1, 96, 54, 54])
MaxPool2d output shape: torch.Size([1, 96, 26, 26])
Conv2d output shape: torch.Size([1, 256, 26, 26])
ReLU output shape: torch.Size([1, 256, 26, 26])
MaxPool2d output shape: torch.Size([1, 256, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 256, 12, 12])
ReLU output shape: torch.Size([1, 256, 12, 12])
MaxPool2d output shape: torch.Size([1, 256, 5, 5])
Flatten output shape: torch.Size([1, 6400])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 10])
3、读取数据集
尽管原文中AlexNet是在ImageNet上进行训练的,但本文在这里使用的是Fashion-MNIST数据集。因为即使在现代GPU上,训练ImageNet模型,同时使其收敛可能需要数小时或数天的时间。将AlexNet直接应用于Fashion-MNIST的一个问题是,Fashion-MNIST图像的分辨率为 ,像素低于ImageNet图像。
为了解决这个问题,我们将它们增加到 (通常来讲这不是一个明智的做法,但在这里这样做是为了有效使用AlexNet架构)。这里需要使用`d2l.load_data_fashion_mnist`函数中的`resize`参数执行此调整(不理解的可以参考文章Softmax回归load_data_fashion_mnist函数的注释)。
python
batch_size = 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
4、训练AlexNet
现在AlexNet可以开始被训练了。与LeNet相比,这里的主要变化是使用更小的学习速率训练,这是因为网络更深更广、图像分辨率更高,训练卷积神经网络就更昂贵。
python
lr, num_epochs = 0.01, 10
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
python
loss 0.331, train acc 0.878, test acc 0.883
3941.8 examples/sec on cuda:0
5、总结
- AlexNet的架构与LeNet相似,但使用了更多的卷积层和更多的参数来拟合大规模的ImageNet数据集。
- 今天,AlexNet已经被更有效的架构所超越,但它是从浅层网络到深层网络的关键一步。
- 尽管AlexNet的代码只比LeNet多出几行,但学术界花了很多年才接受深度学习这一概念,并应用其出色的实验结果。这也是由于缺乏有效的计算工具。
- Dropout、ReLU和预处理是提升计算机视觉任务性能的其他关键步骤。