mobilenet.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # Copyright (c) 2019 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. from paddle import fluid
  18. from paddle.fluid.param_attr import ParamAttr
  19. from paddle.fluid.regularizer import L2Decay
  20. from ppdet.experimental import mixed_precision_global_state
  21. from ppdet.core.workspace import register
  22. __all__ = ['MobileNet']
  23. @register
  24. class MobileNet(object):
  25. """
  26. MobileNet v1, see https://arxiv.org/abs/1704.04861
  27. Args:
  28. norm_type (str): normalization type, 'bn' and 'sync_bn' are supported
  29. norm_decay (float): weight decay for normalization layer weights
  30. conv_decay (float): weight decay for convolution layer weights.
  31. conv_group_scale (int): scaling factor for convolution groups
  32. with_extra_blocks (bool): if extra blocks should be added
  33. extra_block_filters (list): number of filter for each extra block
  34. """
  35. __shared__ = ['norm_type', 'weight_prefix_name']
  36. def __init__(self,
  37. norm_type='bn',
  38. norm_decay=0.,
  39. conv_decay=0.,
  40. conv_group_scale=1,
  41. conv_learning_rate=1.0,
  42. with_extra_blocks=False,
  43. extra_block_filters=[[256, 512], [128, 256], [128, 256],
  44. [64, 128]],
  45. weight_prefix_name=''):
  46. self.norm_type = norm_type
  47. self.norm_decay = norm_decay
  48. self.conv_decay = conv_decay
  49. self.conv_group_scale = conv_group_scale
  50. self.conv_learning_rate = conv_learning_rate
  51. self.with_extra_blocks = with_extra_blocks
  52. self.extra_block_filters = extra_block_filters
  53. self.prefix_name = weight_prefix_name
  54. def _conv_norm(self,
  55. input,
  56. filter_size,
  57. num_filters,
  58. stride,
  59. padding,
  60. num_groups=1,
  61. act='relu',
  62. use_cudnn=True,
  63. name=None):
  64. parameter_attr = ParamAttr(
  65. learning_rate=self.conv_learning_rate,
  66. initializer=fluid.initializer.MSRA(),
  67. regularizer=L2Decay(self.conv_decay),
  68. name=name + "_weights")
  69. conv = fluid.layers.conv2d(
  70. input=input,
  71. num_filters=num_filters,
  72. filter_size=filter_size,
  73. stride=stride,
  74. padding=padding,
  75. groups=num_groups,
  76. act=None,
  77. use_cudnn=use_cudnn,
  78. param_attr=parameter_attr,
  79. bias_attr=False)
  80. bn_name = name + "_bn"
  81. norm_decay = self.norm_decay
  82. bn_param_attr = ParamAttr(
  83. regularizer=L2Decay(norm_decay), name=bn_name + '_scale')
  84. bn_bias_attr = ParamAttr(
  85. regularizer=L2Decay(norm_decay), name=bn_name + '_offset')
  86. return fluid.layers.batch_norm(
  87. input=conv,
  88. act=act,
  89. param_attr=bn_param_attr,
  90. bias_attr=bn_bias_attr,
  91. moving_mean_name=bn_name + '_mean',
  92. moving_variance_name=bn_name + '_variance')
  93. def depthwise_separable(self,
  94. input,
  95. num_filters1,
  96. num_filters2,
  97. num_groups,
  98. stride,
  99. scale,
  100. name=None):
  101. mixed_precision_enabled = mixed_precision_global_state() is not None
  102. depthwise_conv = self._conv_norm(
  103. input=input,
  104. filter_size=3,
  105. num_filters=int(num_filters1 * scale),
  106. stride=stride,
  107. padding=1,
  108. num_groups=int(num_groups * scale),
  109. use_cudnn=mixed_precision_enabled,
  110. name=name + "_dw")
  111. pointwise_conv = self._conv_norm(
  112. input=depthwise_conv,
  113. filter_size=1,
  114. num_filters=int(num_filters2 * scale),
  115. stride=1,
  116. padding=0,
  117. name=name + "_sep")
  118. return pointwise_conv
  119. def _extra_block(self,
  120. input,
  121. num_filters1,
  122. num_filters2,
  123. num_groups,
  124. stride,
  125. name=None):
  126. pointwise_conv = self._conv_norm(
  127. input=input,
  128. filter_size=1,
  129. num_filters=int(num_filters1),
  130. stride=1,
  131. num_groups=int(num_groups),
  132. padding=0,
  133. act='relu6',
  134. name=name + "_extra1")
  135. normal_conv = self._conv_norm(
  136. input=pointwise_conv,
  137. filter_size=3,
  138. num_filters=int(num_filters2),
  139. stride=2,
  140. num_groups=int(num_groups),
  141. padding=1,
  142. act='relu6',
  143. name=name + "_extra2")
  144. return normal_conv
  145. def __call__(self, input):
  146. scale = self.conv_group_scale
  147. blocks = []
  148. # input 1/1
  149. out = self._conv_norm(
  150. input, 3, int(32 * scale), 2, 1, name=self.prefix_name + "conv1")
  151. # 1/2
  152. out = self.depthwise_separable(
  153. out, 32, 64, 32, 1, scale, name=self.prefix_name + "conv2_1")
  154. out = self.depthwise_separable(
  155. out, 64, 128, 64, 2, scale, name=self.prefix_name + "conv2_2")
  156. # 1/4
  157. out = self.depthwise_separable(
  158. out, 128, 128, 128, 1, scale, name=self.prefix_name + "conv3_1")
  159. out = self.depthwise_separable(
  160. out, 128, 256, 128, 2, scale, name=self.prefix_name + "conv3_2")
  161. # 1/8
  162. blocks.append(out)
  163. out = self.depthwise_separable(
  164. out, 256, 256, 256, 1, scale, name=self.prefix_name + "conv4_1")
  165. out = self.depthwise_separable(
  166. out, 256, 512, 256, 2, scale, name=self.prefix_name + "conv4_2")
  167. # 1/16
  168. blocks.append(out)
  169. for i in range(5):
  170. out = self.depthwise_separable(
  171. out,
  172. 512,
  173. 512,
  174. 512,
  175. 1,
  176. scale,
  177. name=self.prefix_name + "conv5_" + str(i + 1))
  178. module11 = out
  179. out = self.depthwise_separable(
  180. out, 512, 1024, 512, 2, scale, name=self.prefix_name + "conv5_6")
  181. # 1/32
  182. out = self.depthwise_separable(
  183. out, 1024, 1024, 1024, 1, scale, name=self.prefix_name + "conv6")
  184. module13 = out
  185. blocks.append(out)
  186. if not self.with_extra_blocks:
  187. return blocks
  188. num_filters = self.extra_block_filters
  189. module14 = self._extra_block(module13, num_filters[0][0],
  190. num_filters[0][1], 1, 2,
  191. self.prefix_name + "conv7_1")
  192. module15 = self._extra_block(module14, num_filters[1][0],
  193. num_filters[1][1], 1, 2,
  194. self.prefix_name + "conv7_2")
  195. module16 = self._extra_block(module15, num_filters[2][0],
  196. num_filters[2][1], 1, 2,
  197. self.prefix_name + "conv7_3")
  198. module17 = self._extra_block(module16, num_filters[3][0],
  199. num_filters[3][1], 1, 2,
  200. self.prefix_name + "conv7_4")
  201. return module11, module13, module14, module15, module16, module17