mobilenet_v1.py 8.1 KB

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