==代码地址==
https://github.com/xmy0916/DLNetwork

简介

AlexNet首次在大规模图像数据集实现了深层卷积神经网络结构,点燃了深度学习这把火。其在ImageNet LSVRC-2012目标识别的top-5 error为15.3%,同期第二名仅为26.2%,碾压其他传统的hand-craft 特征方法,使得计算机视觉从业者从繁重的特征工程中解脱出来,转向思考能够从数据中自动提取需要的特征,做到数据驱动。得益于GPU计算性能的提升以及大规模数据集的出现,自此后每年的ImageNet LSVRC挑战赛都被深度学习模型霸占着榜首。

重点

参考:https://blog.csdn.net/qq_31278903/article/details/90671908

  • Relu做激活函数,代替Sigmoid来加快SGD的收敛速度
  • dropout避免过拟合
  • 使用了重叠的最大池化(Max Pooling)
  • 提出LRN(局部响应归一化)
  • 使用GPU加速训练
  • 使用了数据增强策略(Data Augmentation)

RELU

在这里插入图片描述

  • 计算开销小。sigmoidsigmoid的正向传播有指数运算,倒数运算,而ReLu是线性输出;反向传播中,sigmoidsigmoid有指数运算,而ReLU有输出的部分,导数始终为1.
  • 梯度饱和问题
  • 稀疏性。Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生

数据增强

神经网络由于训练的参数多,表能能力强,所以需要比较多的数据量,不然很容易过拟合。当训练数据有限时,可以通过一些变换从已有的训练数据集中生成一些新的数据,以快速地扩充训练数据。对于图像数据集来说,可以对图像进行一些形变操作:

  • 翻转
  • 随机裁剪
  • 平移,颜色光照的变换

AlexNet中对数据做了以下操作:

随机裁剪,对256×256256×256的图片进行随机裁剪227×227227×227,然后进行水平翻转。测试的时候,对左上、右上、左下、右下、中间分别做了5次裁剪,然后翻转,共10个裁剪,之后对结果求平均。
对RGB空间做PCA(主成分分析),然后对主成分做一个(0, 0.1)的高斯扰动,也就是对颜色、光照做变换,错误率下降1%

层叠池化

在AlexNet中使用的池化(Pooling)却是可重叠的,也就是说,在池化的时候,每次移动的步长小于池化的窗口长度。AlexNet池化的大小为3×3的正方形,每次池化移动步长为2,这样就会出现重叠。重叠池化可以避免过拟合,这个策略贡献了0.3%的Top-5错误率。与非重叠方案s=2,z=2s=2,z=2相比,输出的维度是相等的,并且能在一定程度上抑制过拟合。

LRN

好像都没人用了…

Dropout避免模型过拟合

这个是比较常用的抑制过拟合的方法了。
引入Dropout主要是为了防止过拟合。在神经网络中Dropout通过修改神经网络本身结构来实现,对于某一层的神经元,通过定义的概率将神经元置为0,这个神经元就不参与前向和后向传播,就如同在网络中被删除了一样,同时保持输入层与输出层神经元的个数不变,然后按照神经网络的学习方法进行参数更新。在下一次迭代中,又重新随机删除一些神经元(置为0),直至训练结束。
Dropout应该算是AlexNet中一个很大的创新,现在神经网络中的必备结构之一。Dropout也可以看成是一种模型组合,每次生成的网络结构都不一样,通过组合多个模型的方式能够有效地减少过拟合,Dropout只需要两倍的训练时间即可实现模型组合(类似取平均)的效果,非常高效。
在这里插入图片描述

结构

在线看网络结构
在这里插入图片描述

代码

参考pytorch官方实现的AlexNet代码,修改到我的工程,官方代码链接:
https://github.com/pytorch/vision/tree/master/torchvision/models

这里和LeNet的一样在cifar10上进行测试,首先采用两种策略进行测试:

  • Training from scratch
  • finetune on official pretrained model

策略一比较简单,基本不用修改代码结构,不多赘述,策略二进行了简单的修改:

def AlexNet_pretrain(saveFeature = False,cfg = None):
    model = AlexNet(saveFeature = saveFeature, cfg = cfg)
    num_class = cfg["num_class"]
    state_dict = load_state_dict_from_url(model_urls['alexnet'])
    if num_class != 1000:
        weight = torch.Tensor(random.rand(num_class, 4096))
        bias = torch.Tensor(random.rand(num_class))
        state_dict["classifier.6.weight"] = weight
        state_dict["classifier.6.bias"] = bias
    model.load_state_dict(state_dict)
    return model

这段代码给AlexNet类套了个函数在外头,官方pretrain的模型分类是1000但是我们只需要10分类,因此在判断分类类别时如果不等于1000需要对torch.load加载的字典的值进行处理,就是把最后的全连接层的参数给删了赋值我们自己随机初始化的tensor即可,代码对应:

if num_class != 1000:
        weight = torch.Tensor(random.rand(num_class, 4096))
        bias = torch.Tensor(random.rand(num_class))
        state_dict["classifier.6.weight"] = weight
        state_dict["classifier.6.bias"] = bias

最后在两种策略上进行5epoch的训练测试:

模型 AlexNet
轮数 5
精度 0.800、0.860(加pretrain)
日志 alexnet.logalexnet_pretrain.log

完整代码地址:https://github.com/xmy0916/DLNetwork

配置不加pretrain:
config/config.py:
在这里插入图片描述
运行命令:

python3 train.py --model alexnet