一、论文总览

该论文提出了一种基于深度卷积神经网络(CNN)的图画分类办法,并在ILSVRC-2010和ILSVRC-2012图画分类挑战赛中取得了新的记载。首要工作和奉献如下:

  1. 练习了其时最大的卷积神经网络,包含5个卷积层和3个全衔接层,参数量达6000万个,在ILSVRC-2010测验集上取得了top-1错误率37.5%,top-5错误率17.0%,明显优于之前的办法。

  2. 提出了几个新的网络架构优化技巧,如ReLU激活函数、数据增强、部分呼应归一化(Local Response Normalization)、堆叠池化(Overlapping Pooling) 等,这些技巧明显进步了网络的功能。

3.模型并行(model parrallel): 运用了两个GTX 580 3GB显卡并行练习,完成了高效的GPU卷积操作,明显削减了练习时间。

  1. 运用了随机失活(dropout) 等正则化办法来操控过拟合,并详细剖析了其有用性。

  2. 在ILSVRC-2012比赛中运用该模型,取得了top-5错误率18.2%的成果,明显优于第二名的16.4%。

  3. 获得了很多视觉知识,如不同层级的卷积核表明,高维特征向量的类似度计算等。

总体而言,该论文经过构建其时最大的卷积神经网络并运用各种优化技巧,在ImageNet等大规模图画数据集上取得了新的state-of-the-art成果,对后续的计算机视觉研讨产生了重大影响。

二、数据预处理/增强

运用的是ImageNet数据集,将一切图画缩放到256×256巨细,假如图画尺寸不是正方形,先按份额缩小,然后从中间裁剪出256×256巨细的正方形区域。

AlexNet论文精读及模型详解

留意:此处是直接运用的原始RGB图片,没有进行SIFT的特征提取,这也被看作端到端的练习模型,简化了练习以及推理的流程,这种端到端的思维深刻影响了深度学习模型的开展,现在大多数模型均是选用端到端的办法进行练习的。

一起论文运用两种办法进行数据增强第一种是对每张图片进行裁取和翻转,经过处理每张图片会得到十张图片输入模型预测出成果。第二种是对图片的RGB三个色彩通道进行平移和调整,即进行RGB通道强度调整。

AlexNet论文精读及模型详解

三、AlexNet网络结构剖析

论文中的模型作者用了两块GPU进行练习,即运用了模型并行的办法,这种办法会给模型的工程实践带来困难,所以在之后跟着显卡功能的进步已很少运用,但现在在NLP领域,LLM(large language model)的练习再次遇到了算力瓶颈,以GPT为代表的大模型再次运用模型并行的办法进行练习。

AlexNet论文精读及模型详解

模型一共有八层,前五层是CNN层,紧接着跟着两个全衔接层,最终是一个1000类的softmax分类层。第二层,第四层,第五层的CNN层后面均跟着Max pooling层和LRM层(local response normalization,作用是避免过拟合)。两层全衔接层均运用了Dropout的办法避免过拟合。实际上这两层全衔接层是参数最多的,构成了模型练习的瓶颈,也是或许造成过拟合的罪魁祸首,为了避免过拟合,这两层全衔接层都运用了Dropout的办法。

LRM层现在根本已不再运用,其作用现在遍及认为也比较小,故本文不再做介绍,只需知道论文作者运用其本意是为了避免过拟合,进步模型泛化才能。

其结构图能够简化为在单块gpu上进行练习的。

AlexNet论文精读及模型详解

图片来源:blog.csdn.net/guzhao9901/…

原图输入256 256,实际上进行了随机裁剪,实际巨细为227 227。

1️⃣卷积层C1

C1的根本结构:卷积–>部分呼应归一化(LRN)–>ReLU–>池化

  • 卷积:输入为227 227 3,运用96个11113的卷积核,padding = 0,stride = 4。 FeatureMap为(227-11+02+4)/4 = 55,即555596。
  • 部分呼应归一化(LRN):对ReLU激活函数前的输出进行部分呼应归一化处理。
  • 激活函数:选用ReLU激活函数。
  • 池化:33的池化核,padding = 0,stride = 2,池化后的FeatureMap为(55-3+02+2)/2=27, 即C1输出为272796(若依照论文将数据分到两个GPU中处理,每组输出为272748)。

