centernet_fpn.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. # Copyright (c) 2021 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. import numpy as np
  15. import math
  16. import paddle
  17. import paddle.nn as nn
  18. from paddle.nn.initializer import KaimingUniform
  19. from paddlex.ppdet.core.workspace import register, serializable
  20. from paddlex.ppdet.modeling.layers import ConvNormLayer
  21. from ..shape_spec import ShapeSpec
  22. def fill_up_weights(up):
  23. weight = up.weight
  24. f = math.ceil(weight.shape[2] / 2)
  25. c = (2 * f - 1 - f % 2) / (2. * f)
  26. for i in range(weight.shape[2]):
  27. for j in range(weight.shape[3]):
  28. weight[0, 0, i, j] = \
  29. (1 - math.fabs(i / f - c)) * (1 - math.fabs(j / f - c))
  30. for c in range(1, weight.shape[0]):
  31. weight[c, 0, :, :] = weight[0, 0, :, :]
  32. class IDAUp(nn.Layer):
  33. def __init__(self, ch_ins, ch_out, up_strides, dcn_v2=True):
  34. super(IDAUp, self).__init__()
  35. for i in range(1, len(ch_ins)):
  36. ch_in = ch_ins[i]
  37. up_s = int(up_strides[i])
  38. proj = nn.Sequential(
  39. ConvNormLayer(
  40. ch_in,
  41. ch_out,
  42. filter_size=3,
  43. stride=1,
  44. use_dcn=dcn_v2,
  45. bias_on=dcn_v2,
  46. norm_decay=None,
  47. dcn_lr_scale=1.,
  48. dcn_regularizer=None),
  49. nn.ReLU())
  50. node = nn.Sequential(
  51. ConvNormLayer(
  52. ch_out,
  53. ch_out,
  54. filter_size=3,
  55. stride=1,
  56. use_dcn=dcn_v2,
  57. bias_on=dcn_v2,
  58. norm_decay=None,
  59. dcn_lr_scale=1.,
  60. dcn_regularizer=None),
  61. nn.ReLU())
  62. param_attr = paddle.ParamAttr(initializer=KaimingUniform())
  63. up = nn.Conv2DTranspose(
  64. ch_out,
  65. ch_out,
  66. kernel_size=up_s * 2,
  67. weight_attr=param_attr,
  68. stride=up_s,
  69. padding=up_s // 2,
  70. groups=ch_out,
  71. bias_attr=False)
  72. # TODO: uncomment fill_up_weights
  73. #fill_up_weights(up)
  74. setattr(self, 'proj_' + str(i), proj)
  75. setattr(self, 'up_' + str(i), up)
  76. setattr(self, 'node_' + str(i), node)
  77. def forward(self, inputs, start_level, end_level):
  78. for i in range(start_level + 1, end_level):
  79. upsample = getattr(self, 'up_' + str(i - start_level))
  80. project = getattr(self, 'proj_' + str(i - start_level))
  81. inputs[i] = project(inputs[i])
  82. inputs[i] = upsample(inputs[i])
  83. node = getattr(self, 'node_' + str(i - start_level))
  84. inputs[i] = node(paddle.add(inputs[i], inputs[i - 1]))
  85. class DLAUp(nn.Layer):
  86. def __init__(self, start_level, channels, scales, ch_in=None, dcn_v2=True):
  87. super(DLAUp, self).__init__()
  88. self.start_level = start_level
  89. if ch_in is None:
  90. ch_in = channels
  91. self.channels = channels
  92. channels = list(channels)
  93. scales = np.array(scales, dtype=int)
  94. for i in range(len(channels) - 1):
  95. j = -i - 2
  96. setattr(
  97. self,
  98. 'ida_{}'.format(i),
  99. IDAUp(
  100. ch_in[j:],
  101. channels[j],
  102. scales[j:] // scales[j],
  103. dcn_v2=dcn_v2))
  104. scales[j + 1:] = scales[j]
  105. ch_in[j + 1:] = [channels[j] for _ in channels[j + 1:]]
  106. def forward(self, inputs):
  107. out = [inputs[-1]] # start with 32
  108. for i in range(len(inputs) - self.start_level - 1):
  109. ida = getattr(self, 'ida_{}'.format(i))
  110. ida(inputs, len(inputs) - i - 2, len(inputs))
  111. out.insert(0, inputs[-1])
  112. return out
  113. @register
  114. @serializable
  115. class CenterNetDLAFPN(nn.Layer):
  116. """
  117. Args:
  118. in_channels (list): number of input feature channels from backbone.
  119. [16, 32, 64, 128, 256, 512] by default, means the channels of DLA-34
  120. down_ratio (int): the down ratio from images to heatmap, 4 by default
  121. last_level (int): the last level of input feature fed into the upsamplng block
  122. out_channel (int): the channel of the output feature, 0 by default means
  123. the channel of the input feature whose down ratio is `down_ratio`
  124. dcn_v2 (bool): whether use the DCNv2, true by default
  125. """
  126. def __init__(self,
  127. in_channels,
  128. down_ratio=4,
  129. last_level=5,
  130. out_channel=0,
  131. dcn_v2=True):
  132. super(CenterNetDLAFPN, self).__init__()
  133. self.first_level = int(np.log2(down_ratio))
  134. self.down_ratio = down_ratio
  135. self.last_level = last_level
  136. scales = [2**i for i in range(len(in_channels[self.first_level:]))]
  137. self.dla_up = DLAUp(
  138. self.first_level,
  139. in_channels[self.first_level:],
  140. scales,
  141. dcn_v2=dcn_v2)
  142. self.out_channel = out_channel
  143. if out_channel == 0:
  144. self.out_channel = in_channels[self.first_level]
  145. self.ida_up = IDAUp(
  146. in_channels[self.first_level:self.last_level],
  147. self.out_channel,
  148. [2**i for i in range(self.last_level - self.first_level)],
  149. dcn_v2=dcn_v2)
  150. @classmethod
  151. def from_config(cls, cfg, input_shape):
  152. return {'in_channels': [i.channels for i in input_shape]}
  153. def forward(self, body_feats):
  154. dla_up_feats = self.dla_up(body_feats)
  155. ida_up_feats = []
  156. for i in range(self.last_level - self.first_level):
  157. ida_up_feats.append(dla_up_feats[i].clone())
  158. self.ida_up(ida_up_feats, 0, len(ida_up_feats))
  159. return ida_up_feats[-1]
  160. @property
  161. def out_shape(self):
  162. return [ShapeSpec(channels=self.out_channel, stride=self.down_ratio)]