Skip to content

AlexNet

一、AlexNet 的历史意义

2012 年,AlexNet 的出现是计算机视觉领域的一个重大突破。在此之前,大家都用手工设计的特征来做图像识别,而 AlexNet 首次证明了机器学习到的特征比手工设计的特征效果更好,一举打破了当时计算机视觉研究的现状。

它用了 8 层卷积神经网络,以巨大的优势赢得了 2012 年 ImageNet 图像识别挑战赛(ImageNet 是当时最大的图像数据集,有 1000 多万张图片,1000 个类别)。而且它是第一个能在 GPU 上高效运行的深度卷积网络,利用 GPU 的并行计算能力解决了卷积和矩阵乘法的计算瓶颈,当时用了两个 NVIDIA GTX580 GPU 来实现快速卷积运算。

二、AlexNet 的模型设计

AlexNet 和我们之前学的 LeNet 设计理念很像,但要深很多、复杂很多:

  1. 网络层数更深:AlexNet 一共有 8 层,包括 5 个卷积层、2 个全连接隐藏层、1 个全连接输出层,而 LeNet 只有 7 层(卷积层 + 全连接层)。

  2. 卷积窗口和通道数的变化

    • 第一层用了 11×11 的大卷积窗口,因为 ImageNet 的图像比 MNIST 大 10 倍以上,需要更大的窗口来捕捉目标;步幅设为 4,用来快速缩小输出的尺寸。

    • 第二层把卷积窗口缩小到 5×5,还加了填充,让输入和输出的尺寸一致;之后的卷积层都用 3×3 的小窗口。

    • 每一层的卷积通道数是 LeNet 的 10 倍,第一层就有 96 个通道,能捕捉更多的特征。

  3. 汇聚层的使用:在第一层、第二层和第五层卷积层之后,都加了 3×3 窗口、步幅为 2 的最大汇聚层,用来缩小特征图的尺寸。

  4. 巨大的全连接层:最后一个卷积层之后有两个全连接层,每个都有 4096 个输出,这两个层的参数就占了将近 1GB 的显存。当年因为 GPU 显存小,原版 AlexNet 用了双 GPU 来分担参数,现在 GPU 显存足够了,就不需要这么做了。

从LeNet(左)到AlexNet(右)

从LeNet(左)到AlexNet(右)¶

三、激活函数的改进

AlexNet 把原来的 sigmoid 激活函数换成了 ReLU 激活函数,这是一个很重要的改进:

  1. 计算更简单:ReLU 不需要像 sigmoid 那样做复杂的求幂运算,计算更快。

  2. 更容易训练:sigmoid 函数的输出如果接近 0 或者 1 的时候,梯度几乎为 0,反向传播的时候没法更新模型参数;而 ReLU 在正区间的梯度一直是 1,就算模型参数初始化得不太好,也能正常训练。

四、容量控制和数据预处理

为了避免过拟合,AlexNet 做了两个重要的处理:

  1. 暂退法(Dropout):在全连接层用了暂退法,随机让一部分神经元不工作,减少模型的复杂度,避免过拟合;而 LeNet 只用了权重衰减(L2 正则化)来控制复杂度。

  2. 数据增强:训练的时候对图像做了很多增强,比如随机翻转、裁切、改变颜色,这样相当于增加了很多训练样本,让模型更健壮,减少过拟合。

五、代码实现(PyTorch 版)

我们用 PyTorch 来实现一个精简版的 AlexNet,适合在 Fashion-MNIST 数据集上训练:

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

# 定义AlexNet模型
net = nn.Sequential(
    # 第一层:11×11卷积,步幅4,填充1,输出96个通道
    nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 第二层:5×5卷积,填充2,输出256个通道
    nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 三个连续的3×3卷积,输出通道数先增加后减少
    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(),
    # 全连接层,用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分类,所以输出10
    nn.Linear(4096, 10)
)

我们可以测试一下每一层的输出形状:

python
# 测试模型的输出形状
X = torch.randn(1, 1, 224, 224)
for layer in net:
    X = layer(X)
    print(layer.__class__.__name__, '输出形状:\t', X.shape)

运行结果会显示每一层的输出形状,比如第一层卷积之后是torch.Size([1, 96, 54, 54]),经过池化之后变成torch.Size([1, 96, 26, 26]),最后输出是torch.Size([1, 10])

六、读取数据集

原来的 AlexNet 是在 ImageNet 上训练的,但 ImageNet 太大了,我们用 Fashion-MNIST 来演示。不过 Fashion-MNIST 的图像是 28×28 的,而 AlexNet 是为 224×224 的图像设计的,所以我们需要把图像 resize 到 224×224:

python
batch_size = 128
# 加载数据集,把图像resize到224×224
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)

七、训练模型

训练 AlexNet 的时候,我们要用比 LeNet 更小的学习率,因为网络更深、图像分辨率更高,训练的成本更高:

python
lr, num_epochs = 0.01, 10
# 训练模型,用d2l的训练函数
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

训练完成之后,我们可以看到模型在测试集上的准确率比 LeNet 高很多,因为 AlexNet 能捕捉更多的特征。

八、小结

  1. AlexNet 是深度学习的一个里程碑,它证明了机器学习到的特征比手工设计的更好,是从浅层网络到深层网络的关键一步。

  2. AlexNet 的改进包括:更深的网络结构、用 ReLU 代替 sigmoid、用暂退法控制过拟合、用数据增强增加训练样本。

  3. 虽然现在有比 AlexNet 更高效的模型,但 AlexNet 的设计思路对后来的深度学习模型影响很大。

(注:文档部分内容可能由 AI 生成) 源地址

京ICP备2024093538号-1