2️⃣卷积层C2

C2的根本结构:卷积–>部分呼应归一化(LRN)–>ReLU–>池化

  • 卷积:输入为272796,运用256个5596的卷积核,padding = 2, stride = 1。 FeatureMap为(27-5+22+1)/1 = 27,即2727256。
  • 部分呼应归一化(LRN):在ReLU激活之前相同执行部分呼应归一化操作。
  • 激活函数:运用ReLU激活函数。
  • 池化:3 3的池化核,padding = 0,stride = 2,池化后的FeatureMap为(27-3+0+2)/2=13, 即C2输出为1313256(若按论文方式分配到两个GPU,则每组输出为1313128)。

3️⃣卷积层C3

C3的根本结构为:卷积–>ReLU

  • 卷积:输入为1313256,运用384个33256的卷积核,padding = 1,stride = 1。 FeatureMap为(13-3+12+1)/1 = 13,即1313384。
  • 激活函数:选用ReLU激活函数,C3输出为1313384(若依照论文将数据分配到两个GPU中处理,则每组输出为1313192)。

4️⃣ 卷积层C4

C4的根本结构为:卷积–>ReLU

  • 卷积:输入为1313384,运用384个33384的卷积核,padding = 1,stride = 1。 FeatureMap为1313384。
  • 激活函数:选用ReLU激活函数,C4输出为1313384(若按论文方式分配到两个GPU,则每组输出为1313192)。

5️⃣ 卷积层C5

C5的根本结构为:卷积–>ReLU–>池化

  • 卷积:输入为1313384,运用256个33384的卷积核,padding = 1,stride = 1。 FeatureMap巨细仍为1313256。
  • 激活函数:选用ReLU激活函数。
  • 池化:池化核巨细为3 3,padding = 0,stride = 2,池化后的FeatureMap为(13-3+02+2)/2=6, C5输出为66256(若依照论文分到两个GPU中处理,每组输出为66128)。

6️⃣ 全衔接层FC6

FC6的根本结构为:卷积(全衔接完成)–>ReLU–>Dropout

  • 全衔接:实际上经过卷积进行等效的全衔接操作,输入为66256,运用4096个66256的卷积核,padding = 0,stride = 1, FeatureMap巨细为114096。
  • 激活函数:选用ReLU激活函数。
  • Dropout:在全衔接层中运用Dropout技术,随机丢掉一部分神经元节点,以避免过拟合,终究FC6输出为114096。

7️⃣全衔接层FC7

FC7的根本结构为:全衔接–>ReLU–>Dropout

  • 全衔接:直接进行全衔接操作,输入维度为114096。
  • 激活函数:选用ReLU激活函数。
  • Dropout:相同运用Dropout避免过拟合,FC7输出为114096。

8️⃣ 全衔接层FC8

FC8的根本结构为:全衔接–>softmax

  • 全衔接:对上一层的输出进行全衔接操作,输入维度为114096。
  • softmax:最终选用softmax激活函数进行分类,输出维度为111000,对应1000类物体类别概率散布。

四、ReLU激活函数

ReLU(x)=max(0,x)ReLU(x)=max(0,x)

