Python----经典神经网络(《ImageNet Classification with Deep Convolutional Neural Networks》论文和AlexNet网络构建)

一、论文的基本信息

  • 标题: ImageNet Classification with Deep Convolutional Neural Networks(使用深度卷积神经网络的ImageNet分类)

  • 作者: Alex Krizhevsky, Ilya Sutskever, Geoffrey E. Hinton

  • 单位: University of Toronto(多伦多大学)

  • 发表会议: NIPS 2012

二、主要内容

        这篇论文的主要贡献在于,他们训练了一个大型的深度卷积神经网络(CNN),以对ImageNet LSVRC-2010竞赛中的120万张高分辨率图像进行分类,这些图像属于1000个不同的类别。 该网络在测试数据上取得了显著成果,top-1和top-5的错误率分别为37.5%和17.0%,远超当时的现有技术水平。

        这个神经网络拥有6000万个参数和65万个神经元,由五个卷积层、一些最大池化层以及三个全连接层和一个1000路softmax层构成。 为了加快训练速度,他们采用了非饱和神经元和高效的GPU卷积运算实现。 为了减少全连接层中的过拟合现象,他们使用了一种称为“dropout”的正则化方法,并证明该方法非常有效。 此外,他们在ILSVRC-2012竞赛中使用了该模型的一个变体,并取得了15.3%的top-5测试错误率,而第二名的成绩为26.2%。

三、研究的背景

        当时,物体识别主要依赖于机器学习方法。 为了提高物体识别的性能,可以采用更大的数据集、更强大的模型以及更好的防止过拟合技术。 然而,之前带有标签的图像数据集相对较小(通常只有几万张图像,例如NORB、Caltech-101/256和CIFAR-10/100)。 虽然简单识别任务在这样规模的数据集上表现良好,但现实场景中的物体具有相当大的可变性,因此需要更大的训练集。 ImageNet数据集的出现,包含超过1500万张带有标签的高分辨率图像,解决了这个问题。  

        为了从数百万张图像中学习数千个对象,需要一个具有强大学习能力的模型。 由于物体识别任务的复杂性,仅仅依靠大型数据集是不够的,模型还需要大量的先验知识。 卷积神经网络(CNN)正是这样一类模型,它们可以通过调整深度和宽度来控制模型容量,并且对图像的性质具有很强且基本正确的假设(例如,统计数据的平稳性和像素依赖的局部性)。 与具有相似大小层的标准前馈神经网络相比,CNN具有更少的连接和参数,因此更容易训练,并且理论上的最佳性能可能仅略逊于前者。

四、数据集

        ImageNet是一个包含超过1500万张带有标签的高分辨率图像的数据集,这些图像属于大约22,000个类别。 图像来自网络,并由人工使用Amazon Mechanical Turk众包工具进行标注。 从2010年开始,作为Pascal Visual Object Challenge的一部分,举办了ImageNet Large-Scale Visual Recognition Challenge(ILSVRC)年度竞赛。 ILSVRC使用ImageNet的一个子集,其中包含1000个类别,每个类别大约有1000张图像。 总共有大约120万张训练图像、50,000张验证图像和150,000张测试图像。 由于ILSVRC-2010是唯一提供测试集标签的ILSVRC版本,因此作者在该版本上进行了大部分实验,同时也在ILSVRC-2012数据集上报告了结果。 ImageNet报告两种错误率:top-1和top-5错误率。  

        由于ImageNet包含各种分辨率的图像,而他们的系统需要固定的输入维度,因此作者将图像下采样到固定的256x256分辨率。 对于矩形图像,他们首先将图像缩放,使较短的边长为256,然后从结果图像中裁剪出中心的256x256区域。 除了从每个像素中减去训练集上的平均活动外,没有对图像进行任何其他预处理。 因此,他们使用像素的原始RGB值(居中处理后)训练网络。

五、网络架构 

        该网络的架构如上图所示,包含八个学习层:五个卷积层和三个全连接层

