ttf_fpn.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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 as nn
  16. import paddle.nn.functional as F
  17. from paddle import ParamAttr
  18. from paddle.nn.initializer import Constant, Uniform, Normal, XavierUniform
  19. from ppdet.core.workspace import register, serializable
  20. from paddle.regularizer import L2Decay
  21. from ppdet.modeling.layers import DeformableConvV2, ConvNormLayer, LiteConv
  22. import math
  23. from ppdet.modeling.ops import batch_norm
  24. from ..shape_spec import ShapeSpec
  25. __all__ = ['TTFFPN']
  26. class Upsample(nn.Layer):
  27. def __init__(self, ch_in, ch_out, norm_type='bn'):
  28. super(Upsample, self).__init__()
  29. fan_in = ch_in * 3 * 3
  30. stdv = 1. / math.sqrt(fan_in)
  31. self.dcn = DeformableConvV2(
  32. ch_in,
  33. ch_out,
  34. kernel_size=3,
  35. weight_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
  36. bias_attr=ParamAttr(
  37. initializer=Constant(0),
  38. regularizer=L2Decay(0.),
  39. learning_rate=2.),
  40. lr_scale=2.,
  41. regularizer=L2Decay(0.))
  42. self.bn = batch_norm(
  43. ch_out, norm_type=norm_type, initializer=Constant(1.))
  44. def forward(self, feat):
  45. dcn = self.dcn(feat)
  46. bn = self.bn(dcn)
  47. relu = F.relu(bn)
  48. out = F.interpolate(relu, scale_factor=2., mode='bilinear')
  49. return out
  50. class DeConv(nn.Layer):
  51. def __init__(self, ch_in, ch_out, norm_type='bn'):
  52. super(DeConv, self).__init__()
  53. self.deconv = nn.Sequential()
  54. conv1 = ConvNormLayer(
  55. ch_in=ch_in,
  56. ch_out=ch_out,
  57. stride=1,
  58. filter_size=1,
  59. norm_type=norm_type,
  60. initializer=XavierUniform())
  61. conv2 = nn.Conv2DTranspose(
  62. in_channels=ch_out,
  63. out_channels=ch_out,
  64. kernel_size=4,
  65. padding=1,
  66. stride=2,
  67. groups=ch_out,
  68. weight_attr=ParamAttr(initializer=XavierUniform()),
  69. bias_attr=False)
  70. bn = batch_norm(ch_out, norm_type=norm_type, norm_decay=0.)
  71. conv3 = ConvNormLayer(
  72. ch_in=ch_out,
  73. ch_out=ch_out,
  74. stride=1,
  75. filter_size=1,
  76. norm_type=norm_type,
  77. initializer=XavierUniform())
  78. self.deconv.add_sublayer('conv1', conv1)
  79. self.deconv.add_sublayer('relu6_1', nn.ReLU6())
  80. self.deconv.add_sublayer('conv2', conv2)
  81. self.deconv.add_sublayer('bn', bn)
  82. self.deconv.add_sublayer('relu6_2', nn.ReLU6())
  83. self.deconv.add_sublayer('conv3', conv3)
  84. self.deconv.add_sublayer('relu6_3', nn.ReLU6())
  85. def forward(self, inputs):
  86. return self.deconv(inputs)
  87. class LiteUpsample(nn.Layer):
  88. def __init__(self, ch_in, ch_out, norm_type='bn'):
  89. super(LiteUpsample, self).__init__()
  90. self.deconv = DeConv(ch_in, ch_out, norm_type=norm_type)
  91. self.conv = LiteConv(ch_in, ch_out, norm_type=norm_type)
  92. def forward(self, inputs):
  93. deconv_up = self.deconv(inputs)
  94. conv = self.conv(inputs)
  95. interp_up = F.interpolate(conv, scale_factor=2., mode='bilinear')
  96. return deconv_up + interp_up
  97. class ShortCut(nn.Layer):
  98. def __init__(self,
  99. layer_num,
  100. ch_in,
  101. ch_out,
  102. norm_type='bn',
  103. lite_neck=False,
  104. name=None):
  105. super(ShortCut, self).__init__()
  106. shortcut_conv = nn.Sequential()
  107. for i in range(layer_num):
  108. fan_out = 3 * 3 * ch_out
  109. std = math.sqrt(2. / fan_out)
  110. in_channels = ch_in if i == 0 else ch_out
  111. shortcut_name = name + '.conv.{}'.format(i)
  112. if lite_neck:
  113. shortcut_conv.add_sublayer(
  114. shortcut_name,
  115. LiteConv(
  116. in_channels=in_channels,
  117. out_channels=ch_out,
  118. with_act=i < layer_num - 1,
  119. norm_type=norm_type))
  120. else:
  121. shortcut_conv.add_sublayer(
  122. shortcut_name,
  123. nn.Conv2D(
  124. in_channels=in_channels,
  125. out_channels=ch_out,
  126. kernel_size=3,
  127. padding=1,
  128. weight_attr=ParamAttr(initializer=Normal(0, std)),
  129. bias_attr=ParamAttr(
  130. learning_rate=2., regularizer=L2Decay(0.))))
  131. if i < layer_num - 1:
  132. shortcut_conv.add_sublayer(shortcut_name + '.act',
  133. nn.ReLU())
  134. self.shortcut = self.add_sublayer('shortcut', shortcut_conv)
  135. def forward(self, feat):
  136. out = self.shortcut(feat)
  137. return out
  138. @register
  139. @serializable
  140. class TTFFPN(nn.Layer):
  141. """
  142. Args:
  143. in_channels (list): number of input feature channels from backbone.
  144. [128,256,512,1024] by default, means the channels of DarkNet53
  145. backbone return_idx [1,2,3,4].
  146. planes (list): the number of output feature channels of FPN.
  147. [256, 128, 64] by default
  148. shortcut_num (list): the number of convolution layers in each shortcut.
  149. [3,2,1] by default, means DarkNet53 backbone return_idx_1 has 3 convs
  150. in its shortcut, return_idx_2 has 2 convs and return_idx_3 has 1 conv.
  151. norm_type (string): norm type, 'sync_bn', 'bn', 'gn' are optional.
  152. bn by default
  153. lite_neck (bool): whether to use lite conv in TTFNet FPN,
  154. False by default
  155. fusion_method (string): the method to fusion upsample and lateral layer.
  156. 'add' and 'concat' are optional, add by default
  157. """
  158. __shared__ = ['norm_type']
  159. def __init__(self,
  160. in_channels,
  161. planes=[256, 128, 64],
  162. shortcut_num=[3, 2, 1],
  163. norm_type='bn',
  164. lite_neck=False,
  165. fusion_method='add'):
  166. super(TTFFPN, self).__init__()
  167. self.planes = planes
  168. self.shortcut_num = shortcut_num[::-1]
  169. self.shortcut_len = len(shortcut_num)
  170. self.ch_in = in_channels[::-1]
  171. self.fusion_method = fusion_method
  172. self.upsample_list = []
  173. self.shortcut_list = []
  174. self.upper_list = []
  175. for i, out_c in enumerate(self.planes):
  176. in_c = self.ch_in[i] if i == 0 else self.upper_list[-1]
  177. upsample_module = LiteUpsample if lite_neck else Upsample
  178. upsample = self.add_sublayer(
  179. 'upsample.' + str(i),
  180. upsample_module(
  181. in_c, out_c, norm_type=norm_type))
  182. self.upsample_list.append(upsample)
  183. if i < self.shortcut_len:
  184. shortcut = self.add_sublayer(
  185. 'shortcut.' + str(i),
  186. ShortCut(
  187. self.shortcut_num[i],
  188. self.ch_in[i + 1],
  189. out_c,
  190. norm_type=norm_type,
  191. lite_neck=lite_neck,
  192. name='shortcut.' + str(i)))
  193. self.shortcut_list.append(shortcut)
  194. if self.fusion_method == 'add':
  195. upper_c = out_c
  196. elif self.fusion_method == 'concat':
  197. upper_c = out_c * 2
  198. else:
  199. raise ValueError('Illegal fusion method. Expected add or\
  200. concat, but received {}'.format(self.fusion_method))
  201. self.upper_list.append(upper_c)
  202. def forward(self, inputs):
  203. feat = inputs[-1]
  204. for i, out_c in enumerate(self.planes):
  205. feat = self.upsample_list[i](feat)
  206. if i < self.shortcut_len:
  207. shortcut = self.shortcut_list[i](inputs[-i - 2])
  208. if self.fusion_method == 'add':
  209. feat = feat + shortcut
  210. else:
  211. feat = paddle.concat([feat, shortcut], axis=1)
  212. return feat
  213. @classmethod
  214. def from_config(cls, cfg, input_shape):
  215. return {'in_channels': [i.channels for i in input_shape], }
  216. @property
  217. def out_shape(self):
  218. return [ShapeSpec(channels=self.upper_list[-1], )]