pan.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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 paddle
  16. import paddle.nn as nn
  17. import paddle.nn.functional as F
  18. from paddle import ParamAttr
  19. from paddle.nn.initializer import XavierUniform
  20. from paddle.regularizer import L2Decay
  21. from paddlex.ppdet.core.workspace import register, serializable
  22. from paddlex.ppdet.modeling.layers import ConvNormLayer
  23. from ..shape_spec import ShapeSpec
  24. __all__ = ['PAN']
  25. @register
  26. @serializable
  27. class PAN(nn.Layer):
  28. """
  29. Path Aggregation Network, see https://arxiv.org/abs/1803.01534
  30. Args:
  31. in_channels (list[int]): input channels of each level which can be
  32. derived from the output shape of backbone by from_config
  33. out_channel (list[int]): output channel of each level
  34. spatial_scales (list[float]): the spatial scales between input feature
  35. maps and original input image which can be derived from the output
  36. shape of backbone by from_config
  37. has_extra_convs (bool): whether to add extra conv to the last level.
  38. default False
  39. extra_stage (int): the number of extra stages added to the last level.
  40. default 1
  41. use_c5 (bool): Whether to use c5 as the input of extra stage,
  42. otherwise p5 is used. default True
  43. norm_type (string|None): The normalization type in FPN module. If
  44. norm_type is None, norm will not be used after conv and if
  45. norm_type is string, bn, gn, sync_bn are available. default None
  46. norm_decay (float): weight decay for normalization layer weights.
  47. default 0.
  48. freeze_norm (bool): whether to freeze normalization layer.
  49. default False
  50. relu_before_extra_convs (bool): whether to add relu before extra convs.
  51. default False
  52. """
  53. def __init__(self,
  54. in_channels,
  55. out_channel,
  56. spatial_scales=[0.125, 0.0625, 0.03125],
  57. start_level=0,
  58. end_level=-1,
  59. norm_type=None):
  60. super(PAN, self).__init__()
  61. self.out_channel = out_channel
  62. self.num_ins = len(in_channels)
  63. self.spatial_scales = spatial_scales
  64. if end_level == -1:
  65. self.end_level = self.num_ins
  66. else:
  67. # if end_level < inputs, no extra level is allowed
  68. self.end_level = end_level
  69. assert end_level <= len(in_channels)
  70. self.start_level = start_level
  71. self.norm_type = norm_type
  72. self.lateral_convs = []
  73. for i in range(self.start_level, self.end_level):
  74. in_c = in_channels[i - self.start_level]
  75. if self.norm_type is not None:
  76. lateral = self.add_sublayer(
  77. 'pan_lateral' + str(i),
  78. ConvNormLayer(
  79. ch_in=in_c,
  80. ch_out=self.out_channel,
  81. filter_size=1,
  82. stride=1,
  83. norm_type=self.norm_type,
  84. norm_decay=self.norm_decay,
  85. freeze_norm=self.freeze_norm,
  86. initializer=XavierUniform(fan_out=in_c)))
  87. else:
  88. lateral = self.add_sublayer(
  89. 'pan_lateral' + str(i),
  90. nn.Conv2D(
  91. in_channels=in_c,
  92. out_channels=self.out_channel,
  93. kernel_size=1,
  94. weight_attr=ParamAttr(
  95. initializer=XavierUniform(fan_out=in_c))))
  96. self.lateral_convs.append(lateral)
  97. @classmethod
  98. def from_config(cls, cfg, input_shape):
  99. return {'in_channels': [i.channels for i in input_shape], }
  100. def forward(self, body_feats):
  101. laterals = []
  102. for i, lateral_conv in enumerate(self.lateral_convs):
  103. laterals.append(lateral_conv(body_feats[i + self.start_level]))
  104. num_levels = len(laterals)
  105. for i in range(1, num_levels):
  106. lvl = num_levels - i
  107. upsample = F.interpolate(
  108. laterals[lvl],
  109. scale_factor=2.,
  110. mode='bilinear', )
  111. laterals[lvl - 1] += upsample
  112. outs = [laterals[i] for i in range(num_levels)]
  113. for i in range(0, num_levels - 1):
  114. outs[i + 1] += F.interpolate(
  115. outs[i], scale_factor=0.5, mode='bilinear')
  116. return outs
  117. @property
  118. def out_shape(self):
  119. return [
  120. ShapeSpec(
  121. channels=self.out_channel, stride=1. / s)
  122. for s in self.spatial_scales
  123. ]