pcb defect detetcion application
[ealt-edge.git] / example-apps / PDD / pcb-defect-detection / libs / networks / slim_nets / inception_v3.py
1 # Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 # ==============================================================================
15 """Contains the definition for inception v3 classification network."""
16
17 from __future__ import absolute_import
18 from __future__ import division
19 from __future__ import print_function
20
21 import tensorflow as tf
22
23 from nets import inception_utils
24
25 slim = tf.contrib.slim
26 trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)
27
28
29 def inception_v3_base(inputs,
30                       final_endpoint='Mixed_7c',
31                       min_depth=16,
32                       depth_multiplier=1.0,
33                       scope=None):
34   """Inception model from http://arxiv.org/abs/1512.00567.
35
36   Constructs an Inception v3 network from inputs to the given final endpoint.
37   This method can construct the network up to the final inception block
38   Mixed_7c.
39
40   Note that the names of the layers in the paper do not correspond to the names
41   of the endpoints registered by this function although they build the same
42   network.
43
44   Here is a mapping from the old_names to the new names:
45   Old name          | New name
46   =======================================
47   conv0             | Conv2d_1a_3x3
48   conv1             | Conv2d_2a_3x3
49   conv2             | Conv2d_2b_3x3
50   pool1             | MaxPool_3a_3x3
51   conv3             | Conv2d_3b_1x1
52   conv4             | Conv2d_4a_3x3
53   pool2             | MaxPool_5a_3x3
54   mixed_35x35x256a  | Mixed_5b
55   mixed_35x35x288a  | Mixed_5c
56   mixed_35x35x288b  | Mixed_5d
57   mixed_17x17x768a  | Mixed_6a
58   mixed_17x17x768b  | Mixed_6b
59   mixed_17x17x768c  | Mixed_6c
60   mixed_17x17x768d  | Mixed_6d
61   mixed_17x17x768e  | Mixed_6e
62   mixed_8x8x1280a   | Mixed_7a
63   mixed_8x8x2048a   | Mixed_7b
64   mixed_8x8x2048b   | Mixed_7c
65
66   Args:
67     inputs: a tensor of size [batch_size, height, width, channels].
68     final_endpoint: specifies the endpoint to construct the network up to. It
69       can be one of ['Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3',
70       'MaxPool_3a_3x3', 'Conv2d_3b_1x1', 'Conv2d_4a_3x3', 'MaxPool_5a_3x3',
71       'Mixed_5b', 'Mixed_5c', 'Mixed_5d', 'Mixed_6a', 'Mixed_6b', 'Mixed_6c',
72       'Mixed_6d', 'Mixed_6e', 'Mixed_7a', 'Mixed_7b', 'Mixed_7c'].
73     min_depth: Minimum depth value (number of channels) for all convolution ops.
74       Enforced when depth_multiplier < 1, and not an active constraint when
75       depth_multiplier >= 1.
76     depth_multiplier: Float multiplier for the depth (number of channels)
77       for all convolution ops. The value must be greater than zero. Typical
78       usage will be to set this value in (0, 1) to reduce the number of
79       parameters or computation cost of the model.
80     scope: Optional variable_scope.
81
82   Returns:
83     tensor_out: output tensor corresponding to the final_endpoint.
84     end_points: a set of activations for external use, for example summaries or
85                 losses.
86
87   Raises:
88     ValueError: if final_endpoint is not set to one of the predefined values,
89                 or depth_multiplier <= 0
90   """
91   # end_points will collect relevant activations for external use, for example
92   # summaries or losses.
93   end_points = {}
94
95   if depth_multiplier <= 0:
96     raise ValueError('depth_multiplier is not greater than zero.')
97   depth = lambda d: max(int(d * depth_multiplier), min_depth)
98
99   with tf.variable_scope(scope, 'InceptionV3', [inputs]):
100     with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
101                         stride=1, padding='VALID'):
102       # 299 x 299 x 3
103       end_point = 'Conv2d_1a_3x3'
104       net = slim.conv2d(inputs, depth(32), [3, 3], stride=2, scope=end_point)
105       end_points[end_point] = net
106       if end_point == final_endpoint: return net, end_points
107       # 149 x 149 x 32
108       end_point = 'Conv2d_2a_3x3'
109       net = slim.conv2d(net, depth(32), [3, 3], scope=end_point)
110       end_points[end_point] = net
111       if end_point == final_endpoint: return net, end_points
112       # 147 x 147 x 32
113       end_point = 'Conv2d_2b_3x3'
114       net = slim.conv2d(net, depth(64), [3, 3], padding='SAME', scope=end_point)
115       end_points[end_point] = net
116       if end_point == final_endpoint: return net, end_points
117       # 147 x 147 x 64
118       end_point = 'MaxPool_3a_3x3'
119       net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
120       end_points[end_point] = net
121       if end_point == final_endpoint: return net, end_points
122       # 73 x 73 x 64
123       end_point = 'Conv2d_3b_1x1'
124       net = slim.conv2d(net, depth(80), [1, 1], scope=end_point)
125       end_points[end_point] = net
126       if end_point == final_endpoint: return net, end_points
127       # 73 x 73 x 80.
128       end_point = 'Conv2d_4a_3x3'
129       net = slim.conv2d(net, depth(192), [3, 3], scope=end_point)
130       end_points[end_point] = net
131       if end_point == final_endpoint: return net, end_points
132       # 71 x 71 x 192.
133       end_point = 'MaxPool_5a_3x3'
134       net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
135       end_points[end_point] = net
136       if end_point == final_endpoint: return net, end_points
137       # 35 x 35 x 192.
138
139     # Inception blocks
140     with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
141                         stride=1, padding='SAME'):
142       # mixed: 35 x 35 x 256.
143       end_point = 'Mixed_5b'
144       with tf.variable_scope(end_point):
145         with tf.variable_scope('Branch_0'):
146           branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
147         with tf.variable_scope('Branch_1'):
148           branch_1 = slim.conv2d(net, depth(48), [1, 1], scope='Conv2d_0a_1x1')
149           branch_1 = slim.conv2d(branch_1, depth(64), [5, 5],
150                                  scope='Conv2d_0b_5x5')
151         with tf.variable_scope('Branch_2'):
152           branch_2 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
153           branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
154                                  scope='Conv2d_0b_3x3')
155           branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
156                                  scope='Conv2d_0c_3x3')
157         with tf.variable_scope('Branch_3'):
158           branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
159           branch_3 = slim.conv2d(branch_3, depth(32), [1, 1],
160                                  scope='Conv2d_0b_1x1')
161         net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
162       end_points[end_point] = net
163       if end_point == final_endpoint: return net, end_points
164
165       # mixed_1: 35 x 35 x 288.
166       end_point = 'Mixed_5c'
167       with tf.variable_scope(end_point):
168         with tf.variable_scope('Branch_0'):
169           branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
170         with tf.variable_scope('Branch_1'):
171           branch_1 = slim.conv2d(net, depth(48), [1, 1], scope='Conv2d_0b_1x1')
172           branch_1 = slim.conv2d(branch_1, depth(64), [5, 5],
173                                  scope='Conv_1_0c_5x5')
174         with tf.variable_scope('Branch_2'):
175           branch_2 = slim.conv2d(net, depth(64), [1, 1],
176                                  scope='Conv2d_0a_1x1')
177           branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
178                                  scope='Conv2d_0b_3x3')
179           branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
180                                  scope='Conv2d_0c_3x3')
181         with tf.variable_scope('Branch_3'):
182           branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
183           branch_3 = slim.conv2d(branch_3, depth(64), [1, 1],
184                                  scope='Conv2d_0b_1x1')
185         net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
186       end_points[end_point] = net
187       if end_point == final_endpoint: return net, end_points
188
189       # mixed_2: 35 x 35 x 288.
190       end_point = 'Mixed_5d'
191       with tf.variable_scope(end_point):
192         with tf.variable_scope('Branch_0'):
193           branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
194         with tf.variable_scope('Branch_1'):
195           branch_1 = slim.conv2d(net, depth(48), [1, 1], scope='Conv2d_0a_1x1')
196           branch_1 = slim.conv2d(branch_1, depth(64), [5, 5],
197                                  scope='Conv2d_0b_5x5')
198         with tf.variable_scope('Branch_2'):
199           branch_2 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
200           branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
201                                  scope='Conv2d_0b_3x3')
202           branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
203                                  scope='Conv2d_0c_3x3')
204         with tf.variable_scope('Branch_3'):
205           branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
206           branch_3 = slim.conv2d(branch_3, depth(64), [1, 1],
207                                  scope='Conv2d_0b_1x1')
208         net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
209       end_points[end_point] = net
210       if end_point == final_endpoint: return net, end_points
211
212       # mixed_3: 17 x 17 x 768.
213       end_point = 'Mixed_6a'
214       with tf.variable_scope(end_point):
215         with tf.variable_scope('Branch_0'):
216           branch_0 = slim.conv2d(net, depth(384), [3, 3], stride=2,
217                                  padding='VALID', scope='Conv2d_1a_1x1')
218         with tf.variable_scope('Branch_1'):
219           branch_1 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
220           branch_1 = slim.conv2d(branch_1, depth(96), [3, 3],
221                                  scope='Conv2d_0b_3x3')
222           branch_1 = slim.conv2d(branch_1, depth(96), [3, 3], stride=2,
223                                  padding='VALID', scope='Conv2d_1a_1x1')
224         with tf.variable_scope('Branch_2'):
225           branch_2 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID',
226                                      scope='MaxPool_1a_3x3')
227         net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
228       end_points[end_point] = net
229       if end_point == final_endpoint: return net, end_points
230
231       # mixed4: 17 x 17 x 768.
232       end_point = 'Mixed_6b'
233       with tf.variable_scope(end_point):
234         with tf.variable_scope('Branch_0'):
235           branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
236         with tf.variable_scope('Branch_1'):
237           branch_1 = slim.conv2d(net, depth(128), [1, 1], scope='Conv2d_0a_1x1')
238           branch_1 = slim.conv2d(branch_1, depth(128), [1, 7],
239                                  scope='Conv2d_0b_1x7')
240           branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
241                                  scope='Conv2d_0c_7x1')
242         with tf.variable_scope('Branch_2'):
243           branch_2 = slim.conv2d(net, depth(128), [1, 1], scope='Conv2d_0a_1x1')
244           branch_2 = slim.conv2d(branch_2, depth(128), [7, 1],
245                                  scope='Conv2d_0b_7x1')
246           branch_2 = slim.conv2d(branch_2, depth(128), [1, 7],
247                                  scope='Conv2d_0c_1x7')
248           branch_2 = slim.conv2d(branch_2, depth(128), [7, 1],
249                                  scope='Conv2d_0d_7x1')
250           branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
251                                  scope='Conv2d_0e_1x7')
252         with tf.variable_scope('Branch_3'):
253           branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
254           branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
255                                  scope='Conv2d_0b_1x1')
256         net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
257       end_points[end_point] = net
258       if end_point == final_endpoint: return net, end_points
259
260       # mixed_5: 17 x 17 x 768.
261       end_point = 'Mixed_6c'
262       with tf.variable_scope(end_point):
263         with tf.variable_scope('Branch_0'):
264           branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
265         with tf.variable_scope('Branch_1'):
266           branch_1 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
267           branch_1 = slim.conv2d(branch_1, depth(160), [1, 7],
268                                  scope='Conv2d_0b_1x7')
269           branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
270                                  scope='Conv2d_0c_7x1')
271         with tf.variable_scope('Branch_2'):
272           branch_2 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
273           branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
274                                  scope='Conv2d_0b_7x1')
275           branch_2 = slim.conv2d(branch_2, depth(160), [1, 7],
276                                  scope='Conv2d_0c_1x7')
277           branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
278                                  scope='Conv2d_0d_7x1')
279           branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
280                                  scope='Conv2d_0e_1x7')
281         with tf.variable_scope('Branch_3'):
282           branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
283           branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
284                                  scope='Conv2d_0b_1x1')
285         net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
286       end_points[end_point] = net
287       if end_point == final_endpoint: return net, end_points
288       # mixed_6: 17 x 17 x 768.
289       end_point = 'Mixed_6d'
290       with tf.variable_scope(end_point):
291         with tf.variable_scope('Branch_0'):
292           branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
293         with tf.variable_scope('Branch_1'):
294           branch_1 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
295           branch_1 = slim.conv2d(branch_1, depth(160), [1, 7],
296                                  scope='Conv2d_0b_1x7')
297           branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
298                                  scope='Conv2d_0c_7x1')
299         with tf.variable_scope('Branch_2'):
300           branch_2 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
301           branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
302                                  scope='Conv2d_0b_7x1')
303           branch_2 = slim.conv2d(branch_2, depth(160), [1, 7],
304                                  scope='Conv2d_0c_1x7')
305           branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
306                                  scope='Conv2d_0d_7x1')
307           branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
308                                  scope='Conv2d_0e_1x7')
309         with tf.variable_scope('Branch_3'):
310           branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
311           branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
312                                  scope='Conv2d_0b_1x1')
313         net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
314       end_points[end_point] = net
315       if end_point == final_endpoint: return net, end_points
316
317       # mixed_7: 17 x 17 x 768.
318       end_point = 'Mixed_6e'
319       with tf.variable_scope(end_point):
320         with tf.variable_scope('Branch_0'):
321           branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
322         with tf.variable_scope('Branch_1'):
323           branch_1 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
324           branch_1 = slim.conv2d(branch_1, depth(192), [1, 7],
325                                  scope='Conv2d_0b_1x7')
326           branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
327                                  scope='Conv2d_0c_7x1')
328         with tf.variable_scope('Branch_2'):
329           branch_2 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
330           branch_2 = slim.conv2d(branch_2, depth(192), [7, 1],
331                                  scope='Conv2d_0b_7x1')
332           branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
333                                  scope='Conv2d_0c_1x7')
334           branch_2 = slim.conv2d(branch_2, depth(192), [7, 1],
335                                  scope='Conv2d_0d_7x1')
336           branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
337                                  scope='Conv2d_0e_1x7')
338         with tf.variable_scope('Branch_3'):
339           branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
340           branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
341                                  scope='Conv2d_0b_1x1')
342         net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
343       end_points[end_point] = net
344       if end_point == final_endpoint: return net, end_points
345
346       # mixed_8: 8 x 8 x 1280.
347       end_point = 'Mixed_7a'
348       with tf.variable_scope(end_point):
349         with tf.variable_scope('Branch_0'):
350           branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
351           branch_0 = slim.conv2d(branch_0, depth(320), [3, 3], stride=2,
352                                  padding='VALID', scope='Conv2d_1a_3x3')
353         with tf.variable_scope('Branch_1'):
354           branch_1 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
355           branch_1 = slim.conv2d(branch_1, depth(192), [1, 7],
356                                  scope='Conv2d_0b_1x7')
357           branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
358                                  scope='Conv2d_0c_7x1')
359           branch_1 = slim.conv2d(branch_1, depth(192), [3, 3], stride=2,
360                                  padding='VALID', scope='Conv2d_1a_3x3')
361         with tf.variable_scope('Branch_2'):
362           branch_2 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID',
363                                      scope='MaxPool_1a_3x3')
364         net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
365       end_points[end_point] = net
366       if end_point == final_endpoint: return net, end_points
367       # mixed_9: 8 x 8 x 2048.
368       end_point = 'Mixed_7b'
369       with tf.variable_scope(end_point):
370         with tf.variable_scope('Branch_0'):
371           branch_0 = slim.conv2d(net, depth(320), [1, 1], scope='Conv2d_0a_1x1')
372         with tf.variable_scope('Branch_1'):
373           branch_1 = slim.conv2d(net, depth(384), [1, 1], scope='Conv2d_0a_1x1')
374           branch_1 = tf.concat(axis=3, values=[
375               slim.conv2d(branch_1, depth(384), [1, 3], scope='Conv2d_0b_1x3'),
376               slim.conv2d(branch_1, depth(384), [3, 1], scope='Conv2d_0b_3x1')])
377         with tf.variable_scope('Branch_2'):
378           branch_2 = slim.conv2d(net, depth(448), [1, 1], scope='Conv2d_0a_1x1')
379           branch_2 = slim.conv2d(
380               branch_2, depth(384), [3, 3], scope='Conv2d_0b_3x3')
381           branch_2 = tf.concat(axis=3, values=[
382               slim.conv2d(branch_2, depth(384), [1, 3], scope='Conv2d_0c_1x3'),
383               slim.conv2d(branch_2, depth(384), [3, 1], scope='Conv2d_0d_3x1')])
384         with tf.variable_scope('Branch_3'):
385           branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
386           branch_3 = slim.conv2d(
387               branch_3, depth(192), [1, 1], scope='Conv2d_0b_1x1')
388         net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
389       end_points[end_point] = net
390       if end_point == final_endpoint: return net, end_points
391
392       # mixed_10: 8 x 8 x 2048.
393       end_point = 'Mixed_7c'
394       with tf.variable_scope(end_point):
395         with tf.variable_scope('Branch_0'):
396           branch_0 = slim.conv2d(net, depth(320), [1, 1], scope='Conv2d_0a_1x1')
397         with tf.variable_scope('Branch_1'):
398           branch_1 = slim.conv2d(net, depth(384), [1, 1], scope='Conv2d_0a_1x1')
399           branch_1 = tf.concat(axis=3, values=[
400               slim.conv2d(branch_1, depth(384), [1, 3], scope='Conv2d_0b_1x3'),
401               slim.conv2d(branch_1, depth(384), [3, 1], scope='Conv2d_0c_3x1')])
402         with tf.variable_scope('Branch_2'):
403           branch_2 = slim.conv2d(net, depth(448), [1, 1], scope='Conv2d_0a_1x1')
404           branch_2 = slim.conv2d(
405               branch_2, depth(384), [3, 3], scope='Conv2d_0b_3x3')
406           branch_2 = tf.concat(axis=3, values=[
407               slim.conv2d(branch_2, depth(384), [1, 3], scope='Conv2d_0c_1x3'),
408               slim.conv2d(branch_2, depth(384), [3, 1], scope='Conv2d_0d_3x1')])
409         with tf.variable_scope('Branch_3'):
410           branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
411           branch_3 = slim.conv2d(
412               branch_3, depth(192), [1, 1], scope='Conv2d_0b_1x1')
413         net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
414       end_points[end_point] = net
415       if end_point == final_endpoint: return net, end_points
416     raise ValueError('Unknown final endpoint %s' % final_endpoint)
417
418
419 def inception_v3(inputs,
420                  num_classes=1000,
421                  is_training=True,
422                  dropout_keep_prob=0.8,
423                  min_depth=16,
424                  depth_multiplier=1.0,
425                  prediction_fn=slim.softmax,
426                  spatial_squeeze=True,
427                  reuse=None,
428                  scope='InceptionV3'):
429   """Inception model from http://arxiv.org/abs/1512.00567.
430
431   "Rethinking the Inception Architecture for Computer Vision"
432
433   Christian Szegedy, Vincent Vanhoucke, Sergey Ioffe, Jonathon Shlens,
434   Zbigniew Wojna.
435
436   With the default arguments this method constructs the exact model defined in
437   the paper. However, one can experiment with variations of the inception_v3
438   network by changing arguments dropout_keep_prob, min_depth and
439   depth_multiplier.
440
441   The default image size used to train this network is 299x299.
442
443   Args:
444     inputs: a tensor of size [batch_size, height, width, channels].
445     num_classes: number of predicted classes.
446     is_training: whether is training or not.
447     dropout_keep_prob: the percentage of activation values that are retained.
448     min_depth: Minimum depth value (number of channels) for all convolution ops.
449       Enforced when depth_multiplier < 1, and not an active constraint when
450       depth_multiplier >= 1.
451     depth_multiplier: Float multiplier for the depth (number of channels)
452       for all convolution ops. The value must be greater than zero. Typical
453       usage will be to set this value in (0, 1) to reduce the number of
454       parameters or computation cost of the model.
455     prediction_fn: a function to get predictions out of logits.
456     spatial_squeeze: if True, logits is of shape [B, C], if false logits is
457         of shape [B, 1, 1, C], where B is batch_size and C is number of classes.
458     reuse: whether or not the network and its variables should be reused. To be
459       able to reuse 'scope' must be given.
460     scope: Optional variable_scope.
461
462   Returns:
463     logits: the pre-softmax activations, a tensor of size
464       [batch_size, num_classes]
465     end_points: a dictionary from components of the network to the corresponding
466       activation.
467
468   Raises:
469     ValueError: if 'depth_multiplier' is less than or equal to zero.
470   """
471   if depth_multiplier <= 0:
472     raise ValueError('depth_multiplier is not greater than zero.')
473   depth = lambda d: max(int(d * depth_multiplier), min_depth)
474
475   with tf.variable_scope(scope, 'InceptionV3', [inputs, num_classes],
476                          reuse=reuse) as scope:
477     with slim.arg_scope([slim.batch_norm, slim.dropout],
478                         is_training=is_training):
479       net, end_points = inception_v3_base(
480           inputs, scope=scope, min_depth=min_depth,
481           depth_multiplier=depth_multiplier)
482
483       # Auxiliary Head logits
484       with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
485                           stride=1, padding='SAME'):
486         aux_logits = end_points['Mixed_6e']
487         with tf.variable_scope('AuxLogits'):
488           aux_logits = slim.avg_pool2d(
489               aux_logits, [5, 5], stride=3, padding='VALID',
490               scope='AvgPool_1a_5x5')
491           aux_logits = slim.conv2d(aux_logits, depth(128), [1, 1],
492                                    scope='Conv2d_1b_1x1')
493
494           # Shape of feature map before the final layer.
495           kernel_size = _reduced_kernel_size_for_small_input(
496               aux_logits, [5, 5])
497           aux_logits = slim.conv2d(
498               aux_logits, depth(768), kernel_size,
499               weights_initializer=trunc_normal(0.01),
500               padding='VALID', scope='Conv2d_2a_{}x{}'.format(*kernel_size))
501           aux_logits = slim.conv2d(
502               aux_logits, num_classes, [1, 1], activation_fn=None,
503               normalizer_fn=None, weights_initializer=trunc_normal(0.001),
504               scope='Conv2d_2b_1x1')
505           if spatial_squeeze:
506             aux_logits = tf.squeeze(aux_logits, [1, 2], name='SpatialSqueeze')
507           end_points['AuxLogits'] = aux_logits
508
509       # Final pooling and prediction
510       with tf.variable_scope('Logits'):
511         kernel_size = _reduced_kernel_size_for_small_input(net, [8, 8])
512         net = slim.avg_pool2d(net, kernel_size, padding='VALID',
513                               scope='AvgPool_1a_{}x{}'.format(*kernel_size))
514         # 1 x 1 x 2048
515         net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')
516         end_points['PreLogits'] = net
517         # 2048
518         logits = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
519                              normalizer_fn=None, scope='Conv2d_1c_1x1')
520         if spatial_squeeze:
521           logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
522         # 1000
523       end_points['Logits'] = logits
524       end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
525   return logits, end_points
526 inception_v3.default_image_size = 299
527
528
529 def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
530   """Define kernel size which is automatically reduced for small input.
531
532   If the shape of the input images is unknown at graph construction time this
533   function assumes that the input images are is large enough.
534
535   Args:
536     input_tensor: input tensor of size [batch_size, height, width, channels].
537     kernel_size: desired kernel size of length 2: [kernel_height, kernel_width]
538
539   Returns:
540     a tensor with the kernel size.
541
542   TODO(jrru): Make this function work with unknown shapes. Theoretically, this
543   can be done with the code below. Problems are two-fold: (1) If the shape was
544   known, it will be lost. (2) inception.slim.ops._two_element_tuple cannot
545   handle tensors that define the kernel size.
546       shape = tf.shape(input_tensor)
547       return = tf.pack([tf.minimum(shape[1], kernel_size[0]),
548                         tf.minimum(shape[2], kernel_size[1])])
549
550   """
551   shape = input_tensor.get_shape().as_list()
552   if shape[1] is None or shape[2] is None:
553     kernel_size_out = kernel_size
554   else:
555     kernel_size_out = [min(shape[1], kernel_size[0]),
556                        min(shape[2], kernel_size[1])]
557   return kernel_size_out
558
559
560 inception_v3_arg_scope = inception_utils.inception_arg_scope