文章目录
0. 前言
AlexNet是深度学习领军任务Geoffrey Hinton教授的学生Alex Krizhevsky提出来的。AlexNet在ILSVRC 2012竞赛中以压倒性的成绩获得了冠军。AlexNet是一个具有突破性意义的模型,在他之前,神经网络和深度学习都陷入了长时间的瓶颈期。AlexNet一经问世就统治了整个图像识别领域。直至今日,AlexNet也依然是效果出色且具有启发意义的网络结构。
论文原文:ImageNet Classification with Deep Convolutional Neural Networks
1. AlexNet结构

AlexNet是一个8层的网络结构,前五层为卷积层,后3层为全连接层。且使用了2张GPU(GTX 580, 3GB)。只有第3个卷积层和全连接层需要接收来自两张GPU的前一层的所有输出。其余各层都是只接收来自于同一个GPU的上一层的输出。
卷积层1:卷积核: 11 ∗ 11 ∗ 3 11*11*3 11∗11∗3,卷积核数量:96
卷积层2:卷积核: 5 ∗ 5 ∗ 96 5*5*96 5∗5∗96,卷积核数量:256
卷积层3:卷积核: 3 ∗ 3 ∗ 256 3*3*256 3∗3∗256,卷积核数量:384
卷积层4:卷积核: 3 ∗ 3 ∗ 384 3*3*384 3∗3∗384,卷积核数量:384
卷积层5:卷积核: 3 ∗ 3 ∗ 384 3*3*384 3∗3∗384,卷积核数量:256
全连接层1:4096
全连接层2:4096
全连接层3:1000
[1]所有层的激励函数全部为:Relu(Rectified Linear Units);
[2]第1、2、5卷积层有最大池化Max Pooling,第3、4卷积层没有;
[3]第1、2卷积层需要LRN处理;
[4]第3卷积层和所有的全连接层都是接受上一层两个GPU的特征图,而其余各层都是接收来自于同一个GPU上一层的特征图。
用TensorBoard可以很方便的查看AlexNet的网络结构:

