代码地址
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"] = weightstate_dict["classifier.6.bias"] = biasmodel.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"] = weightstate_dict["classifier.6.bias"] = bias
最后在两种策略上进行5epoch的训练测试:
模型 | AlexNet |
---|---|
轮数 | 5 |
精度 | 0.800、0.860(加pretrain) |
日志 | alexnet.log、alexnet_pretrain.log |
完整代码地址:https://github.com/xmy0916/DLNetwork
配置不加pretrain:
config/config.py:
运行命令:
python3 train.py --model alexnet