hrfpn.py 4.3 KB

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