2. 关于Relu激励函数
Relu全称为Rectified Linear Units,修正线性单元,其表达式为:
R
e
l
u
=
m
a
x
(
0
,
x
)
Relu = max(0, x)
Relu=max(0,x)
与传统的饱和非线性激活函数如Sigmoid和tanh(x)相比,Relu在卷积神经网络中能获得更快的速度,几乎是饱和非线性激活函数的6倍。主要结局了在网络较深的时候,饱和非线性激活函数的梯度弥散问题。
3. 关于避免过拟合的手段
3.1 重叠池化(Overlapping Pooling)
在池化时,通常都是不重叠的。而在AlxeNet中,提出了一种重叠池化的方式,让池化的步长小于池化核的大小,那么在池化的过程中就会有重叠。实验验证了这种有重叠的池化方式能避免过拟合。
3.2 数据增加(Data Augmentation)
数据增加的方式主要有图像平移和水平翻转。所谓图像平移就是从大小为 256 ∗ 256 256*256 256∗256的图片中随机提取 224 ∗ 224 224*224 224∗224的图片及其水平翻转,这样可以使得数据集扩大2048倍。
在测试阶段,网络预测的结果是这张图片四个角和中心提取出来的5张图片及其水平翻转共计10张图片预测结果的平均。
此外,还有增加训练集中各图片在RGB通道上的强度。对于每一个RGB图片上的像素点
I
x
y
=
[
I
x
y
R
,
I
x
y
G
,
I
x
y
B
]
T
I_{xy}=[I_{xy}^R, I_{xy}^G, I_{xy}^B]^T
Ixy=[IxyR,IxyG,IxyB]T需要加上如下的量:
I
x
y
:
=
I
x
y
+
[
p
1
,
p
2
,
p
3
]
[
α
1
λ
1
+
α
2
λ
2
+
α
3
λ
3
]
T
I_{xy} := I_{xy}+[p_1, p_2, p_3][\alpha_1 \lambda_1+\alpha_2 \lambda_2+\alpha_3 \lambda_3]^T
Ixy:=Ixy+[p1,p2,p3][α1λ1+α2λ2+α3λ3]T
其中
p
i
p_i
pi和
λ
i
\lambda_i
λi是第i个RGB像素协方差矩阵
[
I
x
y
R
,
I
x
y
G
,
I
x
y
B
]
T
[
I
x
y
R
,
I
x
y
G
,
I
x
y
B
]
[I_{xy}^R, I_{xy}^G, I_{xy}^B]^T[I_{xy}^R, I_{xy}^G, I_{xy}^B]
[IxyR,IxyG,IxyB]T[IxyR,IxyG,IxyB]大小为
3
∗
3
3*3
3∗3的特征向量和特征值。
α
i
\alpha_i
αi是一个随机值,满足均值为0方差为0.1的高斯分布。
3.3 Dropout
使每个隐藏层中的神经元以0.5的概率等于0,当该神经元输出为0时,在前向传播中该神经元不产生作用。在每次迭代时,所得到的网络结构都不一样。在测试的时候,需要给每个隐藏层的神经元的输出乘以0.5,去近似dropout网络预测分布的几何平均。
Dropout在AlexNet中只出现在全连接层的1,2层
4. AlexNet实现
实现AlexNet可以使用tflearn库:
import tflearn
from tflearn.layers.core import input_data, dropout, fully_connected
from tflearn.layers.conv import conv_2d, max_pool_2d
from tflearn.layers.estimator import regression
import tflearn.datasets.oxflower17 as oxflower17
import numpy as np
def loadData():
'''
获取数据集
'''
X, Y = oxflower17.load_data(dirname='17flowers/', one_hot=True, resize_pics=(227, 227))
return X, Y
def convLayer(network, para):
'''
定义卷积层
@param network:网络
@param para: 该层的参数
'''
for i in range(1, 6):
network = conv_2d(network, para[i]['kernel_para'][1], para[i]['kernel_para'][0], strides=para[i]['kernel_para'][2], activation=para[i]['activa'])
if para[i]['isPool']:
network = max_pool_2d(network, para[i]['pool_para'][0], strides=para[i]['pool_para'][1])
return network
def fcLayer(network, para):
'''
定义全连接层
@param network : 网络
@param para: 全连接层参数
'''
for i in range(1, 4):
network = fully_connected(network, para[i]['nNode'], activation=para[i]['activa'])
if para[i]['isDropout']:
network = dropout(network, para[i]['keep_prob'])
return network
使用上述的几个简单函数,构建AlexNet:
def AlexNet():
# 定义输入
network = input_data(shape=[None, 227, 227, 3])
# 定义卷积层
conv_para = {1: {'kernel_para': [11, 96, 4], 'activa': 'relu', 'isPool': True, 'pool_para': [3, 2]}, # 第一层:卷积核11*11,输出96个特征图,strides为4; 池化3*3,步长为2
2: {'kernel_para': [5, 256, 1], 'activa': 'relu', 'isPool': True, 'pool_para': [3, 2]}, # 第二层:卷积核5*5,输出256个特征图,strides为1; 池化3*3,步长为2
3: {'kernel_para': [3, 384, 1], 'activa': 'relu', 'isPool': False}, # 第三层:卷积核3*3,输出384个特征图,strides为1,不池化
4: {'kernel_para': [3, 384, 1], 'activa': 'relu', 'isPool': False}, # 第四层:卷积核3*3,输出384个特征图,strides为1,不池化
5: {'kernel_para': [3, 256, 1], 'activa': 'relu', 'isPool': True, 'pool_para': [3, 2]} # 第五层:卷积核3*3,输出256个特征图,strides为1; 池化3*3,步长为2
}
network = convLayer(network, conv_para)
# 定义全连接层
fc_para = {1: {'nNode': 4096, 'activa': 'tanh', 'isDropout': True, 'keep_prob': 0.5}, # 第一层: 4096个节点,激励函数为tanh, dropout:0.5
2: {'nNode': 4096, 'activa': 'tanh', 'isDropout': True, 'keep_prob': 0.5}, # 第二层: 4096个节点,激励函数为tanh, dropout:0.5
3: {'nNode': 17, 'activa': 'softmax', 'isDropout': False} # 第一层: 4096个节点,激励函数为tanh, dropout:0.5
}
network = fcLayer(network, fc_para)
return network
开始训练AlexNet模型:
if __name__ == '__main__':
X, Y = loadData()
network = AlexNet()
# 定义优化算法和损失函数
network = regression(network, optimizer='momentum', loss='categorical_crossentropy', learning_rate=0.001)
# Training
model = tflearn.DNN(network, checkpoint_path='model_alexnet', max_checkpoints=1, tensorboard_verbose=2, tensorboard_dir='logs/')
model.fit(X, Y, n_epoch=1, validation_set=0.1, shuffle=True, show_metric=True, batch_size=64, snapshot_step=200, snapshot_epoch=False, run_id='alexnet_oxflowers17')
---------------------------------
Run id: alexnet_oxflowers17
Log directory: logs/
---------------------------------
Training samples: 1224
Validation samples: 136
–
Training Step: 1 | time: 14.174s
| Momentum | epoch: 001 | loss: 0.00000 - acc: 0.0000 – iter: 0064/1224
Training Step: 2 | total loss: 2.67125 | time: 26.990s
| Momentum | epoch: 001 | loss: 2.67125 - acc: 0.0281 – iter: 0128/1224
Training Step: 3 | total loss: 2.99733 | time: 39.316s
| Momentum | epoch: 001 | loss: 2.99733 - acc: 0.0562 – iter: 0192/1224
Training Step: 4 | total loss: 2.93764 | time: 52.385s
| Momentum | epoch: 001 | loss: 2.93764 - acc: 0.0492 – iter: 0256/1224
Training Step: 5 | total loss: 3.02957 | time: 66.853s
| Momentum | epoch: 001 | loss: 3.02957 - acc: 0.0692 – iter: 0320/1224