shufflenet_v2.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. # copyright (c) 2020 PaddlePaddle 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. from __future__ import absolute_import
  15. from __future__ import division
  16. from __future__ import print_function
  17. import paddle.fluid as fluid
  18. from paddle.fluid.initializer import MSRA
  19. from paddle.fluid.param_attr import ParamAttr
  20. class ShuffleNetV2():
  21. def __init__(self, num_classes=None, scale=1.0):
  22. self.num_classes = num_classes
  23. self.scale = scale
  24. def __call__(self, input):
  25. scale = self.scale
  26. stage_repeats = [4, 8, 4]
  27. if scale == 0.25:
  28. stage_out_channels = [-1, 24, 24, 48, 96, 512]
  29. elif scale == 0.33:
  30. stage_out_channels = [-1, 24, 32, 64, 128, 512]
  31. elif scale == 0.5:
  32. stage_out_channels = [-1, 24, 48, 96, 192, 1024]
  33. elif scale == 1.0:
  34. stage_out_channels = [-1, 24, 116, 232, 464, 1024]
  35. elif scale == 1.5:
  36. stage_out_channels = [-1, 24, 176, 352, 704, 1024]
  37. elif scale == 2.0:
  38. stage_out_channels = [-1, 24, 224, 488, 976, 2048]
  39. else:
  40. raise NotImplementedError("This scale size:[" + str(scale) +
  41. "] is not implemented!")
  42. #conv1
  43. input_channel = stage_out_channels[1]
  44. conv1 = self.conv_bn_layer(
  45. input=input,
  46. filter_size=3,
  47. num_filters=input_channel,
  48. padding=1,
  49. stride=2,
  50. name='stage1_conv')
  51. pool1 = fluid.layers.pool2d(
  52. input=conv1,
  53. pool_size=3,
  54. pool_stride=2,
  55. pool_padding=1,
  56. pool_type='max')
  57. conv = pool1
  58. # bottleneck sequences
  59. for idxstage in range(len(stage_repeats)):
  60. numrepeat = stage_repeats[idxstage]
  61. output_channel = stage_out_channels[idxstage + 2]
  62. for i in range(numrepeat):
  63. if i == 0:
  64. conv = self.inverted_residual_unit(
  65. input=conv,
  66. num_filters=output_channel,
  67. stride=2,
  68. benchmodel=2,
  69. name=str(idxstage + 2) + '_' + str(i + 1))
  70. else:
  71. conv = self.inverted_residual_unit(
  72. input=conv,
  73. num_filters=output_channel,
  74. stride=1,
  75. benchmodel=1,
  76. name=str(idxstage + 2) + '_' + str(i + 1))
  77. output = self.conv_bn_layer(
  78. input=conv,
  79. filter_size=1,
  80. num_filters=stage_out_channels[-1],
  81. padding=0,
  82. stride=1,
  83. name='conv5')
  84. if self.num_classes is not None:
  85. output = fluid.layers.pool2d(
  86. input=output,
  87. pool_size=7,
  88. pool_stride=1,
  89. pool_padding=0,
  90. pool_type='avg')
  91. output = fluid.layers.fc(input=output,
  92. size=self.num_classes,
  93. param_attr=ParamAttr(
  94. initializer=MSRA(),
  95. name='fc6_weights'),
  96. bias_attr=ParamAttr(name='fc6_offset'))
  97. return output
  98. def conv_bn_layer(self,
  99. input,
  100. filter_size,
  101. num_filters,
  102. stride,
  103. padding,
  104. num_groups=1,
  105. use_cudnn=True,
  106. if_act=True,
  107. name=None):
  108. conv = fluid.layers.conv2d(
  109. input=input,
  110. num_filters=num_filters,
  111. filter_size=filter_size,
  112. stride=stride,
  113. padding=padding,
  114. groups=num_groups,
  115. act=None,
  116. use_cudnn=use_cudnn,
  117. param_attr=ParamAttr(
  118. 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)