3.1、ReLU非线性

        传统的神经元输出建模方式是使用函数f(x) = tanh(x)或f(x) = (1 + e^(-x))^(-1)。 但就使用梯度下降的训练时间而言,这些饱和非线性函数比非饱和非线性函数f(x) = max(0, x)慢得多。 作者采用了Nair和Hinton提出的方法,将具有这种非线性函数的神经元称为Rectified Linear Units(ReLU)。 带有ReLU的深度卷积神经网络的训练速度比带有tanh单元的网络快好几倍。

3.2、多GPU训练

        单个GTX 580 GPU只有3GB的内存,这限制了其上可训练的网络的最大尺寸。 而120万个训练样本足以训练出大到无法放在单个GPU上的网络,因此作者将网络分布在两个GPU上。 他们采用的并行化方案基本上是将一半的核(或神经元)放在每个GPU上,并且只有在某些层进行GPU之间的通信。

3.3、局部响应归一化

        LRN 首先是在 AlexNet 中首先,被定义,它的目的在于卷积(即 Relu 激活 函数出来之后的)值进行局部的归一化。

        在神经生物学中,有一个概念叫做侧抑制(lateral inhibitio),指的是被激 活的神经元会抑制它周围的神经元,而归一化(normalization)的目的就 是“抑制”,两者不谋而合,这就是局部归一化的动机,它就是借鉴“侧抑制”的 思想来实现局部抑制,当我们使用Relu激活函数的时候,这种局部抑制显得 很有效果。

        LRN的主要思想是在神经元输出的局部范围内进行归一化操作,使得激活值 较大的神经元对后续神经元的影响降低,从而减少梯度消失和梯度爆炸的问 题。具体来说,对于每个神经元,LRN会将其输出按照局部范围进行加权平 均,然后将加权平均值除以一个尺度因子(通常为2),最后将结果取平方 根并减去均值,得到归一化后的输出。

3.4、重叠池化

        CNN中的池化层用于汇总同一核映射中相邻神经元组的输出。 传统上,相邻池化单元汇总的邻域不重叠。 在这项工作中,作者使用了重叠池化,其中s < z,并且发现这可以稍微提高模型的性能并减少过拟合。

3.5、防止过拟合

        AlexNet设置的dropout参数为0.5,AlexNet使用的是 Scale at Training 的 Dropout 实现方式。在训练时,AlexNet通过在前向传播的过程中随机将一 部分神经元的输出置为零,实现了Dropout。在测试时,AlexNet不再使用 Dropout,而是在训练时的基础上将权重按照训练时的概率进行缩放,以保持一致性。

        Dropout为什么能够解决过拟合:

        (1)减少过拟合: 在标准的神经网络中,网络可能会过度依赖于一些特定 的神经元,导致对训练数据的过拟合。Dropout通过随机丢弃神经元,迫使 网络学习对于任何单个神经元的变化都要更加鲁棒的特征表示,从而减少了 对训练数据的过度拟合。

        (2)取平均的作用: 在训练过程中,通过丢弃随机的神经元,每次前向传 播都相当于在训练不同的子网络。在测试阶段,不再进行Dropout,但是通 过保留所有的权重,网络结构变得更加完整。因此,可以看作是在多个不同 的子网络中进行了训练,最终的预测结果相当于对这些子网络的输出取平 均。这种“综合取平均”的策略有助于减轻过拟合,因为一些互为反向的拟合 会相互抵消。

3.6、模型架构细节

3.6.1、输入层(Input Layer)

  • 输入尺寸:224×224×3(RGB图像,经中心裁剪和归一化处理)

  • 处理步骤:原始图像缩放到224×224

3.6.2、第1层卷积

  • 类型:卷积层  

  • 卷积核:96个,尺寸11×11×3  

  • 步长(Stride):4  

  • 填充(Padding):0(实际计算时可能隐式填充2,以保持输出尺寸为整数)

  • 输出尺寸

    • ((224-11)+2*P)/4+1=55

    • 输出特征图:55*55*96

  • 激活函数:ReLU  

  • 附加操作:局部响应归一化(LRN) → 最大池化(Max-Pooling)

    • LRN参数:k=2, n=5, α=10^(-4), β=0.75  

    • 池化核:3×3  

    • 池化步长:2(重叠池化)  

    • 池化后尺寸:27×27×96

