inception_v2.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  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 v2 classification network."""
  16. from __future__ import absolute_import
  17. from __future__ import division
  18. from __future__ import print_function
  19. import tensorflow as tf
  20. from nets import inception_utils
  21. slim = tf.contrib.slim
  22. trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)
  23. def inception_v2_base(inputs,
  24. final_endpoint='Mixed_5c',
  25. min_depth=16,
  26. depth_multiplier=1.0,
  27. scope=None):
  28. """Inception v2 (6a2).
  29. Constructs an Inception v2 network from inputs to the given final endpoint.
  30. This method can construct the network up to the layer inception(5b) as
  31. described in http://arxiv.org/abs/1502.03167.
  32. Args:
  33. inputs: a tensor of shape [batch_size, height, width, channels].
  34. final_endpoint: specifies the endpoint to construct the network up to. It
  35. can be one of ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1',
  36. 'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b', 'Mixed_3c', 'Mixed_4a',
  37. 'Mixed_4b', 'Mixed_4c', 'Mixed_4d', 'Mixed_4e', 'Mixed_5a', 'Mixed_5b',
  38. 'Mixed_5c'].
  39. min_depth: Minimum depth value (number of channels) for all convolution ops.
  40. Enforced when depth_multiplier < 1, and not an active constraint when
  41. depth_multiplier >= 1.
  42. depth_multiplier: Float multiplier for the depth (number of channels)
  43. for all convolution ops. The value must be greater than zero. Typical
  44. usage will be to set this value in (0, 1) to reduce the number of
  45. parameters or computation cost of the model.
  46. scope: Optional variable_scope.
  47. Returns:
  48. tensor_out: output tensor corresponding to the final_endpoint.
  49. end_points: a set of activations for external use, for example summaries or
  50. losses.
  51. Raises:
  52. ValueError: if final_endpoint is not set to one of the predefined values,
  53. or depth_multiplier <= 0
  54. """
  55. # end_points will collect relevant activations for external use, for example
  56. # summaries or losses.
  57. end_points = {}
  58. # Used to find thinned depths for each layer.
  59. if depth_multiplier <= 0:
  60. raise ValueError('depth_multiplier is not greater than zero.')
  61. depth = lambda d: max(int(d * depth_multiplier), min_depth)
  62. with tf.variable_scope(scope, 'InceptionV2', [inputs]):
  63. with slim.arg_scope(
  64. [slim.conv2d, slim.max_pool2d, slim.avg_pool2d, slim.separable_conv2d],
  65. stride=1, padding='SAME'):
  66. # Note that sizes in the comments below assume an input spatial size of
  67. # 224x224, however, the inputs can be of any size greater 32x32.
  68. # 224 x 224 x 3
  69. end_point = 'Conv2d_1a_7x7'
  70. # depthwise_multiplier here is different from depth_multiplier.
  71. # depthwise_multiplier determines the output channels of the initial
  72. # depthwise conv (see docs for tf.nn.separable_conv2d), while
  73. # depth_multiplier controls the # channels of the subsequent 1x1
  74. # convolution. Must have
  75. # in_channels * depthwise_multipler <= out_channels
  76. # so that the separable convolution is not overparameterized.
  77. depthwise_multiplier = min(int(depth(64) / 3), 8)
  78. net = slim.separable_conv2d(
  79. inputs, depth(64), [7, 7], depth_multiplier=depthwise_multiplier,
  80. stride=2, weights_initializer=trunc_normal(1.0),
  81. scope=end_point)
  82. end_points[end_point] = net
  83. if end_point == final_endpoint: return net, end_points
  84. # 112 x 112 x 64
  85. end_point = 'MaxPool_2a_3x3'
  86. net = slim.max_pool2d(net, [3, 3], scope=end_point, stride=2)
  87. end_points[end_point] = net
  88. if end_point == final_endpoint: return net, end_points
  89. # 56 x 56 x 64
  90. end_point = 'Conv2d_2b_1x1'
  91. net = slim.conv2d(net, depth(64), [1, 1], scope=end_point,
  92. weights_initializer=trunc_normal(0.1))
  93. end_points[end_point] = net
  94. if end_point == final_endpoint: return net, end_points
  95. # 56 x 56 x 64
  96. end_point = 'Conv2d_2c_3x3'
  97. net = slim.conv2d(net, depth(192), [3, 3], scope=end_point)
  98. end_points[end_point] = net
  99. if end_point == final_endpoint: return net, end_points
  100. # 56 x 56 x 192
  101. end_point = 'MaxPool_3a_3x3'
  102. net = slim.max_pool2d(net, [3, 3], scope=end_point, stride=2)
  103. end_points[end_point] = net
  104. if end_point == final_endpoint: return net, end_points
  105. # 28 x 28 x 192
  106. # Inception module.
  107. end_point = 'Mixed_3b'
  108. with tf.variable_scope(end_point):
  109. with tf.variable_scope('Branch_0'):
  110. branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
  111. with tf.variable_scope('Branch_1'):
  112. branch_1 = slim.conv2d(
  113. net, depth(64), [1, 1],
  114. weights_initializer=trunc_normal(0.09),
  115. scope='Conv2d_0a_1x1')
  116. branch_1 = slim.conv2d(branch_1, depth(64), [3, 3],
  117. scope='Conv2d_0b_3x3')
  118. with tf.variable_scope('Branch_2'):
  119. branch_2 = slim.conv2d(
  120. net, depth(64), [1, 1],
  121. weights_initializer=trunc_normal(0.09),
  122. scope='Conv2d_0a_1x1')
  123. branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
  124. scope='Conv2d_0b_3x3')
  125. branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
  126. scope='Conv2d_0c_3x3')
  127. with tf.variable_scope('Branch_3'):
  128. branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
  129. branch_3 = slim.conv2d(
  130. branch_3, depth(32), [1, 1],
  131. weights_initializer=trunc_normal(0.1),
  132. scope='Conv2d_0b_1x1')
  133. net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
  134. end_points[end_point] = net
  135. if end_point == final_endpoint: return net, end_points
  136. # 28 x 28 x 256
  137. end_point = 'Mixed_3c'
  138. with tf.variable_scope(end_point):
  139. with tf.variable_scope('Branch_0'):
  140. branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
  141. with tf.variable_scope('Branch_1'):
  142. branch_1 = slim.conv2d(
  143. net, depth(64), [1, 1],
  144. weights_initializer=trunc_normal(0.09),
  145. scope='Conv2d_0a_1x1')
  146. branch_1 = slim.conv2d(branch_1, depth(96), [3, 3],
  147. scope='Conv2d_0b_3x3')
  148. with tf.variable_scope('Branch_2'):
  149. branch_2 = slim.conv2d(
  150. net, depth(64), [1, 1],
  151. weights_initializer=trunc_normal(0.09),
  152. 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(
  160. branch_3, depth(64), [1, 1],
  161. weights_initializer=trunc_normal(0.1),
  162. scope='Conv2d_0b_1x1')
  163. net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
  164. end_points[end_point] = net
  165. if end_point == final_endpoint: return net, end_points
  166. # 28 x 28 x 320
  167. end_point = 'Mixed_4a'
  168. with tf.variable_scope(end_point):
  169. with tf.variable_scope('Branch_0'):
  170. branch_0 = slim.conv2d(
  171. net, depth(128), [1, 1],
  172. weights_initializer=trunc_normal(0.09),
  173. scope='Conv2d_0a_1x1')
  174. branch_0 = slim.conv2d(branch_0, depth(160), [3, 3], stride=2,
  175. scope='Conv2d_1a_3x3')
  176. with tf.variable_scope('Branch_1'):
  177. branch_1 = slim.conv2d(
  178. net, depth(64), [1, 1],
  179. weights_initializer=trunc_normal(0.09),
  180. scope='Conv2d_0a_1x1')
  181. branch_1 = slim.conv2d(
  182. branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3')
  183. branch_1 = slim.conv2d(
  184. branch_1, depth(96), [3, 3], stride=2, scope='Conv2d_1a_3x3')
  185. with tf.variable_scope('Branch_2'):
  186. branch_2 = slim.max_pool2d(
  187. net, [3, 3], stride=2, scope='MaxPool_1a_3x3')
  188. net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
  189. end_points[end_point] = net
  190. if end_point == final_endpoint: return net, end_points
  191. # 14 x 14 x 576
  192. end_point = 'Mixed_4b'
  193. with tf.variable_scope(end_point):
  194. with tf.variable_scope('Branch_0'):
  195. branch_0 = slim.conv2d(net, depth(224), [1, 1], scope='Conv2d_0a_1x1')
  196. with tf.variable_scope('Branch_1'):
  197. branch_1 = slim.conv2d(
  198. net, depth(64), [1, 1],
  199. weights_initializer=trunc_normal(0.09),
  200. scope='Conv2d_0a_1x1')
  201. branch_1 = slim.conv2d(
  202. branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3')
  203. with tf.variable_scope('Branch_2'):
  204. branch_2 = slim.conv2d(
  205. net, depth(96), [1, 1],
  206. weights_initializer=trunc_normal(0.09),
  207. scope='Conv2d_0a_1x1')
  208. branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
  209. scope='Conv2d_0b_3x3')
  210. branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
  211. scope='Conv2d_0c_3x3')
  212. with tf.variable_scope('Branch_3'):
  213. branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
  214. branch_3 = slim.conv2d(
  215. branch_3, depth(128), [1, 1],
  216. weights_initializer=trunc_normal(0.1),
  217. scope='Conv2d_0b_1x1')
  218. net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
  219. end_points[end_point] = net
  220. if end_point == final_endpoint: return net, end_points
  221. # 14 x 14 x 576
  222. end_point = 'Mixed_4c'
  223. with tf.variable_scope(end_point):
  224. with tf.variable_scope('Branch_0'):
  225. branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
  226. with tf.variable_scope('Branch_1'):
  227. branch_1 = slim.conv2d(
  228. net, depth(96), [1, 1],
  229. weights_initializer=trunc_normal(0.09),
  230. scope='Conv2d_0a_1x1')
  231. branch_1 = slim.conv2d(branch_1, depth(128), [3, 3],
  232. scope='Conv2d_0b_3x3')
  233. with tf.variable_scope('Branch_2'):
  234. branch_2 = slim.conv2d(
  235. net, depth(96), [1, 1],
  236. weights_initializer=trunc_normal(0.09),
  237. scope='Conv2d_0a_1x1')
  238. branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
  239. scope='Conv2d_0b_3x3')
  240. branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
  241. scope='Conv2d_0c_3x3')
  242. with tf.variable_scope('Branch_3'):
  243. branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
  244. branch_3 = slim.conv2d(
  245. branch_3, depth(128), [1, 1],
  246. weights_initializer=trunc_normal(0.1),
  247. scope='Conv2d_0b_1x1')
  248. net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
  249. end_points[end_point] = net
  250. if end_point == final_endpoint: return net, end_points
  251. # 14 x 14 x 576
  252. end_point = 'Mixed_4d'
  253. with tf.variable_scope(end_point):
  254. with tf.variable_scope('Branch_0'):
  255. branch_0 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
  256. with tf.variable_scope('Branch_1'):
  257. branch_1 = slim.conv2d(
  258. net, depth(128), [1, 1],
  259. weights_initializer=trunc_normal(0.09),
  260. scope='Conv2d_0a_1x1')
  261. branch_1 = slim.conv2d(branch_1, depth(160), [3, 3],
  262. scope='Conv2d_0b_3x3')
  263. with tf.variable_scope('Branch_2'):
  264. branch_2 = slim.conv2d(
  265. net, depth(128), [1, 1],
  266. weights_initializer=trunc_normal(0.09),
  267. scope='Conv2d_0a_1x1')
  268. branch_2 = slim.conv2d(branch_2, depth(160), [3, 3],
  269. scope='Conv2d_0b_3x3')
  270. branch_2 = slim.conv2d(branch_2, depth(160), [3, 3],
  271. scope='Conv2d_0c_3x3')
  272. with tf.variable_scope('Branch_3'):
  273. branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
  274. branch_3 = slim.conv2d(
  275. branch_3, depth(96), [1, 1],
  276. weights_initializer=trunc_normal(0.1),
  277. scope='Conv2d_0b_1x1')
  278. net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
  279. end_points[end_point] = net
  280. if end_point == final_endpoint: return net, end_points
  281. # 14 x 14 x 576
  282. end_point = 'Mixed_4e'
  283. with tf.variable_scope(end_point):
  284. with tf.variable_scope('Branch_0'):
  285. branch_0 = slim.conv2d(net, depth(96), [1, 1], scope='Conv2d_0a_1x1')
  286. with tf.variable_scope('Branch_1'):
  287. branch_1 = slim.conv2d(
  288. net, depth(128), [1, 1],
  289. weights_initializer=trunc_normal(0.09),
  290. scope='Conv2d_0a_1x1')
  291. branch_1 = slim.conv2d(branch_1, depth(192), [3, 3],
  292. scope='Conv2d_0b_3x3')
  293. with tf.variable_scope('Branch_2'):
  294. branch_2 = slim.conv2d(
  295. net, depth(160), [1, 1],
  296. weights_initializer=trunc_normal(0.09),
  297. scope='Conv2d_0a_1x1')
  298. branch_2 = slim.conv2d(branch_2, depth(192), [3, 3],
  299. scope='Conv2d_0b_3x3')
  300. branch_2 = slim.conv2d(branch_2, depth(192), [3, 3],
  301. scope='Conv2d_0c_3x3')
  302. with tf.variable_scope('Branch_3'):
  303. branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
  304. branch_3 = slim.conv2d(
  305. branch_3, depth(96), [1, 1],
  306. weights_initializer=trunc_normal(0.1),
  307. scope='Conv2d_0b_1x1')
  308. net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
  309. end_points[end_point] = net
  310. if end_point == final_endpoint: return net, end_points
  311. # 14 x 14 x 576
  312. end_point = 'Mixed_5a'
  313. with tf.variable_scope(end_point):
  314. with tf.variable_scope('Branch_0'):
  315. branch_0 = slim.conv2d(
  316. net, depth(128), [1, 1],
  317. weights_initializer=trunc_normal(0.09),
  318. scope='Conv2d_0a_1x1')
  319. branch_0 = slim.conv2d(branch_0, depth(192), [3, 3], stride=2,
  320. scope='Conv2d_1a_3x3')
  321. with tf.variable_scope('Branch_1'):
  322. branch_1 = slim.conv2d(
  323. net, depth(192), [1, 1],
  324. weights_initializer=trunc_normal(0.09),
  325. scope='Conv2d_0a_1x1')
  326. branch_1 = slim.conv2d(branch_1, depth(256), [3, 3],
  327. scope='Conv2d_0b_3x3')
  328. branch_1 = slim.conv2d(branch_1, depth(256), [3, 3], stride=2,
  329. scope='Conv2d_1a_3x3')
  330. with tf.variable_scope('Branch_2'):
  331. branch_2 = slim.max_pool2d(net, [3, 3], stride=2,
  332. scope='MaxPool_1a_3x3')
  333. net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
  334. end_points[end_point] = net
  335. if end_point == final_endpoint: return net, end_points
  336. # 7 x 7 x 1024
  337. end_point = 'Mixed_5b'
  338. with tf.variable_scope(end_point):
  339. with tf.variable_scope('Branch_0'):
  340. branch_0 = slim.conv2d(net, depth(352), [1, 1], scope='Conv2d_0a_1x1')
  341. with tf.variable_scope('Branch_1'):
  342. branch_1 = slim.conv2d(
  343. net, depth(192), [1, 1],
  344. weights_initializer=trunc_normal(0.09),
  345. scope='Conv2d_0a_1x1')
  346. branch_1 = slim.conv2d(branch_1, depth(320), [3, 3],
  347. scope='Conv2d_0b_3x3')
  348. with tf.variable_scope('Branch_2'):
  349. branch_2 = slim.conv2d(
  350. net, depth(160), [1, 1],
  351. weights_initializer=trunc_normal(0.09),
  352. scope='Conv2d_0a_1x1')
  353. branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
  354. scope='Conv2d_0b_3x3')
  355. branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
  356. scope='Conv2d_0c_3x3')
  357. with tf.variable_scope('Branch_3'):
  358. branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
  359. branch_3 = slim.conv2d(
  360. branch_3, depth(128), [1, 1],
  361. weights_initializer=trunc_normal(0.1),
  362. scope='Conv2d_0b_1x1')
  363. net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
  364. end_points[end_point] = net
  365. if end_point == final_endpoint: return net, end_points
  366. # 7 x 7 x 1024
  367. end_point = 'Mixed_5c'
  368. with tf.variable_scope(end_point):
  369. with tf.variable_scope('Branch_0'):
  370. branch_0 = slim.conv2d(net, depth(352), [1, 1], scope='Conv2d_0a_1x1')
  371. with tf.variable_scope('Branch_1'):
  372. branch_1 = slim.conv2d(
  373. net, depth(192), [1, 1],
  374. weights_initializer=trunc_normal(0.09),
  375. scope='Conv2d_0a_1x1')
  376. branch_1 = slim.conv2d(branch_1, depth(320), [3, 3],
  377. scope='Conv2d_0b_3x3')
  378. with tf.variable_scope('Branch_2'):
  379. branch_2 = slim.conv2d(
  380. net, depth(192), [1, 1],
  381. weights_initializer=trunc_normal(0.09),
  382. scope='Conv2d_0a_1x1')
  383. branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
  384. scope='Conv2d_0b_3x3')
  385. branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
  386. scope='Conv2d_0c_3x3')
  387. with tf.variable_scope('Branch_3'):
  388. branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
  389. branch_3 = slim.conv2d(
  390. branch_3, depth(128), [1, 1],
  391. weights_initializer=trunc_normal(0.1),
  392. scope='Conv2d_0b_1x1')
  393. net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
  394. end_points[end_point] = net
  395. if end_point == final_endpoint: return net, end_points
  396. raise ValueError('Unknown final endpoint %s' % final_endpoint)
  397. def inception_v2(inputs,
  398. num_classes=1000,
  399. is_training=True,
  400. dropout_keep_prob=0.8,
  401. min_depth=16,
  402. depth_multiplier=1.0,
  403. prediction_fn=slim.softmax,
  404. spatial_squeeze=True,
  405. reuse=None,
  406. scope='InceptionV2'):
  407. """Inception v2 model for classification.
  408. Constructs an Inception v2 network for classification as described in
  409. http://arxiv.org/abs/1502.03167.
  410. The default image size used to train this network is 224x224.
  411. Args:
  412. inputs: a tensor of shape [batch_size, height, width, channels].
  413. num_classes: number of predicted classes.
  414. is_training: whether is training or not.
  415. dropout_keep_prob: the percentage of activation values that are retained.
  416. min_depth: Minimum depth value (number of channels) for all convolution ops.
  417. Enforced when depth_multiplier < 1, and not an active constraint when
  418. depth_multiplier >= 1.
  419. depth_multiplier: Float multiplier for the depth (number of channels)
  420. for all convolution ops. The value must be greater than zero. Typical
  421. usage will be to set this value in (0, 1) to reduce the number of
  422. parameters or computation cost of the model.
  423. prediction_fn: a function to get predictions out of logits.
  424. spatial_squeeze: if True, logits is of shape is [B, C], if false logits is
  425. of shape [B, 1, 1, C], where B is batch_size and C is number of classes.
  426. reuse: whether or not the network and its variables should be reused. To be
  427. able to reuse 'scope' must be given.
  428. scope: Optional variable_scope.
  429. Returns:
  430. logits: the pre-softmax activations, a tensor of size
  431. [batch_size, num_classes]
  432. end_points: a dictionary from components of the network to the corresponding
  433. activation.
  434. Raises:
  435. ValueError: if final_endpoint is not set to one of the predefined values,
  436. or depth_multiplier <= 0
  437. """
  438. if depth_multiplier <= 0:
  439. raise ValueError('depth_multiplier is not greater than zero.')
  440. # Final pooling and prediction
  441. with tf.variable_scope(scope, 'InceptionV2', [inputs, num_classes],
  442. reuse=reuse) as scope:
  443. with slim.arg_scope([slim.batch_norm, slim.dropout],
  444. is_training=is_training):
  445. net, end_points = inception_v2_base(
  446. inputs, scope=scope, min_depth=min_depth,
  447. depth_multiplier=depth_multiplier)
  448. with tf.variable_scope('Logits'):
  449. kernel_size = _reduced_kernel_size_for_small_input(net, [7, 7])
  450. net = slim.avg_pool2d(net, kernel_size, padding='VALID',
  451. scope='AvgPool_1a_{}x{}'.format(*kernel_size))
  452. # 1 x 1 x 1024
  453. net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')
  454. logits = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
  455. normalizer_fn=None, scope='Conv2d_1c_1x1')
  456. if spatial_squeeze:
  457. logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
  458. end_points['Logits'] = logits
  459. end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
  460. return logits, end_points
  461. inception_v2.default_image_size = 224
  462. def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
  463. """Define kernel size which is automatically reduced for small input.
  464. If the shape of the input images is unknown at graph construction time this
  465. function assumes that the input images are is large enough.
  466. Args:
  467. input_tensor: input tensor of size [batch_size, height, width, channels].
  468. kernel_size: desired kernel size of length 2: [kernel_height, kernel_width]
  469. Returns:
  470. a tensor with the kernel size.
  471. TODO(jrru): Make this function work with unknown shapes. Theoretically, this
  472. can be done with the code below. Problems are two-fold: (1) If the shape was
  473. known, it will be lost. (2) inception.slim.ops._two_element_tuple cannot
  474. handle tensors that define the kernel size.
  475. shape = tf.shape(input_tensor)
  476. return = tf.pack([tf.minimum(shape[1], kernel_size[0]),
  477. tf.minimum(shape[2], kernel_size[1])])
  478. """
  479. shape = input_tensor.get_shape().as_list()
  480. if shape[1] is None or shape[2] is None:
  481. kernel_size_out = kernel_size
  482. else:
  483. kernel_size_out = [min(shape[1], kernel_size[0]),
  484. min(shape[2], kernel_size[1])]
  485. return kernel_size_out
  486. inception_v2_arg_scope = inception_utils.inception_arg_scope