shufflenet_v2.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
  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. from __future__ import absolute_import
  15. from __future__ import division
  16. from __future__ import print_function
  17. from collections import OrderedDict
  18. import paddle.fluid as fluid
  19. from paddle.fluid.initializer import MSRA
  20. from paddle.fluid.param_attr import ParamAttr
  21. class ShuffleNetV2():
  22. def __init__(self, num_classes=None, scale=1.0):
  23. self.num_classes = num_classes
  24. self.scale = scale
  25. def __call__(self, input):
  26. scale = self.scale
  27. stage_repeats = [4, 8, 4]
  28. if scale == 0.25:
  29. stage_out_channels = [-1, 24, 24, 48, 96, 512]
  30. elif scale == 0.33:
  31. stage_out_channels = [-1, 24, 32, 64, 128, 512]
  32. elif scale == 0.5:
  33. stage_out_channels = [-1, 24, 48, 96, 192, 1024]
  34. elif scale == 1.0:
  35. stage_out_channels = [-1, 24, 116, 232, 464, 1024]
  36. elif scale == 1.5:
  37. stage_out_channels = [-1, 24, 176, 352, 704, 1024]
  38. elif scale == 2.0:
  39. stage_out_channels = [-1, 24, 224, 488, 976, 2048]
  40. else:
  41. raise NotImplementedError("This scale size:[" + str(scale) +
  42. "] is not implemented!")
  43. #conv1
  44. input_channel = stage_out_channels[1]
  45. conv1 = self.conv_bn_layer(
  46. input=input,
  47. filter_size=3,
  48. num_filters=input_channel,
  49. padding=1,
  50. stride=2,
  51. name='stage1_conv')
  52. pool1 = fluid.layers.pool2d(
  53. input=conv1,
  54. pool_size=3,
  55. pool_stride=2,
  56. pool_padding=1,
  57. pool_type='max')
  58. conv = pool1
  59. # bottleneck sequences
  60. for idxstage in range(len(stage_repeats)):
  61. numrepeat = stage_repeats[idxstage]
  62. output_channel = stage_out_channels[idxstage + 2]
  63. for i in range(numrepeat):
  64. if i == 0:
  65. conv = self.inverted_residual_unit(
  66. input=conv,
  67. num_filters=output_channel,
  68. stride=2,
  69. benchmodel=2,
  70. name=str(idxstage + 2) + '_' + str(i + 1))
  71. else:
  72. conv = self.inverted_residual_unit(
  73. input=conv,
  74. num_filters=output_channel,
  75. stride=1,
  76. benchmodel=1,
  77. name=str(idxstage + 2) + '_' + str(i + 1))
  78. output = self.conv_bn_layer(
  79. input=conv,
  80. filter_size=1,
  81. num_filters=stage_out_channels[-1],
  82. padding=0,
  83. stride=1,
  84. name='conv5')
  85. if self.num_classes is not None:
  86. output = fluid.layers.pool2d(
  87. input=output,
  88. pool_size=7,
  89. pool_stride=1,
  90. pool_padding=0,
  91. pool_type='avg')
  92. output = fluid.layers.fc(
  93. input=output,
  94. size=self.num_classes,
  95. param_attr=ParamAttr(initializer=MSRA(), name='fc6_weights'),
  96. bias_attr=ParamAttr(name='fc6_offset'))
  97. return OrderedDict([('logits', output)])
  98. return output
  99. def conv_bn_layer(self,
  100. input,
  101. filter_size,
  102. num_filters,
  103. stride,
  104. padding,
  105. num_groups=1,
  106. use_cudnn=True,
  107. if_act=True,
  108. name=None):
  109. conv = fluid.layers.conv2d(
  110. input=input,
  111. num_filters=num_filters,
  112. filter_size=filter_size,
  113. stride=stride,
  114. padding=padding,
  115. groups=num_groups,
  116. act=None,
  117. use_cudnn=use_cudnn,
  118. param_attr=ParamAttr(initializer=MSRA(), name=name + '_weights'),
  119. bias_attr=False)
  120. out = int((input.shape[2] - 1) / float(stride) + 1)
  121. bn_name = name + '_bn'
  122. if if_act:
  123. return fluid.layers.batch_norm(
  124. input=conv,
  125. act='relu',
  126. param_attr=ParamAttr(name=bn_name + "_scale"),
  127. bias_attr=ParamAttr(name=bn_name + "_offset"),
  128. moving_mean_name=bn_name + '_mean',
  129. moving_variance_name=bn_name + '_variance')
  130. else:
  131. return fluid.layers.batch_norm(
  132. input=conv,
  133. param_attr=ParamAttr(name=bn_name + "_scale"),
  134. bias_attr=ParamAttr(name=bn_name + "_offset"),
  135. moving_mean_name=bn_name + '_mean',
  136. moving_variance_name=bn_name + '_variance')
  137. def channel_shuffle(self, x, groups):
  138. num_channels = x.shape[1]
  139. channels_per_group = num_channels // groups
  140. x_shape = fluid.layers.shape(x)
  141. # reshape
  142. x = fluid.layers.reshape(
  143. x=x,
  144. shape=[
  145. x_shape[0], groups, channels_per_group, x_shape[2], x_shape[3]
  146. ])
  147. x = fluid.layers.transpose(x=x, perm=[0, 2, 1, 3, 4])
  148. # flatten
  149. x = fluid.layers.reshape(
  150. x=x, shape=[x_shape[0], num_channels, x_shape[2], x_shape[3]])
  151. return x
  152. def inverted_residual_unit(self,
  153. input,
  154. num_filters,
  155. stride,
  156. benchmodel,
  157. name=None):
  158. assert stride in [1, 2], \
  159. "supported stride are {} but your stride is {}".format([1,2], stride)
  160. oup_inc = num_filters // 2
  161. inp = input.shape[1]
  162. if benchmodel == 1:
  163. x1, x2 = fluid.layers.split(
  164. input,
  165. num_or_sections=[input.shape[1] // 2, input.shape[1] // 2],
  166. dim=1)
  167. conv_pw = self.conv_bn_layer(
  168. input=x2,
  169. num_filters=oup_inc,
  170. filter_size=1,
  171. stride=1,
  172. padding=0,
  173. num_groups=1,
  174. if_act=True,
  175. name='stage_' + name + '_conv1')
  176. conv_dw = self.conv_bn_layer(
  177. input=conv_pw,
  178. num_filters=oup_inc,
  179. filter_size=3,
  180. stride=stride,
  181. padding=1,
  182. num_groups=oup_inc,
  183. if_act=False,
  184. use_cudnn=False,
  185. name='stage_' + name + '_conv2')
  186. conv_linear = self.conv_bn_layer(
  187. input=conv_dw,
  188. num_filters=oup_inc,
  189. filter_size=1,
  190. stride=1,
  191. padding=0,
  192. num_groups=1,
  193. if_act=True,
  194. name='stage_' + name + '_conv3')
  195. out = fluid.layers.concat([x1, conv_linear], axis=1)
  196. else:
  197. #branch1
  198. conv_dw_1 = self.conv_bn_layer(
  199. input=input,
  200. num_filters=inp,
  201. filter_size=3,
  202. stride=stride,
  203. padding=1,
  204. num_groups=inp,
  205. if_act=False,
  206. use_cudnn=False,
  207. name='stage_' + name + '_conv4')
  208. conv_linear_1 = self.conv_bn_layer(
  209. input=conv_dw_1,
  210. num_filters=oup_inc,
  211. filter_size=1,
  212. stride=1,
  213. padding=0,
  214. num_groups=1,
  215. if_act=True,
  216. name='stage_' + name + '_conv5')
  217. #branch2
  218. conv_pw_2 = self.conv_bn_layer(
  219. input=input,
  220. num_filters=oup_inc,
  221. filter_size=1,
  222. stride=1,
  223. padding=0,
  224. num_groups=1,
  225. if_act=True,
  226. name='stage_' + name + '_conv1')
  227. conv_dw_2 = self.conv_bn_layer(
  228. input=conv_pw_2,
  229. num_filters=oup_inc,
  230. filter_size=3,
  231. stride=stride,
  232. padding=1,
  233. num_groups=oup_inc,
  234. if_act=False,
  235. use_cudnn=False,
  236. name='stage_' + name + '_conv2')
  237. conv_linear_2 = self.conv_bn_layer(
  238. input=conv_dw_2,
  239. num_filters=oup_inc,
  240. filter_size=1,
  241. stride=1,
  242. padding=0,
  243. num_groups=1,
  244. if_act=True,
  245. name='stage_' + name + '_conv3')
  246. out = fluid.layers.concat([conv_linear_1, conv_linear_2], axis=1)
  247. return self.channel_shuffle(out, 2)