lc_pan.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. # Copyright (c) 2022 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 as nn
  16. import paddle.nn.functional as F
  17. from paddle import ParamAttr
  18. from paddle.regularizer import L2Decay
  19. from ppdet.core.workspace import register, serializable
  20. from ..shape_spec import ShapeSpec
  21. from ..backbones.lcnet import DepthwiseSeparable
  22. from .csp_pan import ConvBNLayer, Channel_T, DPModule
  23. __all__ = ['LCPAN']
  24. @register
  25. @serializable
  26. class LCPAN(nn.Layer):
  27. """Path Aggregation Network with LCNet module.
  28. Args:
  29. in_channels (List[int]): Number of input channels per scale.
  30. out_channels (int): Number of output channels (used at each scale)
  31. kernel_size (int): The conv2d kernel size of this Module.
  32. num_features (int): Number of output features of CSPPAN module.
  33. num_csp_blocks (int): Number of bottlenecks in CSPLayer. Default: 1
  34. use_depthwise (bool): Whether to depthwise separable convolution in
  35. blocks. Default: True
  36. """
  37. def __init__(self,
  38. in_channels,
  39. out_channels,
  40. kernel_size=5,
  41. num_features=3,
  42. use_depthwise=True,
  43. act='hard_swish',
  44. spatial_scales=[0.125, 0.0625, 0.03125]):
  45. super(LCPAN, self).__init__()
  46. self.conv_t = Channel_T(in_channels, out_channels, act=act)
  47. in_channels = [out_channels] * len(spatial_scales)
  48. self.in_channels = in_channels
  49. self.out_channels = out_channels
  50. self.spatial_scales = spatial_scales
  51. self.num_features = num_features
  52. conv_func = DPModule if use_depthwise else ConvBNLayer
  53. NET_CONFIG = {
  54. #k, in_c, out_c, stride, use_se
  55. "block1": [
  56. [kernel_size, out_channels * 2, out_channels * 2, 1, False],
  57. [kernel_size, out_channels * 2, out_channels, 1, False],
  58. ],
  59. "block2": [
  60. [kernel_size, out_channels * 2, out_channels * 2, 1, False],
  61. [kernel_size, out_channels * 2, out_channels, 1, False],
  62. ]
  63. }
  64. if self.num_features == 4:
  65. self.first_top_conv = conv_func(
  66. in_channels[0], in_channels[0], kernel_size, stride=2, act=act)
  67. self.second_top_conv = conv_func(
  68. in_channels[0], in_channels[0], kernel_size, stride=2, act=act)
  69. self.spatial_scales.append(self.spatial_scales[-1] / 2)
  70. # build top-down blocks
  71. self.upsample = nn.Upsample(scale_factor=2, mode='nearest')
  72. self.top_down_blocks = nn.LayerList()
  73. for idx in range(len(in_channels) - 1, 0, -1):
  74. self.top_down_blocks.append(
  75. nn.Sequential(* [
  76. DepthwiseSeparable(
  77. num_channels=in_c,
  78. num_filters=out_c,
  79. dw_size=k,
  80. stride=s,
  81. use_se=se)
  82. for i, (k, in_c, out_c, s, se) in enumerate(NET_CONFIG[
  83. "block1"])
  84. ]))
  85. # build bottom-up blocks
  86. self.downsamples = nn.LayerList()
  87. self.bottom_up_blocks = nn.LayerList()
  88. for idx in range(len(in_channels) - 1):
  89. self.downsamples.append(
  90. conv_func(
  91. in_channels[idx],
  92. in_channels[idx],
  93. kernel_size=kernel_size,
  94. stride=2,
  95. act=act))
  96. self.bottom_up_blocks.append(
  97. nn.Sequential(* [
  98. DepthwiseSeparable(
  99. num_channels=in_c,
  100. num_filters=out_c,
  101. dw_size=k,
  102. stride=s,
  103. use_se=se)
  104. for i, (k, in_c, out_c, s, se) in enumerate(NET_CONFIG[
  105. "block2"])
  106. ]))
  107. def forward(self, inputs):
  108. """
  109. Args:
  110. inputs (tuple[Tensor]): input features.
  111. Returns:
  112. tuple[Tensor]: CSPPAN features.
  113. """
  114. assert len(inputs) == len(self.in_channels)
  115. inputs = self.conv_t(inputs)
  116. # top-down path
  117. inner_outs = [inputs[-1]]
  118. for idx in range(len(self.in_channels) - 1, 0, -1):
  119. feat_heigh = inner_outs[0]
  120. feat_low = inputs[idx - 1]
  121. upsample_feat = self.upsample(feat_heigh)
  122. inner_out = self.top_down_blocks[len(self.in_channels) - 1 - idx](
  123. paddle.concat([upsample_feat, feat_low], 1))
  124. inner_outs.insert(0, inner_out)
  125. # bottom-up path
  126. outs = [inner_outs[0]]
  127. for idx in range(len(self.in_channels) - 1):
  128. feat_low = outs[-1]
  129. feat_height = inner_outs[idx + 1]
  130. downsample_feat = self.downsamples[idx](feat_low)
  131. out = self.bottom_up_blocks[idx](paddle.concat(
  132. [downsample_feat, feat_height], 1))
  133. outs.append(out)
  134. top_features = None
  135. if self.num_features == 4:
  136. top_features = self.first_top_conv(inputs[-1])
  137. top_features = top_features + self.second_top_conv(outs[-1])
  138. outs.append(top_features)
  139. return tuple(outs)
  140. @property
  141. def out_shape(self):
  142. return [
  143. ShapeSpec(
  144. channels=self.out_channels, stride=1. / s)
  145. for s in self.spatial_scales
  146. ]
  147. @classmethod
  148. def from_config(cls, cfg, input_shape):
  149. return {'in_channels': [i.channels for i in input_shape], }