ReLU函数的导数: dReLU(x)dx={1ifx>00ifx≤0frac{dReLU(x)}{dx} = begin{cases} 1 & text{if } x > 0 \ 0 & text{if } x leq 0 end{cases}

(x)=11+e−xsigma(x)=frac{1}{1+e^{-x}}

Sigmoid函数的导数是: d(x)dx=(x)∗(1−(x))=e−x(1+e−x)2frac{dsigma(x)}{dx} = sigma(x) * (1 – sigma(x)) = frac{e^{-x}}{(1 + e^{-x})^2}

AlexNet论文精读及模型详解

一个sigmoid函数大致相当于两个ReLU函数

关于ReLU的具体剖析能够见这篇文章:(暂未更新)

五、堆叠池化(overlapping pooling)

堆叠池化(overlapping pooling)是一种改善传统的池化层的策略。传统的池化层通常由距离必定距离的池化单元组成,每个单元对相邻的神经元输出进行汇总。相邻池化单元所覆盖的区域不堆叠。而堆叠池化则经过设置池化单元之间的距离小于池化区域巨细来完成堆叠,例如运用距离2像素的池化单元和区域巨细为3×3的池化单元。文中说到,相比传统的非堆叠池化,运用堆叠池化能够将模型在ImageNet数据集上的top-1错误率下降0.4%,top-5错误率下降0.3%。因此,堆叠池化是一种改善池化层规划的策略,能够进步模型功能。

六、Dropout

dropout是一种有用的正则化办法,能够削减深度卷积神经网络中全衔接层过拟合的问题。

留意:dropout是解决的全衔接层过拟合的问题,所以论文中的两个全衔接层运用了dropout,而CNN层没有运用dropout

dropout的首要思维是:在每次前向传达时,以必定概率(如0.5)将每个隐藏神经元的输出置为0,使得每个神经元在每次前向传达时都有必定的概率不参与计算。论文中认为,这样做的目的是打破全衔接层中不同神经元之间的复杂共适应性,迫使每个神经元学习更强大的特征表明,对不同的随机子集都有用。在测验时,不进行dropout,而是将每个神经元的输出乘以必定份额(如0.5),近似于取一切或许dropout网络成果的几何平均。

现在遍及认为dropout相当于一个L2正则项,能够有用削减过拟合问题,一起让模型更强大。值得留意的是,dropout在练习时会增加迭代收敛次数,但能够大大进步模型的泛化才能。

七、练习细节

  1. 运用随机梯度下降(SGD Stochastic Gradient Descent) 进行练习,批巨细为128,动量为0.9,权重衰减为0.0005。发现权重衰减对模型学习非常重要。
  2. 对每个层的权重进行高斯初始化,均值为0,标准差为0.01。留意对权重进行均值为0标准差为0.01的高斯初始化现在非常常见,只有对一些特别深的网络例如GPT这样的模型,才会对权重做均值为0标准差为0.02的高斯初始化。 对第二、四、五卷积层以及全衔接隐藏层的神经元偏置进行常数1初始化,其余层偏置初始化为常数0。 (偏置常数1初始化理论性不强,多为试验炼丹成果,现在遍及将偏置初始化为常数0,成果也不差)
  3. 运用一切层持平的固定学习率,并在验证丢失停止改善时手动将学习率变为本来的十分之一。初始学习率为0.01,练习过程中下降3次。
  4. 练习了大约90个周期,耗时5-6天在两块NVIDIA GTX 580 3GB GPU上进行练习。
  5. 丢失函数是最小化交叉熵,即最大化标签的正确对数概率。

八、PyTorch代码完成

import time
import torch
from torch import nn, optim
import torchvision
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
class AlexNet(nn.Module):
    def __init__(self):
        super(AlexNet, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(1, 96, 11, 4), # in_channels, out_channels, kernel_size, stride, padding
            nn.ReLU(),
            nn.MaxPool2d(3, 2), # kernel_size, stride
            # 减小卷积窗口,运用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
            nn.Conv2d(96, 256, 5, 1, 2),
            nn.ReLU(),
            nn.MaxPool2d(3, 2),
            # 接连3个卷积层,且运用更小的卷积窗口。除了最终的卷积层外,进一步增大了输出通道数。
            # 前两个卷积层后不运用池化层来减小输入的高和宽
            nn.Conv2d(256, 384, 3, 1, 1),
            nn.ReLU(),
            nn.Conv2d(384, 384, 3, 1, 1),
            nn.ReLU(),
            nn.Conv2d(384, 256, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(3, 2)
        )
         # 这儿全衔接层的输出个数比LeNet中的大数倍。运用丢掉层来缓解过拟合
        self.fc = nn.Sequential(
            nn.Linear(256*5*5, 4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(4096, 4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            # 输出层。因为这儿运用Fashion-MNIST,所以用类别数为10,而非论文中的1000
            nn.Linear(4096, 10),
        )
    def forward(self, img):
        feature = self.conv(img)
        output = self.fc(feature.view(img.shape[0], -1))
        return output

参考资料: