> For the complete documentation index, see [llms.txt](https://openmmlabbook.gitbook.io/openmmlab-book/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://openmmlabbook.gitbook.io/openmmlab-book/image-classification/early/alexnet.md).

# AlexNet

## AlexNet

AlexNet 是 Alex Krizhevsky、Geoffrey E. Hinton 等人于 2012 年提出的一个神经网络。网络命名自作者的名字。 凭借 AlexNet，来自多伦多大学的获得了 ILSVRC 2012 的冠军，并且他们的成绩远超上一年的冠军以及当年第二名。 在此之前，大规模图像分类仍然依靠手工设计的图像特征以及复杂但是浅层的机器学习算法。 而 AlexNet 的出现是革命性的，自此以后，深度学习为计算机视觉带来了井喷式的发展。

同样作为卷积神经网络，AlexNet 与 14 年前的 LeNet-5 并没有本质上的不同，仍然是卷积、降采样（也称池化）、全连接层的级联。 但得益于高效的 GPU 实现，这个网络的规模远超他的前辈——总共有 6 千万个参数和 65 万个神经元。 此外 AlexNet 也将 ReLU 非线性、dropout 等技术引入剪辑网络，提高了大型神经网络的计算速度并降低神经网络的过拟合现象。

### 网络结构

![](/files/-MOpFCtiezhSqvtDedSr)

AlexNet 包含 5 个卷积层和 3 个全连接层，其中 3 个卷积层后面进行了降采样。 AlexNet 每层的卷积核大小、卷积步长、以及对应的输出大小均已标记在图中。

#### ReLU

在经典的神经网络中，非线性映射通常使用 sigmoid 或者 tanh 函数。 受限于计算机的硬件设计，这些复杂的计算通常要花费很多的时间。

为了提高网络的计算速度，Krizhevsky 等人使用 ReLU (Rectified Linear Unit) 函数 $$f(x) = max(0, x)$$ 作为 AlexNet 的非线性函数。

实验也证明了 ReLU 的效率。作者在 CIFAR10 数据集上训练了一个四层的卷积网络，错误率下降的速度是使用 tanh 的四倍。

通过简单的推到可知，ReLU 的后传计算为

$$
\frac{\partial L}{\partial x\_i} = \frac{\partial L}{\partial y\_i}  \frac{\partial y\_i}{\partial x\_i}
========================================================================================================

\begin{cases}
\frac{\partial L}{\partial y\_i} & \text{if} \~ x\_i > 0\\
0 & \text{if} \~ x\_i \le 0
\end{cases}
\quad 1 \le i \le H\times W \times C
$$

对于值大于 0 的神经元，它直接传回后一层回传的梯度，对于值小于等于 0 的神经元，传回梯度 0． 由于 $$x\_i > 0$$ 与 $$y\_i>0$$ 是等价的，因此在后传的时候，我们可以直接根据 ReLU 层的输出值计算回传的梯度。正是因为如此，ReLU 在前传计算时可以不保存输入值，进而节约一部分内存。 这种做法在许多深度学习框架中都有所采用。

#### Dropout

Dropout 是一种降低神经网络过拟合现象的技术，也是一种正则化技术。 是同一个团队于 2010 年提出的。[Dropout 原始论文](https://www.cs.toronto.edu/~hinton/absps/JMLRdropout.pdf)

![](/files/-MOpFCtjz-MIu5ZjzAOH)

在文章中，作者认为神经网络的过拟合是神经元之间的“协同适应”现象导致的。 试想，在训练过程中，模型中的一些神经元对被输入中的噪声激活（我们把这个神经元产生的特征称为噪声特征）。 当我们使用梯度下降对所有参数进行全局优化的时候，就可能产生过拟合现象： 神经网络会倾向尝试调整后面层的参数，基于噪声特征给出样本类别的预测，而不是尝试调整前面的层的参数，将这个特征变得更好。 因为全连接层参数过多时，拿出几个参数拟合噪声并不困难。 这种神经元之间相互依赖，共同拟合某些噪声样本的现象称为神经元之间的“协同适应”。

dropout 的提出就是为了避免这种现象，在训练阶段，针对某个输入进行前传计算时，我们随机选择一些神经元，并将它们置零，仅使用剩下的神经元参与输出计算。 这强迫后一层的神经元必须“学会”“充分利用”前层所有神经元，而不是依赖具体个别几个前层的神经元。 同时，这也有助于前一层的神经元能学习出更有通用性的特征表达，因为噪声特征不能有效地被后面的层所利用。

（加个例子解释一下上面这段话）

简单而言，参数过多，模型表达能力过强，是导致过拟合的一个主要原因。 由于全连接层的参数较多，Dropout 通常应用于神经网络中的全连接层。

在 AlexNet 中，Dropout 应用于两个 4096 维输出的全连接层，并以 p=0.5 的概率将输入神经元置零。

Dropout 在训练和测试阶段的行为有所不同。在训练阶段，dropout 随机选择一部分单元，将全连接层的一些输入置零

$$
\begin{align}
b\_i &\sim \text{Bernoulli}(p) & 1\le i \le N \\
D(x)\_i &= b\_i \dot x\_i
\end{align}
$$

而在测试阶段，所有的神经元都参与计算，但对应的权重会乘以 p ，这也等价于神经元的响应乘以 p，在深度学习框架中，dropout 通常设计为单独的层，因此常采用后者。

![](/files/-MOpFCtkBCDkhJVB5SvC)

（可以再详细点，多讨论一下数学和编程的细节）

Dropout 在一定程度上也起了模型组合和平均的作用。在训练阶段，一部分神经元被丢弃，被训练的只有模型的一个子图。 这些不同的子图可以被认为是不同的模型，他们共享卷积层输出的特征，但却使用不同的特征组给出最终用的分类预测。

而在测试阶段，所有连接均被重新利用起来。在结果上，着近似于对所有模型的输出进行了平均。

由于 Dropout 与后续出现的 Batch Normalization 存在一定的冲突。因而 BN 出现后，dropout 在现在的网络中也很少使用了。

#### 其他技术

AlexNet 还采用了一些其他技术，如计算 pooling 时使用 3x3 的感受野，但步长设置为 2，使得每个池化的输出有所重叠。 这种有别于传统的设置是通过实验得来的，作者发现通过重叠的池化可以轻微降低过拟合的现象。

AlexNet 还使用了 Local Response Normalization 。这种技术在现在已经不再使用，因此不做详细介绍。

### AlexNet 的 Pytorch 实现

`torchvision`中 AlexNet 的实现如下，已经包含了上述所有内容。

```python
class AlexNet(nn.Module):

    def __init__(self, num_classes=1000):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
            # ReLU 的原地计算
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(64, 192, kernel_size=5, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(192, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
        )
        # Adaptive average pooling可以将任意大小的featuremap pool至6x6的大小，以应对不同的输入图像尺寸
        self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
        self.classifier = nn.Sequential(
            # Dropout
            nn.Dropout(),
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Linear(4096, num_classes),
        )

    def forward(self, x):
        x = self.features(x)
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        return x
```

## ZFNet

ZFNet 是 AlexNet 的一个变种，和 AlexNet 唯一的区别在于第一个卷积层的配置。AlexNet 使用 11x11 的卷积核，步长为 4，ZFNet 使用 7x7 的卷积核，步长为 2. 之所以采用这样的配置，是因为作者在分析卷积网络学习出的特征的时候，发现使用大卷积核会导致中频特征的消失，而使用大步长会导致的特征中出现一些瑕疵。 而使用更小的卷积核并降低步长可以解决这两个问题。

ZFNet 源自论文《Visualizing and Understanding Convolutional Networks》，ZFNet 命名也来自两位作者 Zeiler 和 Fergus 的首字母。 Zeiler 等人也凭借 ZFNet 获得了 ILSVRC 2013 的冠军。
