vgg.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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 ppdet.core.workspace import register
  20. __all__ = ['VGG']
  21. @register
  22. class VGG(object):
  23. """
  24. VGG, see https://arxiv.org/abs/1409.1556
  25. Args:
  26. depth (int): the VGG net depth (16 or 19)
  27. normalizations (list): params list of init scale in l2 norm, skip init
  28. scale if param is -1.
  29. with_extra_blocks (bool): whether or not extra blocks should be added
  30. extra_block_filters (list): in each extra block, params:
  31. [in_channel, out_channel, padding_size, stride_size, filter_size]
  32. """
  33. def __init__(self,
  34. depth=16,
  35. with_extra_blocks=False,
  36. normalizations=[20., -1, -1, -1, -1, -1],
  37. extra_block_filters=[[256, 512, 1, 2, 3], [128, 256, 1, 2, 3],
  38. [128, 256, 0, 1, 3],
  39. [128, 256, 0, 1, 3]]):
  40. assert depth in [16, 19], \
  41. "depth {} not in [16, 19]"
  42. self.depth = depth
  43. self.depth_cfg = {16: [2, 2, 3, 3, 3], 19: [2, 2, 4, 4, 4]}
  44. self.with_extra_blocks = with_extra_blocks
  45. self.normalizations = normalizations
  46. self.extra_block_filters = extra_block_filters
  47. def __call__(self, input):
  48. layers = []
  49. layers += self._vgg_block(input)
  50. if not self.with_extra_blocks:
  51. return layers[-1]
  52. layers += self._add_extras_block(layers[-1])
  53. norm_cfg = self.normalizations
  54. for k, v in enumerate(layers):
  55. if not norm_cfg[k] == -1:
  56. layers[k] = self._l2_norm_scale(v, init_scale=norm_cfg[k])
  57. return layers
  58. def _vgg_block(self, input):
  59. nums = self.depth_cfg[self.depth]
  60. vgg_base = [64, 128, 256, 512, 512]
  61. conv = input
  62. layers = []
  63. for k, v in enumerate(vgg_base):
  64. conv = self._conv_block(
  65. conv, v, nums[k], name="conv{}_".format(k + 1))
  66. layers.append(conv)
  67. if k == 4:
  68. conv = self._pooling_block(conv, 3, 1, pool_padding=1)
  69. else:
  70. conv = self._pooling_block(conv, 2, 2)
  71. fc6 = self._conv_layer(conv, 1024, 3, 1, 6, dilation=6, name="fc6")
  72. fc7 = self._conv_layer(fc6, 1024, 1, 1, 0, name="fc7")
  73. return [layers[3], fc7]
  74. def _add_extras_block(self, input):
  75. cfg = self.extra_block_filters
  76. conv = input
  77. layers = []
  78. for k, v in enumerate(cfg):
  79. assert len(v) == 5, "extra_block_filters size not fix"
  80. conv = self._extra_block(
  81. conv,
  82. v[0],
  83. v[1],
  84. v[2],
  85. v[3],
  86. v[4],
  87. name="conv{}_".format(6 + k))
  88. layers.append(conv)
  89. return layers
  90. def _conv_block(self, input, num_filter, groups, name=None):
  91. conv = input
  92. for i in range(groups):
  93. conv = self._conv_layer(
  94. input=conv,
  95. num_filters=num_filter,
  96. filter_size=3,
  97. stride=1,
  98. padding=1,
  99. act='relu',
  100. name=name + str(i + 1))
  101. return conv
  102. def _extra_block(self,
  103. input,
  104. num_filters1,
  105. num_filters2,
  106. padding_size,
  107. stride_size,
  108. filter_size,
  109. name=None):
  110. # 1x1 conv
  111. conv_1 = self._conv_layer(
  112. input=input,
  113. num_filters=int(num_filters1),
  114. filter_size=1,
  115. stride=1,
  116. act='relu',
  117. padding=0,
  118. name=name + "1")
  119. # 3x3 conv
  120. conv_2 = self._conv_layer(
  121. input=conv_1,
  122. num_filters=int(num_filters2),
  123. filter_size=filter_size,
  124. stride=stride_size,
  125. act='relu',
  126. padding=padding_size,
  127. name=name + "2")
  128. return conv_2
  129. def _conv_layer(self,
  130. input,
  131. num_filters,
  132. filter_size,
  133. stride,
  134. padding,
  135. dilation=1,
  136. act='relu',
  137. use_cudnn=True,
  138. name=None):
  139. conv = fluid.layers.conv2d(
  140. input=input,
  141. num_filters=num_filters,
  142. filter_size=filter_size,
  143. stride=stride,
  144. padding=padding,
  145. dilation=dilation,
  146. act=act,
  147. use_cudnn=use_cudnn,
  148. param_attr=ParamAttr(name=name + "_weights"),
  149. bias_attr=ParamAttr(name=name + "_biases"),
  150. name=name + '.conv2d.output.1')
  151. return conv
  152. def _pooling_block(self,
  153. conv,
  154. pool_size,
  155. pool_stride,
  156. pool_padding=0,
  157. ceil_mode=True):
  158. pool = fluid.layers.pool2d(
  159. input=conv,
  160. pool_size=pool_size,
  161. pool_type='max',
  162. pool_stride=pool_stride,
  163. pool_padding=pool_padding,
  164. ceil_mode=ceil_mode)
  165. return pool
  166. def _l2_norm_scale(self, input, init_scale=1.0, channel_shared=False):
  167. from paddle.fluid.layer_helper import LayerHelper
  168. from paddle.fluid.initializer import Constant
  169. helper = LayerHelper("Scale")
  170. l2_norm = fluid.layers.l2_normalize(
  171. input, axis=1) # l2 norm along channel
  172. shape = [1] if channel_shared else [input.shape[1]]
  173. scale = helper.create_parameter(
  174. attr=helper.param_attr,
  175. shape=shape,
  176. dtype=input.dtype,
  177. default_initializer=Constant(init_scale))
  178. out = fluid.layers.elementwise_mul(
  179. x=l2_norm,
  180. y=scale,
  181. axis=-1 if channel_shared else 1,
  182. name="conv4_3_norm_scale")
  183. return out