3.6.3、第2层卷积

  • 类型:卷积层  

  • 卷积核:256个,尺寸5×5×96

  • 步长(Stride):1  

  • 填充(Padding):2(保持输出尺寸不变)  

  • 输出尺寸:27x27×256 

  • 激活函数:ReLU  

  • 附加操作:局部响应归一化(LRN) → 最大池化

    • LRN参数:k=2, n=5, α=10^(-4), β=0.75  

    • 池化核:3×3  

    • 池化步长:2(重叠池化)  

    • 池化后尺寸:13x13×256 

3.6.4、第3层卷积

  • 类型:卷积层  

  • 卷积核:384个,尺寸3×3×256  

  • 步长(Stride):1  

  • 填充(Padding):1(保持输出尺寸不变)  

  • 输出尺寸:13*13×384

  • 激活函数:ReLU  

  • 附加操作:无池化或归一化

3.6.5、第4层卷积

  • 类型:卷积层  

  • 卷积核:384个,尺寸3×3×192

  • 步长(Stride):1  

  • 填充(Padding):1(保持输出尺寸不变)  

  • 输出尺寸:13x13×384 

  • 激活函数:ReLU  

  • 附加操作:无池化或归一化

3.6.6、第5层卷积

  • 类型:卷积层

  • 卷积核:256个,尺寸3×3×192(每组GPU处理192个输入通道)

  • 步长(Stride):1

  • 填充(Padding):1(保持输出尺寸不变)

  • 输出尺寸:13×13×256

  • 激活函数:ReLU

  • 附加操作:最大池化

    • 池化核:3×3

    • 池化步长:2(重叠池化)

    • 池化后尺寸:6×6×256

3.6.7、全连接层1

  • 类型:全连接层

  • 输入尺寸:6×6×256 → 展平为9216维向量(6×6×256=9216)

  • 神经元数量:4096

  • 激活函数:ReLU

  • 附加操作:Dropout(概率0.5)

3.6.8、全连接层2

  • 类型:全连接层

  • 输入尺寸:4096

  • 神经元数量:4096

  • 激活函数:ReLU

  • 附加操作:Dropout(概率0.5)

3.6.9、输出层

  • 类型:全连接层 + Softmax

  • 输入尺寸:4096

  • 神经元数量:1000(对应ImageNet的1000个类别)

  • 输出:1000维概率分布(通过Softmax归一化)

层名称操作类型核大小/参数步长填充输入尺寸输出尺寸附加操作
Input图像预处理---224×224×3224×224×3中心裁剪、归一化
Conv1卷积11×11×3, 96个42224×224×355×55×96ReLU → LRN → 池化
Pool1最大池化3×32055×55×9627×27×96-
Conv2卷积5×5×48, 256个1227×27×9627×27×256ReLU → LRN → 池化
Pool2最大池化3×32027×27×25613×13×256-
Conv3卷积3×3×256, 384个1113×13×25613×13×384ReLU
Conv4卷积3×3×192, 384个1113×13×38413×13×384ReLU
Conv5卷积3×3×192, 256个1113×13×38413×13×256ReLU → 池化
Pool5最大池化3×32013×13×2566×6×256-
FC6全连接9216 → 4096--6×6×2564096ReLU → Dropout
FC7全连接4096 → 4096--40964096ReLU → Dropout
FC8全连接 + Softmax4096 → 1000--40961000Softmax

六、网络构建 

import torch
import torch.nn as nn
from torchsummary import summary

