1 #coding=utf-8
2 import tensorflow as tf
3 from datetime import datetime
4 import math
5 import time
6 slim = tf.contrib.slim
7 trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)
8
9 def inception_v3_arg_scope(weight_decay=0.00004, stddev=0.1,batch_norm_var_collection='moving_vars'):
10
11 '''作用:生成网络中经常用到的默认参数。
12 weight_decay:L2正则,设为默认0.00004
13 stddev:标准差'''
14 #batch_normalization参数字典
15 batch_norm_params = {
16 'decay':0.9997,#衰减系数
17 'epsilon':0.001,
18 'updates_collections':tf.GraphKeys.UPDATE_OPS,
19 'variables_collections':{
20 'beta':None,
21 'gamma':None,
22 'moving_mean':[batch_norm_var_collection],
23 'moving_variance':[batch_norm_var_collection],
24 }
25 }
26 #slim.arg_scope给函数参数自动赋予默认值
27 with slim.arg_scope([slim.conv2d, slim.fully_connected],
28 weights_regularizer=slim.l2_regularizer(weight_decay)):
29 #嵌套slim.arg_scope
30 with slim.arg_scope(
31 [slim.conv2d],
32 weights_initializer=tf.truncated_normal_initializer(stddev=stddev),
33 activation_fn=tf.nn.relu,
34 normalizer_fn=slim.batch_norm,
35 normalizer_params=batch_norm_params) as sc:
36 return sc
37
38 def inception_v3_base(input, scope=None):
39 '''作用生成v3网络的卷积部分
40 input:输入图片数据的tensor
41 scope:函数默认的参数环境'''
42
43 end_points = {}#保存关键节点
44
45 with tf.variable_scope(scope, 'InceptionsV3', [inputs]):
46
47 with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
48 stride=1, padding='VALID'):
49 '''定义5个卷积层和2个最大池化层, 输入尺寸为299x299x3,输出尺寸为35x35x192
50 输入:tensor,32:输出的通道数,[3, 3]:卷积核尺寸,stride:步长'''
51 net = slim.conv2d(inputs, 32, [3, 3], stride=2, scope='Conv2d_1a_3x3')
52 net = slim.conv2d(net, 32, [3, 3], scope='Conv2d_2a_3x3')
53 net = slim.conv2d(net, 64, [3, 3], padding='SAME', scope='Conv2d_2b_3x3')
54 net = slim.max_pool2d(net, [3, 3], stride=2, scope='MaxPool_3a_3x3' )
55 net = slim.conv2d(net, 80, [1, 1], scope='Conv2d_3b_1x1')
56 net = slim.conv2d(net, 192, [3, 3], scope='Conv2d_4a_3x3')
57 net = slim.max_pool2d(net, [3, 3], stride=2, scope='MaxPool_5a_3x3')
58
59 with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d], stride=1, padding='SAME'):
60 '''定义3个连续的Inception模块组'''
61
62 with tf.variable_scope('Mixed_5b'):
63
64 with tf.variable_scope('Branch_0'):
65 '''64:输出通道 1x1的卷积核'''
66 branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
67 with tf.variable_scope('Branch_1'):
68 '''48输出通道的1x1卷积核连接64输出通道的5x5卷积核'''
69 branch_1 = slim.conv2d(net, 48, [1, 1], scope='Conv2d_0a_1x1')
70 branch_1 = slim.conv2d(branch_1, 64, [5, 5], scope='Conv2d_0b_5x5')
71 with tf.variable_scope('Branch_2'):
72 '''64输出通道的1x1卷积核连接2个96输出通道的3x3卷积核'''
73 branch_2 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
74 branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0b_3x3')
75 branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0c_3x3')
76 with tf.variable_scope('Branch_3'):
77 '''3x3的平均池化连接32输出通道的1x1卷积核'''
78 branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
79 branch_3 = slim.conv2d(branch_3, 32, [1, 1], scope='Conv2d_0b_1x1')
80 '''tf.concat将4分支合并在一起,形成module的最终输出35x35x(64+64+96+32)'''
81 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
82
83
84 with tf.variable_scope('Mixed_5c'):
85 with tf.variable_scope('Branch_0'):
86 '''64:输出通道 1x1的卷积核'''
87 branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
88 with tf.variable_scope('Branch_1'):
89 '''48输出通道的1x1卷积核连接64输出通道的5x5卷积核'''
90 branch_1 = slim.conv2d(net, 48, [1, 1], scope='Conv2d_0b_1x1')
91 branch_1 = slim.conv2d(branch_1, 64, [5, 5], scope='Conv2d_0c_5x5')
92 with tf.variable_scope('Branch_2'):
93 '''64输出通道的1x1卷积核连接2个96输出通道的3x3卷积核'''
94 branch_2 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
95 branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0b_3x3')
96 branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0c_3x3')
97 with tf.variable_scope('Branch_3'):
98 '''3x3的平均池化连接32输出通道的1x1卷积核'''
99 branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
100 branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
101 '''tf.concat将4分支合并在一起,形成module的最终输出35x35x(64+64+96+64)'''
102 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
103
104
105 with tf.variable_scope('Mixed_5d'):
106
107 with tf.variable_scope('Branch_0'):
108 '''64:输出通道 1x1的卷积核'''
109 branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
110 with tf.variable_scope('Branch_1'):
111 '''48输出通道的1x1卷积核连接64输出通道的5x5卷积核'''
112 branch_1 = slim.conv2d(net, 48, [1, 1], scope='Conv2d_0b_1x1')
113 branch_1 = slim.conv2d(branch_1, 64, [5, 5], scope='Conv2d_0c_5x5')
114 with tf.variable_scope('Branch_2'):
115 '''64输出通道的1x1卷积核连接2个96输出通道的3x3卷积核'''
116 branch_2 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
117 branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0b_3x3')
118 branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0c_3x3')
119 with tf.variable_scope('Branch_3'):
120 '''3x3的平均池化连接32输出通道的1x1卷积核'''
121 branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
122 branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
123 '''tf.concat将4分支合并在一起,形成module的最终输出35x35x(64+64+96+64)'''
124 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
125
126 with tf.variable_scope('Mixed_6a'):
127
128 with tf.variable_scope('Branch_0'):
129 '''384:输出通道 3x3的卷积核 由于步长为2,输出尺寸为17x17x384'''
130 branch_0 = slim.conv2d(net, 384, [3, 3], stride=2,
131 padding='VALID', scope='Conv2d_1a_1x1')
132 with tf.variable_scope('Branch_1'):
133 '''64输出通道的1x1卷积核连接2个96输出通道的3x3卷积核,输出尺寸为17x17x96 '''
134 branch_1 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
135 branch_1 = slim.conv2d(branch_1, 96, [3, 3],
136 scope='Conv2d_0b_3x3')
137 branch_1 = slim.conv2d(branch_1, 96, [3, 3], stride=2,
138 padding='VALID', scope='Conv2d_1a_3x3')
139 with tf.variable_scope('Branch_2'):
140 '''3x3最大池化层, 输出尺寸为17x17x256'''
141 branch_2 = slim.max_pool2d(net, [3, 3], stride=2,
142 padding='VALID', scope='MaxPool_1a_3x3')
143
144 '''tf.concat将3分支合并在一起,形成module的最终输出17x17x(384+48+64)'''
145 net = tf.concat([branch_0, branch_1, branch_2], 3)
146
147 with tf.variable_scope('Mixed_6b'):
148
149 with tf.variable_scope('Branch_0'):
150 '''192:输出通道 1x1的卷积核 '''
151 branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1')
152
153 with tf.variable_scope('Branch_1'):
154 '''第一层:128输出通道的1x1的卷积
155 第二层:128输出通道的1x7的卷积
156 第三层:192输出通道的7x1的卷积'''
157 branch_1 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1')
158 branch_1 = slim.conv2d(branch_1, 128, [1, 7], scope='Conv2d_0b_1x7')
159 branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d_0c_7x1')
160
161 with tf.variable_scope('Branch_2'):
162 '''第一层:128输出通道的1x1的卷积
163 第二层:128输出通道的7x1的卷积
164 第三层:128输出通道的1x7的卷积
165 第四层:128输出通道的7x1的卷积
166 第五层:192输出通道的1x7的卷积'''
167 branch_2 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1')
168 branch_2 = slim.conv2d(branch_2, 128, [7, 1], scope='Conv2d_0b_7x1')
169 branch_2 = slim.conv2d(branch_2, 128, [1, 7], scope='Conv2d_0c_1x1')
170 branch_2 = slim.conv2d(branch_2, 128, [7, 1], scope='Conv2d_0d_7x1')
171 branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d_0e_7x1')
172
173 with tf.variable_scope('Branch_3'):
174 '''3x3的平均池化连接192输出通道的1x1卷积核'''
175 branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
176 branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1')
177
178 '''tf.concat将4分支合并在一起,形成module的最终输出17x17x(192+192+192+192)'''
179 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
180
181 with tf.variable_scope('Mixed_6c'):
182 with tf.variable_scope('Branch_0'):
183 '''192:输出通道 1x1的卷积核 '''
184 branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1')
185
186 with tf.variable_scope('Branch_1'):
187 '''第一层:160输出通道的1x1的卷积
188 第二层:160输出通道的1x7的卷积
189 第三层:192输出通道的7x1的卷积'''
190 branch_1 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
191 branch_1 = slim.conv2d(branch_1, 160, [1, 7], scope='Conv2d_0b_1x7')
192 branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d_0c_7x1')
193
194 with tf.variable_scope('Branch_2'):
195 '''第一层:160输出通道的1x1的卷积
196 第二层:160输出通道的7x1的卷积
197 第三层:160输出通道的1x7的卷积
198 第四层:160输出通道的7x1的卷积
199 第五层:192输出通道的1x7的卷积'''
200 branch_2 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
201 branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d_0b_7x1')
202 branch_2 = slim.conv2d(branch_2, 160, [1, 7], scope='Conv2d_0c_1x1')
203 branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d_0d_7x1')
204 branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d_0e_7x1')
205
206 with tf.variable_scope('Branch_3'):
207 '''3x3的平均池化连接192输出通道的1x1卷积核'''
208 branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
209 branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1')
210
211 '''tf.concat将4分支合并在一起,形成module的最终输出17x17x(192+192+192+192)'''
212 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
213
214
215 with tf.variable_scope('Mixed_6e'):
216 with tf.variable_scope('Branch_0'):
217 '''192:输出通道 1x1的卷积核 '''
218 branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1')
219
220 with tf.variable_scope('Branch_1'):
221 '''第一层:160输出通道的1x1的卷积
222 第二层:160输出通道的1x7的卷积
223 第三层:192输出通道的7x1的卷积'''
224 branch_1 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
225 branch_1 = slim.conv2d(branch_1, 160, [1, 7], scope='Conv2d_0b_1x7')
226 branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d_0c_7x1')
227
228 with tf.variable_scope('Branch_2'):
229 '''第一层:160输出通道的1x1的卷积
230 第二层:160输出通道的7x1的卷积
231 第三层:160输出通道的1x7的卷积
232 第四层:160输出通道的7x1的卷积
233 第五层:192输出通道的1x7的卷积'''
234 branch_2 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
235 branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d_0b_7x1')
236 branch_2 = slim.conv2d(branch_2, 160, [1, 7], scope='Conv2d_0c_1x1')
237 branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d_0d_7x1')
238 branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d_0e_7x1')
239
240 with tf.variable_scope('Branch_3'):
241 '''3x3的平均池化连接192输出通道的1x1卷积核'''
242 branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
243 branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1')
244
245 '''tf.concat将4分支合并在一起,形成module的最终输出17x17x(192+192+192+192)'''
246 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
247
248 with tf.variable_scope('Mixed_6d'):
249 with tf.variable_scope('Branch_0'):
250 '''192:输出通道 1x1的卷积核 '''
251 branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1')
252
253 with tf.variable_scope('Branch_1'):
254 '''第一层:160输出通道的1x1的卷积
255 第二层:160输出通道的1x7的卷积
256 第三层:192输出通道的7x1的卷积'''
257 branch_1 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
258 branch_1 = slim.conv2d(branch_1, 160, [1, 7], scope='Conv2d_0b_1x7')
259 branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d_0c_7x1')
260
261 with tf.variable_scope('Branch_2'):
262 '''第一层:160输出通道的1x1的卷积
263 第二层:160输出通道的7x1的卷积
264 第三层:160输出通道的1x7的卷积
265 第四层:160输出通道的7x1的卷积
266 第五层:192输出通道的1x7的卷积'''
267 branch_2 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
268 branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d_0b_7x1')
269 branch_2 = slim.conv2d(branch_2, 160, [1, 7], scope='Conv2d_0c_1x1')
270 branch_2 = slim.conv2d(branch_2, 160, [7, 1], scope='Conv2d_0d_7x1')
271 branch_2 = slim.conv2d(branch_2, 192, [1, 7], scope='Conv2d_0e_7x1')
272
273 with tf.variable_scope('Branch_3'):
274 '''3x3的平均池化连接192输出通道的1x1卷积核'''
275 branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
276 branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1')
277
278 '''tf.concat将4分支合并在一起,形成module的最终输出17x17x(192+192+192+192)'''
279 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
280 '''将Mixed_6e存储于end_points中,作为Auxiliary Classifier 辅助模型的分类'''
281 end_points['Mixed_6e'] = net
282
283 with tf.variable_scope('Mixed_7a'):
284 with tf.variable_scope('Branch_0'):
285 '''192:输出通道 1x1的卷积核再连接320输出通道数的3x3的卷积,步长为2,
286 由于padding为VALID, 图片尺寸压缩为8x8'''
287 branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1')
288 branch_0 = slim.conv2d(branch_0, 320, [3, 3], stride=2,
289 padding='VALID', scope='Conv2d_1a_3x3')
290
291 with tf.variable_scope('Branch_1'):
292 '''第一层:192输出通道的1x1的卷积
293 第二层:192输出通道的1x7的卷积
294 第三层:192输出通道的7x1的卷积
295 第四层:192输出通道的3x3的卷积
296 tensor输出尺寸为8x8x192'''
297 branch_1 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1')
298 branch_1 = slim.conv2d(branch_1, 192, [1, 7], scope='Conv2d_0b_1x7')
299 branch_1 = slim.conv2d(branch_1, 192, [7, 1], scope='Conv2d_0c_7x1')
300 branch_1 = slim.conv2d(branch_1, 192, [3, 3], stride=2,
301 padding='VALID', scope='Conv2d_1a_3x3')
302 with tf.variable_scope('Branch_2'):
303 '''3x3的最大池化层,步长为2,padding为VALID,由于池化层对输出通道不会产生改变
304 故输出尺寸为8x8x768'''
305 branch_2 = slim.max_pool2d(net, [3, 3], stride=2,
306 padding='VALID', scope='MaxPool_1a_3x3')
307 '''tf.concat将3分支合并在一起,形成module的最终输出8x8x(320+192+768)'''
308 net = tf.concat([branch_0, branch_1, branch_2], 3)
309
310 with tf.variable_scope('Mixed_7b'):
311
312 with tf.variable_scope('Branch_0'):
313 '''320输出通道的1x1的卷积'''
314 branch_0 = slim.conv2d(net, 320, [1, 1], scope='Conv2d_0a_1x1')
315
316 with tf.variable_scope('Branch_1'):
317 '''第一层:1个384输出通道的1x1卷积
318 第二层:由384输出通道的1x3的卷积和384输出通道的3x1的卷积合并
319 tensor输出尺寸为:8x8x(384+384)=8x8x768'''
320 branch_1 = slim.conv2d(net, 384, [1, 1], scope='Conv2d_0a_1x1')
321 branch_1 = tf.concat([
322 slim.conv2d(branch_1, 384, [1, 3], scope='Conv2d_0b_1x3'),
323 slim.conv2d(branch_1, 384, [3, 1], scope='Conv2d_0c_3x1'),], 3)
324
325
326 with tf.variable_scope('Branch_2'):
327 '''第一层:1个448输出通道的1x1卷积
328 第二层:384输出通道的3x3的卷积分支内拆成两个分支分别是:
329 384输出通道的1x3的卷积和384输出通道的3x1的卷积最后合并
330 tensor输出尺寸为:8x8x(384+384)=8x8x768'''
331 branch_2 = slim.conv2d(net, 448, [1, 1], scope='Conv2d_0a_1x1')
332 branch_2 = slim.conv2d(branch_2, 448, [3, 3], scope='Conv2d_0b_3x3')
333 branch_2 = tf.concat([
334 slim.conv2d(branch_2, 384, [1, 3], scope='Conv2d_0c_1x3'),
335 slim.conv2d(branch_2, 384, [3, 1], scope='Conv2d_0d_3x1'),], 3)
336
337 with tf.variable_scope('Branch_3'):
338 '''3x3平均池化层后接一个192输出通道的1x1卷积
339 tensor输出尺寸为:8x8x192'''
340 branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
341 branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1')
342
343 '''tf.concat将3分支合并在一起,形成module的最终输出8x8x(320+768+768+192)'''
344 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
345
346 with tf.variable_scope('Mixed_7c'):
347 with tf.variable_scope('Branch_0'):
348 '''320输出通道的1x1的卷积'''
349 branch_0 = slim.conv2d(net, 320, [1, 1], scope='Conv2d_0a_1x1')
350
351 with tf.variable_scope('Branch_1'):
352 '''第一层:1个384输出通道的1x1卷积
353 第二层:由384输出通道的1x3的卷积和384输出通道的3x1的卷积合并
354 tensor输出尺寸为:8x8x(384+384)=8x8x768'''
355 branch_1 = slim.conv2d(net, 384, [1, 1], scope='Conv2d_0a_1x1')
356 branch_1 = tf.concat([
357 slim.conv2d(branch_1, 384, [1, 3], scope='Conv2d_0b_1x3'),
358 slim.conv2d(branch_1, 384, [3, 1], scope='Conv2d_0c_3x1'), ], 3)
359
360 with tf.variable_scope('Branch_2'):
361 '''第一层:1个448输出通道的1x1卷积
362 第二层:384输出通道的3x3的卷积分支内拆成两个分支分别是:
363 384输出通道的1x3的卷积和384输出通道的3x1的卷积最后合并
364 tensor输出尺寸为:8x8x(384+384)=8x8x768'''
365 branch_2 = slim.conv2d(net, 448, [1, 1], scope='Conv2d_0a_1x1')
366 branch_2 = slim.conv2d(branch_2, 448, [3, 3], scope='Conv2d_0b_3x3')
367 branch_2 = tf.concat([
368 slim.conv2d(branch_2, 384, [1, 3], scope='Conv2d_0c_1x3'),
369 slim.conv2d(branch_2, 384, [3, 1], scope='Conv2d_0d_3x1'), ], 3)
370
371 with tf.variable_scope('Branch_3'):
372 '''3x3平均池化层后接一个192输出通道的1x1卷积
373 tensor输出尺寸为:8x8x192'''
374 branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
375 branch_3 = slim.conv2d(branch_3, 192, [1, 1], scope='Conv2d_0b_1x1')
376
377 '''tf.concat将3分支合并在一起,形成module的最终输出8x8x(320+768+768+192)'''
378 net = tf.concat([branch_0, branch_1, branch_2, branch_3], 3)
379
380 return net, end_points
381
382
383 def inception_v3(inputs,
384 num_classes=1000,
385 is_training=True,
386 dropout_keep_prob=0.8,
387 prediction_fn=slim.softmax,
388 spatial_squeeze=True,
389 reuse=None,
390 scope='Inceptionv3'):
391 '''作用:全局平均池化、softmax、Auxiliary Logits
392 num_classes:最后需要分类的数量
393 is_training:是否是训练过程标志
394 dropout_keep_prob:Dropout所需保留节点的比例
395 prediction_fn:最后用来分类的函数
396 spatial_squeeze:是否进行squeeze标志,(去除维数的操作5x3x1->5x3)
397 reuse:是否对网络和Variable进行重复使用的标志
398 scope:包含默认参数的环境'''
399
400 '''使用tf.variable_scope定义网络name、 reuse等参数'''
401 with tf.variable_scope(scope, 'InceptionV3', [inputs, num_classes], reuse=reuse) as scope:
402 '''使用slim.arg_scope定义Batch Normalization和Dropout的is_training标志的默认值'''
403 with slim.arg_scope([slim.batch_norm, slim.dropout], is_training=is_training):
404 #获取最后一层输出net,end_points
405 net, end_points = inception_v3_base(inputs, scope=scope)
406
407 with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
408 stride=1, padding='SAME'):
409 '''处理Auxiliary Logits部分的逻辑:
410 使用slim.avg_pool2d将卷积、最大池化、
411 平均池化的默认步长设为3,padding设为VALID,end_points获取Mixed_6e'''
412
413 aux_logits = end_points['Mixed_6e']
414
415 with tf.variable_scope('AuxLogits'):
416 '''Mixed_6e接5x5平均池化,步长为3,padding为VALID
417 输出尺寸:17x17x768->5x5x768((17-5+1)/3=5)'''
418
419 aux_logits = slim.avg_pool2d(
420 aux_logits, [5, 5], stride=3, padding='VALID',
421 scope='AvgPool_1a_5x5')
422 '''128输出通道的1x1卷积'''
423 aux_logits = slim.conv2d(
424 aux_logits, 128, [1, 1], scope = 'Conv2d_1b_1x1')
425 '''768输出通道的5x5卷积,
426 输出尺寸变为1x1x768'''
427 aux_logits = slim.conv2d(
428 aux_logits, 768, [5, 5],
429 weights_initializer=trunc_normal(0.01),
430 padding='VALID', scope='Conv2d_2a_5x5')
431 '''输出通道为num_classes的1x1的卷积,
432 输出尺寸变为1x1x1000'''
433 aux_logits = slim.conv2d(
434 aux_logits, num_classes, [1, 1], activation_fn=None,
435 normalizer_fn=None, weights_initializer=trunc_normal(0.01),
436 scope='Conv2d_2b_1x1')
437
438 if spatial_squeeze:
439 '''将1x1x1000通过tf.squeeze变为1000存储到end_points'''
440 aux_logits = tf.squeeze(aux_logits, [1, 2],
441 name='SpatialSqueeze')
442 end_points['AuxLogits'] = aux_logits
443
444 with tf.variable_scope('Logits'):
445 '''处理正常分类预测的逻辑:
446 对Mixed_7e最后一个卷积层的输出进行8x8全局平均化池化,padding为VALID
447 输出尺寸:8x8x2048->1x1x2048
448 '''
449 net = slim.avg_pool2d(net, [8, 8], padding='VALID', scope='AvgPool_1a_8x8')
450 '''连接一个Dropout层,节点保留率:dropout_keep_prob'''
451 net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')
452
453 end_points['PreLogits'] = net
454 '''1000输出通道1x1的卷积'''
455 logits = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
456 normalizer_fn=None, scope='Conv2d_1c_1x1')
457
458 if spatial_squeeze:
459 '''tf.sqeeze去一维'''
460 logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
461
462 end_points['Logits'] = logits
463 '''接softmax对结果进行分类预测'''
464 end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
465 '''返回结果logits,包含辅助节点的end_points'''
466 return logits, end_points
467
468 def time_tensorflow_run(session, target, info_string):
469
470 num_steps_burn_in = 10
471 total_duration = 0.0
472 total_duration_squared = 0.0
473 for i in range(num_batches+num_steps_burn_in):
474 start_time = time.time()
475 _ = session.run(target)
476 duration = time.time()-start_time
477
478 if i >= num_steps_burn_in:
479 if not i % 10:
480 print('%s: step %d, duration = %.3f' %(datetime.now(), i-num_steps_burn_in, duration))
481 total_duration += duration
482 total_duration_squared += duration*duration
483
484 mn = total_duration/num_batches
485 vr = total_duration_squared/num_batches-mn*mn
486 sd = math.sqrt(vr)
487
488 print('%s: %s across %d steps, %.3f +/- %3.3f sec/batch' %(datetime.now(), info_string, num_batches, mn, sd))
489
490 batch_size = 32
491 height, width = 299, 299
492
493 inputs = tf.random_uniform((batch_size, height, width, 3))
494
495 with slim.arg_scope(inception_v3_arg_scope()):
496 logits, end_points = inception_v3(inputs, is_training=False)
497
498 init = tf.global_variables_initializer()
499 sess = tf.Session()
500 sess.run(init)
501 num_batches = 100
502 time_tensorflow_run(sess, logits, "Forward")