bifpn.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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 paddle import fluid
  17. from paddle.fluid.param_attr import ParamAttr
  18. from paddle.fluid.regularizer import L2Decay
  19. from paddle.fluid.initializer import Constant, Xavier
  20. from ppdet.core.workspace import register
  21. __all__ = ['BiFPN']
  22. class FusionConv(object):
  23. def __init__(self, num_chan):
  24. super(FusionConv, self).__init__()
  25. self.num_chan = num_chan
  26. def __call__(self, inputs, name=''):
  27. x = fluid.layers.swish(inputs)
  28. # depthwise
  29. x = fluid.layers.conv2d(
  30. x,
  31. self.num_chan,
  32. filter_size=3,
  33. padding='SAME',
  34. groups=self.num_chan,
  35. param_attr=ParamAttr(
  36. initializer=Xavier(), name=name + '_dw_w'),
  37. bias_attr=False)
  38. # pointwise
  39. x = fluid.layers.conv2d(
  40. x,
  41. self.num_chan,
  42. filter_size=1,
  43. param_attr=ParamAttr(
  44. initializer=Xavier(), name=name + '_pw_w'),
  45. bias_attr=ParamAttr(
  46. regularizer=L2Decay(0.), name=name + '_pw_b'))
  47. # bn + act
  48. x = fluid.layers.batch_norm(
  49. x,
  50. momentum=0.997,
  51. epsilon=1e-04,
  52. param_attr=ParamAttr(
  53. initializer=Constant(1.0),
  54. regularizer=L2Decay(0.),
  55. name=name + '_bn_w'),
  56. bias_attr=ParamAttr(
  57. regularizer=L2Decay(0.), name=name + '_bn_b'))
  58. return x
  59. class BiFPNCell(object):
  60. def __init__(self, num_chan, levels=5):
  61. super(BiFPNCell, self).__init__()
  62. self.levels = levels
  63. self.num_chan = num_chan
  64. num_trigates = levels - 2
  65. num_bigates = levels
  66. self.trigates = fluid.layers.create_parameter(
  67. shape=[num_trigates, 3],
  68. dtype='float32',
  69. default_initializer=fluid.initializer.Constant(1.))
  70. self.bigates = fluid.layers.create_parameter(
  71. shape=[num_bigates, 2],
  72. dtype='float32',
  73. default_initializer=fluid.initializer.Constant(1.))
  74. self.eps = 1e-4
  75. def __call__(self, inputs, cell_name=''):
  76. assert len(inputs) == self.levels
  77. def upsample(feat):
  78. return fluid.layers.resize_nearest(feat, scale=2.)
  79. def downsample(feat):
  80. return fluid.layers.pool2d(
  81. feat,
  82. pool_type='max',
  83. pool_size=3,
  84. pool_stride=2,
  85. pool_padding='SAME')
  86. fuse_conv = FusionConv(self.num_chan)
  87. # normalize weight
  88. trigates = fluid.layers.relu(self.trigates)
  89. bigates = fluid.layers.relu(self.bigates)
  90. trigates /= fluid.layers.reduce_sum(
  91. trigates, dim=1, keep_dim=True) + self.eps
  92. bigates /= fluid.layers.reduce_sum(
  93. bigates, dim=1, keep_dim=True) + self.eps
  94. feature_maps = list(inputs) # make a copy
  95. # top down path
  96. for l in range(self.levels - 1):
  97. p = self.levels - l - 2
  98. w1 = fluid.layers.slice(
  99. bigates, axes=[0, 1], starts=[l, 0], ends=[l + 1, 1])
  100. w2 = fluid.layers.slice(
  101. bigates, axes=[0, 1], starts=[l, 1], ends=[l + 1, 2])
  102. above = upsample(feature_maps[p + 1])
  103. feature_maps[p] = fuse_conv(
  104. w1 * above + w2 * inputs[p],
  105. name='{}_tb_{}'.format(cell_name, l))
  106. # bottom up path
  107. for l in range(1, self.levels):
  108. p = l
  109. name = '{}_bt_{}'.format(cell_name, l)
  110. below = downsample(feature_maps[p - 1])
  111. if p == self.levels - 1:
  112. # handle P7
  113. w1 = fluid.layers.slice(
  114. bigates, axes=[0, 1], starts=[p, 0], ends=[p + 1, 1])
  115. w2 = fluid.layers.slice(
  116. bigates, axes=[0, 1], starts=[p, 1], ends=[p + 1, 2])
  117. feature_maps[p] = fuse_conv(
  118. w1 * below + w2 * inputs[p], name=name)
  119. else:
  120. w1 = fluid.layers.slice(
  121. trigates, axes=[0, 1], starts=[p - 1, 0], ends=[p, 1])
  122. w2 = fluid.layers.slice(
  123. trigates, axes=[0, 1], starts=[p - 1, 1], ends=[p, 2])
  124. w3 = fluid.layers.slice(
  125. trigates, axes=[0, 1], starts=[p - 1, 2], ends=[p, 3])
  126. feature_maps[p] = fuse_conv(
  127. w1 * feature_maps[p] + w2 * below + w3 * inputs[p],
  128. name=name)
  129. return feature_maps
  130. @register
  131. class BiFPN(object):
  132. """
  133. Bidirectional Feature Pyramid Network, see https://arxiv.org/abs/1911.09070
  134. Args:
  135. num_chan (int): number of feature channels
  136. repeat (int): number of repeats of the BiFPN module
  137. level (int): number of FPN levels, default: 5
  138. """
  139. def __init__(self, num_chan, repeat=3, levels=5):
  140. super(BiFPN, self).__init__()
  141. self.num_chan = num_chan
  142. self.repeat = repeat
  143. self.levels = levels
  144. def __call__(self, inputs):
  145. feats = []
  146. # NOTE add two extra levels
  147. for idx in range(self.levels):
  148. if idx <= len(inputs):
  149. if idx == len(inputs):
  150. feat = inputs[-1]
  151. else:
  152. feat = inputs[idx]
  153. if feat.shape[1] != self.num_chan:
  154. feat = fluid.layers.conv2d(
  155. feat,
  156. self.num_chan,
  157. filter_size=1,
  158. padding='SAME',
  159. param_attr=ParamAttr(initializer=Xavier()),
  160. bias_attr=ParamAttr(regularizer=L2Decay(0.)))
  161. feat = fluid.layers.batch_norm(
  162. feat,
  163. momentum=0.997,
  164. epsilon=1e-04,
  165. param_attr=ParamAttr(
  166. initializer=Constant(1.0), regularizer=L2Decay(0.)),
  167. bias_attr=ParamAttr(regularizer=L2Decay(0.)))
  168. if idx >= len(inputs):
  169. feat = fluid.layers.pool2d(
  170. feat,
  171. pool_type='max',
  172. pool_size=3,
  173. pool_stride=2,
  174. pool_padding='SAME')
  175. feats.append(feat)
  176. biFPN = BiFPNCell(self.num_chan, self.levels)
  177. for r in range(self.repeat):
  178. feats = biFPN(feats, 'bifpn_{}'.format(r))
  179. return feats