shufflenet_v2.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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. 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(
  92. input=output,
  93. size=self.num_classes,
  94. param_attr=ParamAttr(initializer=MSRA(), name='fc6_weights'),
  95. bias_attr=ParamAttr(name='fc6_offset'))
  96. return output
  97. def conv_bn_layer(self,
  98. input,
  99. filter_size,
  100. num_filters,
  101. stride,
  102. padding,
  103. num_groups=1,
  104. use_cudnn=True,
  105. if_act=True,
  106. name=None):
  107. conv = fluid.layers.conv2d(
  108. input=input,
  109. num_filters=num_filters,
  110. filter_size=filter_size,
  111. stride=stride,
  112. padding=padding,
  113. groups=num_groups,
  114. act=None,
  115. use_cudnn=use_cudnn,
  116. param_attr=ParamAttr(initializer=MSRA(), name=name + '_weights'),
  117. bias_attr=False)
  118. out = int((input.shape[2] - 1) / float(stride) + 1)
  119. bn_name = name + '_bn'
  120. if if_act:
  121. return fluid.layers.batch_norm(
  122. input=conv,
  123. act='relu',
  124. param_attr=ParamAttr(name=bn_name + "_scale"),
  125. bias_attr=ParamAttr(name=bn_name + "_offset"),
  126. moving_mean_name=bn_name + '_mean',
  127. moving_variance_name=bn_name + '_variance')
  128. else:
  129. return fluid.layers.batch_norm(
  130. input=conv,
  131. param_attr=ParamAttr(name=bn_name + "_scale"),
  132. bias_attr=ParamAttr(name=bn_name + "_offset"),
  133. moving_mean_name=bn_name + '_mean',
  134. moving_variance_name=bn_name + '_variance')
  135. def channel_shuffle(self, x, groups):
  136. num_channels = x.shape[1]
  137. channels_per_group = num_channels // groups
  138. x_shape = fluid.layers.shape(x)
  139. # reshape
  140. x = fluid.layers.reshape(
  141. x=x,
  142. shape=[
  143. x_shape[0], groups, channels_per_group, x_shape[2], x_shape[3]
  144. ])
  145. x = fluid.layers.transpose(x=x, perm=[0, 2, 1, 3, 4])
  146. # flatten
  147. x = fluid.layers.reshape(
  148. x=x, shape=[x_shape[0], num_channels, x_shape[2], x_shape[3]])
  149. return x
  150. def inverted_residual_unit(self,
  151. input,
  152. num_filters,
  153. stride,
  154. benchmodel,
  155. name=None):
  156. assert stride in [1, 2], \
  157. "supported stride are {} but your stride is {}".format([1,2], stride)
  158. oup_inc = num_filters // 2
  159. inp = input.shape[1]
  160. if benchmodel == 1:
  161. x1, x2 = fluid.layers.split(
  162. input,
  163. num_or_sections=[input.shape[1] // 2, input.shape[1] // 2],
  164. dim=1)
  165. conv_pw = self.conv_bn_layer(
  166. input=x2,
  167. num_filters=oup_inc,
  168. filter_size=1,
  169. stride=1,
  170. padding=0,
  171. num_groups=1,
  172. if_act=True,
  173. name='stage_' + name + '_conv1')
  174. conv_dw = self.conv_bn_layer(
  175. input=conv_pw,
  176. num_filters=oup_inc,
  177. filter_size=3,
  178. stride=stride,
  179. padding=1,
  180. num_groups=oup_inc,
  181. if_act=False,
  182. use_cudnn=False,
  183. name='stage_' + name + '_conv2')
  184. conv_linear = self.conv_bn_layer(
  185. input=conv_dw,
  186. num_filters=oup_inc,
  187. filter_size=1,
  188. stride=1,
  189. padding=0,
  190. num_groups=1,
  191. if_act=True,
  192. name='stage_' + name + '_conv3')
  193. out = fluid.layers.concat([x1, conv_linear], axis=1)
  194. else:
  195. #branch1
  196. conv_dw_1 = self.conv_bn_layer(
  197. input=input,
  198. num_filters=inp,
  199. filter_size=3,
  200. stride=stride,
  201. padding=1,
  202. num_groups=inp,
  203. if_act=False,
  204. use_cudnn=False,
  205. name='stage_' + name + '_conv4')
  206. conv_linear_1 = self.conv_bn_layer(
  207. input=conv_dw_1,
  208. num_filters=oup_inc,
  209. filter_size=1,
  210. stride=1,
  211. padding=0,
  212. num_groups=1,
  213. if_act=True,
  214. name='stage_' + name + '_conv5')
  215. #branch2
  216. conv_pw_2 = self.conv_bn_layer(
  217. input=input,
  218. num_filters=oup_inc,
  219. filter_size=1,
  220. stride=1,
  221. padding=0,
  222. num_groups=1,
  223. if_act=True,
  224. name='stage_' + name + '_conv1')
  225. conv_dw_2 = self.conv_bn_layer(
  226. input=conv_pw_2,
  227. num_filters=oup_inc,
  228. filter_size=3,
  229. stride=stride,
  230. padding=1,
  231. num_groups=oup_inc,
  232. if_act=False,
  233. use_cudnn=False,
  234. name='stage_' + name + '_conv2')
  235. conv_linear_2 = self.conv_bn_layer(
  236. input=conv_dw_2,
  237. num_filters=oup_inc,
  238. filter_size=1,
  239. stride=1,
  240. padding=0,
  241. num_groups=1,
  242. if_act=True,
  243. name='stage_' + name + '_conv3')
  244. out = fluid.layers.concat([conv_linear_1, conv_linear_2], axis=1)
  245. return self.channel_shuffle(out, 2)