class AlexNet(nn.Module):
    def __init__(self, num=1000):  # num: 类别数量
        super().__init__()
        self.features = nn.Sequential(
            # 第1个卷积层: 96个卷积核, 11x11大小, 步长4, 填充2
            # 输入: 3x224x224, 输出: 96x54x54 (如果填充=2, 但根据修正后的计算应为 54x54)
            nn.Conv2d(3, 96, 11, 4, 2),
            nn.ReLU(inplace=True),  # ReLU 激活函数, inplace=True 表示原地操作
            nn.MaxPool2d(3, 2),     # 3x3 最大池化, 步长 2. 输出: 96x26x26 (如果输入是 54x54)

            # 第2个卷积层: 256个卷积核, 5x5大小, 步长 1, 填充 2
            # 输入: 96x26x26, 输出: 256x26x26
            nn.Conv2d(96, 256, 5, 1, 2),
            nn.ReLU(inplace=True),  # ReLU 激活函数
            nn.MaxPool2d(3, 2),     # 3x3 最大池化, 步长 2. 输出: 256x12x12

            # 第3个卷积层: 384个卷积核, 3x3大小, 步长 1, 填充 1
            # 输入: 256x12x12, 输出: 384x12x12
            nn.Conv2d(256, 384, 3, 1, 1),
            nn.ReLU(inplace=True),  # ReLU 激活函数

            # 第4个卷积层: 384个卷积核, 3x3大小, 步长 1, 填充 1
            # 输入: 384x12x12, 输出: 384x12x12
            nn.Conv2d(384, 384, 3, 1, 1),
            nn.ReLU(inplace=True),  # ReLU 激活函数

            # 第5个卷积层: 256个卷积核, 3x3大小, 步长 1, 填充 1
            # 输入: 384x12x12, 输出: 256x12x12
            nn.Conv2d(384, 256, 3, 1, 1),
            nn.ReLU(inplace=True),  # ReLU 激活函数
            nn.MaxPool2d(3, 2)      # 3x3 最大池化, 步长 2. 输出: 256x5x5
        )
        self.classfiter = nn.Sequential(  # 注意: 应该是 "classifier", 这里保持原代码一致
            nn.Dropout(p=0.5),       # Dropout, 丢弃概率 0.5
            nn.Linear(256 * 5 * 5, 4096),  # 全连接层, 输入: 256x5x5 展平, 输出: 4096 (修正后的输入大小)
            nn.ReLU(inplace=True),  # ReLU 激活函数

            nn.Dropout(p=0.5),       # Dropout, 丢弃概率 0.5
            nn.Linear(4096, 4096),  # 全连接层, 输出: 4096
            nn.ReLU(inplace=True),  # ReLU 激活函数

            nn.Linear(4096, num),   # 全连接层 (输出层), 输出: 类别数量
        )

    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, 1)  # 展平特征图, 从维度1开始展平
        x = self.classfiter(x)
        return x

if __name__ == '__main__':
    model = AlexNet()
    print(summary(model, (3, 224, 224)))  # 打印模型结构和参数信息
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1           [-1, 96, 55, 55]          34,944
              ReLU-2           [-1, 96, 55, 55]               0
         MaxPool2d-3           [-1, 96, 27, 27]               0
            Conv2d-4          [-1, 256, 27, 27]         614,656
              ReLU-5          [-1, 256, 27, 27]               0
         MaxPool2d-6          [-1, 256, 13, 13]               0
            Conv2d-7          [-1, 384, 13, 13]         885,120
              ReLU-8          [-1, 384, 13, 13]               0
            Conv2d-9          [-1, 384, 13, 13]       1,327,488
             ReLU-10          [-1, 384, 13, 13]               0
           Conv2d-11          [-1, 256, 13, 13]         884,992
             ReLU-12          [-1, 256, 13, 13]               0
        MaxPool2d-13            [-1, 256, 6, 6]               0
          Dropout-14                 [-1, 9216]               0
           Linear-15                 [-1, 4096]      37,752,832
             ReLU-16                 [-1, 4096]               0
          Dropout-17                 [-1, 4096]               0
           Linear-18                 [-1, 4096]      16,781,312
             ReLU-19                 [-1, 4096]               0
           Linear-20                 [-1, 1000]       4,097,000
================================================================
Total params: 62,378,344
Trainable params: 62,378,344
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.57
Forward/backward pass size (MB): 11.09
Params size (MB): 237.95
Estimated Total Size (MB): 249.62
----------------------------------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值