Alex在2012年提出的alexnet网络结构模型引爆了神经网络的应用热潮,并赢得了2012届图像识别大赛的冠军,使得CNN成为在图像分类上的核心算法模型。
接下来本文对该网络配置结构中各个层进行详细的解读(训练阶段):
注:下述关于卷积核的尺寸来自于Alex在2012年发表的经典论文。
1. conv1阶段DFD(data flow diagram):
第一层输入数据为原始的227*227*3的图像,这个图像被11*11*3的卷积核进行卷积运算,卷积核对原始图像的每次卷积都生成一个新的像素。卷积核沿原始图像的x轴方向和y轴方向两个方向移动,移动的步长是4个像素。因此,卷积核在移动的过程中会生成(227-11)/4+1=55个像素(227个像素减去11,正好是54,即生成54个像素,再加上被减去的11也对应生成一个像素),行和列的55*55个像素形成对原始图像卷积之后的像素层。共有96个卷积核,会生成55*55*96个卷积后的像素层。96个卷积核分成2组,每组48个卷积核。对应生成2组55*55*48的卷积后的像素层数据。这些像素层经过relu1单元的处理,生成激活像素层,尺寸仍为2组55*55*48的像素层数据。
这些像素层经过pool运算(池化运算)的处理,池化运算的尺度为3*3,运算的步长为2,则池化后图像的尺寸为(55-3)/2+1=27。 即池化后像素的规模为27*27*96;然后经过归一化处理,归一化运算的尺度为5*5;第一卷积层运算结束后形成的像素层的规模为27*27*96。分别对应96个卷积核所运算形成。这96层像素层分为2组,每组48个像素层,每组在一个独立的GPU上进行运算。
反向传播时,每个卷积核对应一个偏差值。即第一层的96个卷积核对应上层输入的96个偏差值。
2. conv2阶段DFD(data flow diagram):
第二层输入数据为第一层输出的27*27*96的像素层,为便于后续处理,每幅像素层的左右两边和上下两边都要填充2个像素;27*27*96的像素数据分成27*27*48的两组像素数据,两组数据分别再两个不同的GPU中进行运算。每组像素数据被5*5*48的卷积核进行卷积运算,卷积核对每组数据的每次卷积都生成一个新的像素。卷积核沿原始图像的x轴方向和y轴方向两个方向移动,移动的步长是1个像素。因此,卷积核在移动的过程中会生成(27-5+2*2)/1+1=27个像素。(27个像素减去5,正好是22,在加上上下、左右各填充的2个像素,即生成26个像素,再加上被减去的5也对应生成一个像素),行和列的27*27个像素形成对原始图像卷积之后的像素层。共有256个5*5*48卷积核;这256个卷积核分成两组,每组针对一个GPU中的27*27*48的像素进行卷积运算。会生成两组27*27*128个卷积后的像素层。这些像素层经过relu2单元的处理,生成激活像素层,尺寸仍为两组27*27*128的像素层。
这些像素层经过pool运算(池化运算)的处理,池化运算的尺度为3*3,运算的步长为2,则池化后图像的尺寸为(57-3)/2+1=13。 即池化后像素的规模为2组13*13*128的像素层;然后经过归一化处理,归一化运算的尺度为5*5;第二卷积层运算结束后形成的像素层的规模为2组13*13*128的像素层。分别对应2组128个卷积核所运算形成。每组在一个GPU上进行运算。即共256个卷积核,共2个GPU进行运算。
反向传播时,每个卷积核对应一个偏差值。即第一层的96个卷积核对应上层输入的256个偏差值。
3. conv3阶段DFD(data flow diagram):
第三层输入数据为第二层输出的2组13*13*128的像素层;为便于后续处理,每幅像素层的左右两边和上下两边都要填充1个像素;2组像素层数据都被送至2个不同的GPU中进行运算。每个GPU中都有192个卷积核,每个卷积核的尺寸是3*3*256。因此,每个GPU中的卷积核都能对2组13*13*128的像素层的所有数据进行卷积运算。卷积核对每组数据的每次卷积都生成一个新的像素。卷积核沿像素层数据的x轴方向和y轴方向两个方向移动,移动的步长是1个像素。因此,运算后的卷积核的尺寸为(13-3+1*2)/1+1=13(13个像素减去3,正好是10,在加上上下、左右各填充的1个像素,即生成12个像素,再加上被减去的3也对应生成一个像素),每个GPU中共13*13*192个卷积核。2个GPU中共13*13*384个卷积后的像素层。这些像素层经过relu3单元的处理,生成激活像素层,尺寸仍为2组13*13*192像素层,共13*13*384个像素层。
4. conv4阶段DFD(data flow diagram):
第四层输入数据为第三层输出的2组13*13*192的像素层;为便于后续处理,每幅像素层的左右两边和上下两边都要填充1个像素;2组像素层数据都被送至2个不同的GPU中进行运算。每个GPU中都有192个卷积核,每个卷积核的尺寸是3*3*192。因此,每个GPU中的卷积核能对1组13*13*192的像素层的数据进行卷积运算。卷积核对每组数据的每次卷积都生成一个新的像素。卷积核沿像素层数据的x轴方向和y轴方向两个方向移动,移动的步长是1个像素。因此,运算后的卷积核的尺寸为(13-3+1*2)/1+1=13(13个像素减去3,正好是10,在加上上下、左右各填充的1个像素,即生成12个像素,再加上被减去的3也对应生成一个像素),每个GPU中共13*13*192个卷积核。2个GPU中共13*13*384个卷积后的像素层。这些像素层经过relu4单元的处理,生成激活像素层,尺寸仍为2组13*13*192像素层,共13*13*384个像素层。
5. conv5阶段DFD(data flow diagram):
第五层输入数据为第四层输出的2组13*13*192的像素层;为便于后续处理,每幅像素层的左右两边和上下两边都要填充1个像素;2组像素层数据都被送至2个不同的GPU中进行运算。每个GPU中都有128个卷积核,每个卷积核的尺寸是3*3*192。因此,每个GPU中的卷积核能对1组13*13*192的像素层的数据进行卷积运算。卷积核对每组数据的每次卷积都生成一个新的像素。卷积核沿像素层数据的x轴方向和y轴方向两个方向移动,移动的步长是1个像素。因此,运算后的卷积核的尺寸为(13-3+1*2)/1+1=13(13个像素减去3,正好是10,在加上上下、左右各填充的1个像素,即生成12个像素,再加上被减去的3也对应生成一个像素),每个GPU中共13*13*128个卷积核。2个GPU中共13*13*256个卷积后的像素层。这些像素层经过relu5单元的处理,生成激活像素层,尺寸仍为2组13*13*128像素层,共13*13*256个像素层。
2组13*13*128像素层分别在2个不同GPU中进行池化(pool)运算处理。池化运算的尺度为3*3,运算的步长为2,则池化后图像的尺寸为(13-3)/2+1=6。 即池化后像素的规模为两组6*6*128的像素层数据,共6*6*256规模的像素层数据。
6. fc6阶段DFD(data flow diagram):
第六层输入数据的尺寸是6*6*256,采用6*6*256尺寸的滤波器对第六层的输入数据进行卷积运算;每个6*6*256尺寸的滤波器对第六层的输入数据进行卷积运算生成一个运算结果,通过一个神经元输出这个运算结果;共有4096个6*6*256尺寸的滤波器对输入数据进行卷积运算,通过4096个神经元输出运算结果;这4096个运算结果通过relu激活函数生成4096个值;并通过drop运算后输出4096个本层的输出结果值。
由于第六层的运算过程中,采用的滤波器的尺寸(6*6*256)与待处理的feature map的尺寸(6*6*256)相同,即滤波器中的每个系数只与feature map中的一个像素值相乘;而其它卷积层中,每个滤波器的系数都会与多个feature map中像素值相乘;因此,将第六层称为全连接层。
第五层输出的6*6*256规模的像素层数据与第六层的4096个神经元进行全连接,然后经由relu6进行处理后生成4096个数据,再经过dropout6处理后输出4096个数据。
7. fc7阶段DFD(data flow diagram):
第六层输出的4096个数据与第七层的4096个神经元进行全连接,然后经由relu7进行处理后生成4096个数据,再经过dropout7处理后输出4096个数据。
8. fc8阶段DFD(data flow diagram):
第七层输出的4096个数据与第八层的1000个神经元进行全连接,经过训练后输出被训练的数值。
Alexnet网络中各个层发挥的作用如下表所述:
在学习过程中,我们使用随机梯度下降法和一批大小为128、动力为0.9、权重衰减为0.0005的样例来训练我们的网络。我们发现,这少量的权重衰减对于模型学习是重要的。换句话说,这里的权重衰减不仅仅是一个正则化矩阵:它减少了模型的训练误差。对于权重w的更新规则为:
其中i是迭代指数,v是动力变量,ε是学习率,是目标关于w、对求值的导数在第i批样例上的平均值。我们用一个均值为0、标准差为0.01的高斯分布初始化了每一层的权重。我们用常数1初始化了第二、第四和第五个卷积层以及全连接隐层的神经元偏差。该初始化通过提供带正输入的ReLU来加速学习的初级阶段。我们在其余层用常数0初始化神经元偏差。
对于所有层都使用了相等的学习率,这是在整个训练过程中手动调整的。我们遵循的启发式是,当验证误差率在当前学习率下不再提高时,就将学习率除以10。学习率初始化为0.01,在终止前降低三次。作者训练该网络时大致将这120万张图像的训练集循环了90次,在两个NVIDIA GTX 580 3GB GPU上花了五到六天。
各种layer的operation更多解释可以参考http://caffe.berkeleyvision.org/tutorial/layers.html
从计算该模型的数据流过程中,该模型参数大概5kw+。
在caffe开源的model样例中,它也给出了alexnet的复现,具体网络配置文件如下https://github.com/BVLC/caffe/blob/master/models/bvlc_reference_caffenet/train_val.prototxt:
caffe的输出中也有包含这块的内容日志,详情如下:
1. I0721 10:38:15.326920 4692 net.cpp:125] Top shape: 256 3 227 227 (39574272) :output data of layer 0
2. I0721 10:38:15.326971 4692 net.cpp:125] Top shape: 256 1 1 1 (256)
3. I0721 10:38:15.326982 4692 net.cpp:156] data does not need backward computation.
4. I0721 10:38:15.327003 4692 net.cpp:74] Creating Layer conv1
5. I0721 10:38:15.327011 4692 net.cpp:84] conv1 <- data
6. I0721 10:38:15.327033 4692 net.cpp:110] conv1 -> conv1
7. I0721 10:38:16.721956 4692 net.cpp:125] Top shape: 256 96 55 55 (74342400)
8. I0721 10:38:16.722030 4692 net.cpp:151] conv1 needs backward computation.
9. I0721 10:38:16.722059 4692 net.cpp:74] Creating Layer relu1
10. I0721 10:38:16.722070 4692 net.cpp:84] relu1 <- conv1
11. I0721 10:38:16.722082 4692 net.cpp:98] relu1 -> conv1 (in-place)
12. I0721 10:38:16.722096 4692 net.cpp:125] Top shape: 256 96 55 55 (74342400)
13. I0721 10:38:16.722105 4692 net.cpp:151] relu1 needs backward computation.
14. I0721 10:38:16.722116 4692 net.cpp:74] Creating Layer pool1
15. I0721 10:38:16.722125 4692 net.cpp:84] pool1 <- conv1
16. I0721 10:38:16.722133 4692 net.cpp:110] pool1 -> pool1
17. I0721 10:38:16.722167 4692 net.cpp:125] Top shape: 256 96 27 27 (17915904)
18. I0721 10:38:16.722187 4692 net.cpp:151] pool1 needs backward computation.
19. I0721 10:38:16.722205 4692 net.cpp:74] Creating Layer norm1
20. I0721 10:38:16.722221 4692 net.cpp:84] norm1 <- pool1
21. I0721 10:38:16.722234 4692 net.cpp:110] norm1 -> norm1
22. I0721 10:38:16.722251 4692 net.cpp:125] Top shape: 256 96 27 27 (17915904): output data of layer 1
23. I0721 10:38:16.722260 4692 net.cpp:151] norm1 needs backward computation.
24. I0721 10:38:16.722272 4692 net.cpp:74] Creating Layer conv2
25. I0721 10:38:16.722280 4692 net.cpp:84] conv2 <- norm1
26. I0721 10:38:16.722290 4692 net.cpp:110] conv2 -> conv2
27. I0721 10:38:16.725225 4692 net.cpp:125] Top shape: 256 256 27 27 (47775744)
28. I0721 10:38:16.725242 4692 net.cpp:151] conv2 needs backward computation.
29. I0721 10:38:16.725253 4692 net.cpp:74] Creating Layer relu2
30. I0721 10:38:16.725261 4692 net.cpp:84] relu2 <- conv2
31. I0721 10:38:16.725270 4692 net.cpp:98] relu2 -> conv2 (in-place)
32. I0721 10:38:16.725280 4692 net.cpp:125] Top shape: 256 256 27 27 (47775744)
33. I0721 10:38:16.725288 4692 net.cpp:151] relu2 needs backward computation.
34. I0721 10:38:16.725298 4692 net.cpp:74] Creating Layer pool2
35. I0721 10:38:16.725307 4692 net.cpp:84] pool2 <- conv2
36. I0721 10:38:16.725317 4692 net.cpp:110] pool2 -> pool2
37. I0721 10:38:16.725329 4692 net.cpp:125] Top shape: 256 256 13 13 (11075584)
38. I0721 10:38:16.725338 4692 net.cpp:151] pool2 needs backward computation.
39. I0721 10:38:16.725358 4692 net.cpp:74] Creating Layer norm2
40. I0721 10:38:16.725368 4692 net.cpp:84] norm2 <- pool2
41. I0721 10:38:16.725378 4692 net.cpp:110] norm2 -> norm2
42. I0721 10:38:16.725389 4692 net.cpp:125] Top shape: 256 256 13 13 (11075584): output data of layer 2
43. I0721 10:38:16.725399 4692 net.cpp:151] norm2 needs backward computation.
44. I0721 10:38:16.725409 4692 net.cpp:74] Creating Layer conv3
45. I0721 10:38:16.725419 4692 net.cpp:84] conv3 <- norm2
46. I0721 10:38:16.725427 4692 net.cpp:110] conv3 -> conv3
47. I0721 10:38:16.735193 4692 net.cpp:125] Top shape: 256 384 13 13 (16613376)
48. I0721 10:38:16.735213 4692 net.cpp:151] conv3 needs backward computation.
49. I0721 10:38:16.735224 4692 net.cpp:74] Creating Layer relu3
50. I0721 10:38:16.735234 4692 net.cpp:84] relu3 <- conv3
51. I0721 10:38:16.735242 4692 net.cpp:98] relu3 -> conv3 (in-place)
52. I0721 10:38:16.735250 4692 net.cpp:125] Top shape: 256 384 13 13 (16613376): output data of layer 3
53. I0721 10:38:16.735258 4692 net.cpp:151] relu3 needs backward computation.
54. I0721 10:38:16.735302 4692 net.cpp:74] Creating Layer conv4
55. I0721 10:38:16.735312 4692 net.cpp:84] conv4 <- conv3
56. I0721 10:38:16.735321 4692 net.cpp:110] conv4 -> conv4
57. I0721 10:38:16.743952 4692 net.cpp:125] Top shape: 256 384 13 13 (16613376)
58. I0721 10:38:16.743988 4692 net.cpp:151] conv4 needs backward computation.
59. I0721 10:38:16.744000 4692 net.cpp:74] Creating Layer relu4
60. I0721 10:38:16.744010 4692 net.cpp:84] relu4 <- conv4
61. I0721 10:38:16.744020 4692 net.cpp:98] relu4 -> conv4 (in-place)
62. I0721 10:38:16.744030 4692 net.cpp:125] Top shape: 256 384 13 13 (16613376): output data of layer 4
63. I0721 10:38:16.744038 4692 net.cpp:151] relu4 needs backward computation.
64. I0721 10:38:16.744050 4692 net.cpp:74] Creating Layer conv5
65. I0721 10:38:16.744057 4692 net.cpp:84] conv5 <- conv4
66. I0721 10:38:16.744067 4692 net.cpp:110] conv5 -> conv5
67. I0721 10:38:16.748935 4692 net.cpp:125] Top shape: 256 256 13 13 (11075584)
68. I0721 10:38:16.748955 4692 net.cpp:151] conv5 needs backward computation.
69. I0721 10:38:16.748965 4692 net.cpp:74] Creating Layer relu5
70. I0721 10:38:16.748975 4692 net.cpp:84] relu5 <- conv5
71. I0721 10:38:16.748983 4692 net.cpp:98] relu5 -> conv5 (in-place)
72. I0721 10:38:16.748998 4692 net.cpp:125] Top shape: 256 256 13 13 (11075584)
73. I0721 10:38:16.749011 4692 net.cpp:151] relu5 needs backward computation.
74. I0721 10:38:16.749022 4692 net.cpp:74] Creating Layer pool5
75. I0721 10:38:16.749030 4692 net.cpp:84] pool5 <- conv5
76. I0721 10:38:16.749039 4692 net.cpp:110] pool5 -> pool5
77. I0721 10:38:16.749050 4692 net.cpp:125] Top shape: 256 256 6 6 (2359296): output data of layer 5
78. I0721 10:38:16.749058 4692 net.cpp:151] pool5 needs backward computation.
79. I0721 10:38:16.749074 4692 net.cpp:74] Creating Layer fc6
80. I0721 10:38:16.749083 4692 net.cpp:84] fc6 <- pool5
81. I0721 10:38:16.749091 4692 net.cpp:110] fc6 -> fc6
82. I0721 10:38:17.160079 4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576)
83. I0721 10:38:17.160148 4692 net.cpp:151] fc6 needs backward computation.
84. I0721 10:38:17.160166 4692 net.cpp:74] Creating Layer relu6
85. I0721 10:38:17.160177 4692 net.cpp:84] relu6 <- fc6
86. I0721 10:38:17.160190 4692 net.cpp:98] relu6 -> fc6 (in-place)
87. I0721 10:38:17.160202 4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576)
88. I0721 10:38:17.160212 4692 net.cpp:151] relu6 needs backward computation.
89. I0721 10:38:17.160222 4692 net.cpp:74] Creating Layer drop6
90. I0721 10:38:17.160230 4692 net.cpp:84] drop6 <- fc6
91. I0721 10:38:17.160238 4692 net.cpp:98] drop6 -> fc6 (in-place)
92. I0721 10:38:17.160258 4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576):output data of layer 6
93. I0721 10:38:17.160265 4692 net.cpp:151] drop6 needs backward computation.
94. I0721 10:38:17.160277 4692 net.cpp:74] Creating Layer fc7
95. I0721 10:38:17.160286 4692 net.cpp:84] fc7 <- fc6
96. I0721 10:38:17.160295 4692 net.cpp:110] fc7 -> fc7
97. I0721 10:38:17.342094 4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576)
98. I0721 10:38:17.342157 4692 net.cpp:151] fc7 needs backward computation.
99. I0721 10:38:17.342175 4692 net.cpp:74] Creating Layer relu7
100. I0721 10:38:17.342185 4692 net.cpp:84] relu7 <- fc7
101. I0721 10:38:17.342198 4692 net.cpp:98] relu7 -> fc7 (in-place)
102. I0721 10:38:17.342208 4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576)
103. I0721 10:38:17.342217 4692 net.cpp:151] relu7 needs backward computation.
104. I0721 10:38:17.342228 4692 net.cpp:74] Creating Layer drop7
105. I0721 10:38:17.342236 4692 net.cpp:84] drop7 <- fc7
106. I0721 10:38:17.342245 4692 net.cpp:98] drop7 -> fc7 (in-place)
107. I0721 10:38:17.342254 4692 net.cpp:125] Top shape: 256 4096 1 1 (1048576):output data of layer 7
108. I0721 10:38:17.342262 4692 net.cpp:151] drop7 needs backward computation.
109. I0721 10:38:17.342274 4692 net.cpp:74] Creating Layer fc8
110. I0721 10:38:17.342283 4692 net.cpp:84] fc8 <- fc7
111. I0721 10:38:17.342291 4692 net.cpp:110] fc8 -> fc8
112. I0721 10:38:17.343199 4692 net.cpp:125] Top shape: 256 22 1 1 (5632)
113. I0721 10:38:17.343214 4692 net.cpp:151] fc8 needs backward computation.
114. I0721 10:38:17.343231 4692 net.cpp:74] Creating Layer loss
115. I0721 10:38:17.343240 4692 net.cpp:84] loss <- fc8
116. I0721 10:38:17.343250 4692 net.cpp:84] loss <- label
117. I0721 10:38:17.343264 4692 net.cpp:151] loss needs backward computation.
118. I0721 10:38:17.343305 4692 net.cpp:173] Collecting Learning Rate and Weight Decay.
119. I0721 10:38:17.343327 4692 net.cpp:166] Network initialization done.
120. I0721 10:38:17.343335 4692 net.cpp:167] Memory required for Data 1073760256
</div>