摘要
AlexNet是2012年ImageNet竞赛冠军获得者Hinton和他的学生Alex Krizhevsky设计的。也是在那年之后,更多更深的神经网络被提出,网络开始往深水区涉入,比如优秀的vgg,GoogLeNet等。 AlexNet是在LeNet的基础上加深了网络的结构,学习更丰富更高维的图像特征。本文将详细概述AlexNet的特点及核心思想,最后给出相关的代码实现。
AlexNet模型的核心思想
问题
LeNet是卷积神经网络的祖师爷LeCun在1998年提出,用于解决手写数字识别的视觉任务。自那时起,CNN的最基本的架构就定下来了:卷积层、池化层、全连接层。如今各大深度学习框架中所使用的LeNet都是简化改进过的LeNet-5(-5表示具有5个层),和原始的LeNet有些许不同,比如把激活函数改为了现在很常用的ReLu。
LeNet-5模型的套路可以总结为:conv1->pool->conv2->pool2再接全连接层,永恒不变的爱是:卷积层后紧接池化层的模式(卷积必池化)。其经典的模型结构如图所示:
那么就存在一个问题,如何让网络变的更深,且提取的特征丰富呢?
解决方案
1.钱;2.技术,Hinton的学生Alex做的了,小小年纪承受了比思聪都要早的考验(钱和技术给了他巨大的人生考验)。2012年Alex提出的Alexnet网络模型结构引爆了神经网络的应用热潮,并赢得了2012届图像识别大赛的冠军,使得CNN成为在图像分类上的核心算法模型。该模型相比于LeNet模型,Alex将钱花到了极致,多GPU并行训练深度Alexnet将深度学习模型得出预测结果的时间提高到人们可以接受的时间范围之内。因此Alexnet模型的特点如下:
- 更深的网络结构
- 打破卷积必池化的思维定式,使用层叠的卷积层,即卷积层+卷积层+池化层来提取图像的特征
- 多GPU训练
- 使用Dropout、Data Augmentation抑制过拟合
- 使用Relu替换之前的sigmoid的作为激活函数
- 引入LRN
模型结构:
网络特点
- RELU的使用
我们知道神经网络需要使用激活函数,一般激活函数具有两个作用。其一、无论卷积还是全连接层,实质上都是线性运算,通过加入非线性的激活函数可以增强网络的非线性映射能力,相当于kernel method。其二、神经网络一般通过BP算法优化,激活函数可以加快网络收敛速度。传统神经网络激活函数通常为反正切或是sigmoid,AlexNet使用RELU作为激活函数,相比于反正切,该方法训练速度大约有6倍提升。RELU激活函数简单到难以置信。
- LRN
虽然后来的很多网络都不屑于使用LRN,甚至直接说LRN对于网络没有任何提升,但是思路真的很新奇呀。
LRN加在RELU的激活后面,能够增加网络的泛化能力,并在ILSVRC-2012上降低1%的错误率。传说思路来源于神经元的侧向抑制机制,不同的神经元都在做特征提取这件事,能否让他们相互竞争呢?
- Overlapping Pooling
也算是创新点之一吧,毕竟此前的文章的池化没有重叠的,不过后续的其他文章也鲜有重叠。重叠池化的意思是,池化步伐小于kernel size,这样池化后的feature map的感受野其实是有部分重叠的。
- Data Augmentation
文章使用Random Crop、flip从而上千倍的扩充训练样本的数量,也使得随机裁剪成为通用方法。具体做法就是首先将图片resize到256*256大小,然后从中随机crop出224*224大小的patch训练,测试时就从四个角及中心crop,然后水平翻转图像形成10个测试图片,然后对于这10个结果取一下平均值就好啦。另一种增强为转换RGB通道的强度,在之后的模型中很少用到,对于该模型,大约降低了1%错误率。
- DropOut
DropOut通过训练时随机使得一部分结点失效,不贡献连接权重而减少过拟合风险。同时强迫这些神经元去学习互补的一些特征。
AlexNet模型的代码实现
实现环境:
python3.6.5、tensorflow 1.1.8、keras 2.2.0等。
核心代码
本文将给出keras神经网络编程框架实现的一个简单Alexnet模型。(相比论文原始模型,这是一个非常小的网络,只有5个卷积层并且池化层大小不同。)
#alexnet
model3 = Sequential()
model3.add(Conv2D(input_shape=(n,n,3),filters=96,kernel_size=(11,11),strides=(4,4),padding="valid", activation="relu"))
model3.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model3.add(Conv2D(256, kernel_size=(5,5), padding="same",strides=(1,1), activation="relu"))
model3.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model3.add(Conv2D(384, kernel_size=(3,3), padding="same", strides=(1,1), activation="relu"))
model3.add(Conv2D(384, kernel_size=(3,3), padding="same", strides=(1,1), activation="relu"))
model3.add(Conv2D(256, kernel_size=(3,3), padding="same", strides=(1,1), activation="relu"))
model3.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)))
model3.add(Flatten())
model3.add(Dense(4096,activation="relu"))
model3.add(Dense(4096,activation="relu"))
model3.add(Dense(units=len(classes), activation="softmax"))
model3.summary()
plot_model(model3, show_shapes=True, to_file='ALEX_NET.png')
模型参数:
Layer (type) Output Shape Param #
=================================================================
conv2d_42 (Conv2D) (None, 30, 30, 96) 34944
_________________________________________________________________
max_pooling2d_15 (MaxPooling (None, 14, 14, 96) 0
_________________________________________________________________
conv2d_43 (Conv2D) (None, 14, 14, 256) 614656
_________________________________________________________________
max_pooling2d_16 (MaxPooling (None, 6, 6, 256) 0
_________________________________________________________________
conv2d_44 (Conv2D) (None, 6, 6, 384) 885120
_________________________________________________________________
conv2d_45 (Conv2D) (None, 6, 6, 384) 1327488
_________________________________________________________________
conv2d_46 (Conv2D) (None, 6, 6, 256) 884992
_________________________________________________________________
max_pooling2d_17 (MaxPooling (None, 2, 2, 256) 0
_________________________________________________________________
flatten_3 (Flatten) (None, 1024) 0
_________________________________________________________________
dense_8 (Dense) (None, 4096) 4198400
_________________________________________________________________
dense_9 (Dense) (None, 4096) 16781312
_________________________________________________________________
dense_10 (Dense) (None, 8) 32776
=================================================================
Total params: 24,759,688
Trainable params: 24,759,688
Non-trainable params: 0
_________________________________________________________________
模型结构:
总结
对于没有GPU的我们普通人,其越深的Alexnet模型结构,其训练速度越慢,且准确率并不是太高。如果模型过分的深的化,例如VGG模型(基于ALexnet加深了网络深度,证明了更深的网络,能更好的提取特征),则会出现梯度消失等问题。那么如何解决该问题呢,例如使用BatchNorm,将激活函数换为ReLu,使用Xaiver初始化等。以及最后的残差神经网络模型。
参考文献
1.Krizhevsky A, Sutskever I, Hinton G E. ImageNet classification with deep convolutional neural networks[C]// International Conference on Neural Information Processing Systems. Curran Associates Inc. 2012:1097-1105.
2. https://haosen.blog.csdn.net/article/details/111396283
3.https://haosen.blog.csdn.net/article/details/110726937
4. https://haosen.blog.csdn.net/article/details/105822437
5. Tm P , Pranathi A , Saiashritha K , et al. Tomato Leaf Disease Detection Using Convolutional Neural Networks[C]// 2018 Eleventh International Conference on Contemporary Computing (IC3). IEEE Computer Society, 2018