hrfpn.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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. import paddle
  15. import paddle.nn.functional as F
  16. from paddle import ParamAttr
  17. import paddle.nn as nn
  18. from paddle.regularizer import L2Decay
  19. from paddlex.ppdet.core.workspace import register, serializable
  20. from ..shape_spec import ShapeSpec
  21. __all__ = ['HRFPN']
  22. @register
  23. class HRFPN(nn.Layer):
  24. """
  25. Args:
  26. in_channels (list): number of input feature channels from backbone
  27. out_channel (int): number of output feature channels
  28. share_conv (bool): whether to share conv for different layers' reduction
  29. extra_stage (int): add extra stage for returning HRFPN fpn_feats
  30. spatial_scales (list): feature map scaling factor
  31. """
  32. def __init__(self,
  33. in_channels=[18, 36, 72, 144],
  34. out_channel=256,
  35. share_conv=False,
  36. extra_stage=1,
  37. spatial_scales=[1. / 4, 1. / 8, 1. / 16, 1. / 32]):
  38. super(HRFPN, self).__init__()
  39. in_channel = sum(in_channels)
  40. self.in_channel = in_channel
  41. self.out_channel = out_channel
  42. self.share_conv = share_conv
  43. for i in range(extra_stage):
  44. spatial_scales = spatial_scales + [spatial_scales[-1] / 2.]
  45. self.spatial_scales = spatial_scales
  46. self.num_out = len(self.spatial_scales)
  47. self.reduction = nn.Conv2D(
  48. in_channels=in_channel,
  49. out_channels=out_channel,
  50. kernel_size=1,
  51. weight_attr=ParamAttr(name='hrfpn_reduction_weights'),
  52. bias_attr=False)
  53. if share_conv:
  54. self.fpn_conv = nn.Conv2D(
  55. in_channels=out_channel,
  56. out_channels=out_channel,
  57. kernel_size=3,
  58. padding=1,
  59. weight_attr=ParamAttr(name='fpn_conv_weights'),
  60. bias_attr=False)
  61. else:
  62. self.fpn_conv = []
  63. for i in range(self.num_out):
  64. conv_name = "fpn_conv_" + str(i)
  65. conv = self.add_sublayer(
  66. conv_name,
  67. nn.Conv2D(
  68. in_channels=out_channel,
  69. out_channels=out_channel,
  70. kernel_size=3,
  71. padding=1,
  72. weight_attr=ParamAttr(name=conv_name + "_weights"),
  73. bias_attr=False))
  74. self.fpn_conv.append(conv)
  75. def forward(self, body_feats):
  76. num_backbone_stages = len(body_feats)
  77. outs = []
  78. outs.append(body_feats[0])
  79. # resize
  80. for i in range(1, num_backbone_stages):
  81. resized = F.interpolate(
  82. body_feats[i], scale_factor=2**i, mode='bilinear')
  83. outs.append(resized)
  84. # concat
  85. out = paddle.concat(outs, axis=1)
  86. assert out.shape[
  87. 1] == self.in_channel, 'in_channel should be {}, be received {}'.format(
  88. out.shape[1], self.in_channel)
  89. # reduction
  90. out = self.reduction(out)
  91. # conv
  92. outs = [out]
  93. for i in range(1, self.num_out):
  94. outs.append(F.avg_pool2d(out, kernel_size=2**i, stride=2**i))
  95. outputs = []
  96. for i in range(self.num_out):
  97. conv_func = self.fpn_conv if self.share_conv else self.fpn_conv[i]
  98. conv = conv_func(outs[i])
  99. outputs.append(conv)
  100. fpn_feats = [outputs[k] for k in range(self.num_out)]
  101. return fpn_feats
  102. @classmethod
  103. def from_config(cls, cfg, input_shape):
  104. return {
  105. 'in_channels': [i.channels for i in input_shape],
  106. 'spatial_scales': [1.0 / i.stride for i in input_shape],
  107. }
  108. @property
  109. def out_shape(self):
  110. return [
  111. ShapeSpec(
  112. channels=self.out_channel, stride=1. / s)
  113. for s in self.spatial_scales
  114. ]