csp_layer.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. # Copyright (c) OpenMMLab. All rights reserved.
  2. import torch
  3. import torch.nn as nn
  4. from mmcv.cnn import ConvModule, DepthwiseSeparableConvModule
  5. from mmengine.model import BaseModule
  6. from torch import Tensor
  7. from mmdet.utils import ConfigType, OptConfigType, OptMultiConfig
  8. from .se_layer import ChannelAttention
  9. class DarknetBottleneck(BaseModule):
  10. """The basic bottleneck block used in Darknet.
  11. Each ResBlock consists of two ConvModules and the input is added to the
  12. final output. Each ConvModule is composed of Conv, BN, and LeakyReLU.
  13. The first convLayer has filter size of 1x1 and the second one has the
  14. filter size of 3x3.
  15. Args:
  16. in_channels (int): The input channels of this Module.
  17. out_channels (int): The output channels of this Module.
  18. expansion (float): The kernel size of the convolution.
  19. Defaults to 0.5.
  20. add_identity (bool): Whether to add identity to the out.
  21. Defaults to True.
  22. use_depthwise (bool): Whether to use depthwise separable convolution.
  23. Defaults to False.
  24. conv_cfg (dict): Config dict for convolution layer. Defaults to None,
  25. which means using conv2d.
  26. norm_cfg (dict): Config dict for normalization layer.
  27. Defaults to dict(type='BN').
  28. act_cfg (dict): Config dict for activation layer.
  29. Defaults to dict(type='Swish').
  30. """
  31. def __init__(self,
  32. in_channels: int,
  33. out_channels: int,
  34. expansion: float = 0.5,
  35. add_identity: bool = True,
  36. use_depthwise: bool = False,
  37. conv_cfg: OptConfigType = None,
  38. norm_cfg: ConfigType = dict(
  39. type='BN', momentum=0.03, eps=0.001),
  40. act_cfg: ConfigType = dict(type='Swish'),
  41. init_cfg: OptMultiConfig = None) -> None:
  42. super().__init__(init_cfg=init_cfg)
  43. hidden_channels = int(out_channels * expansion)
  44. conv = DepthwiseSeparableConvModule if use_depthwise else ConvModule
  45. self.conv1 = ConvModule(
  46. in_channels,
  47. hidden_channels,
  48. 1,
  49. conv_cfg=conv_cfg,
  50. norm_cfg=norm_cfg,
  51. act_cfg=act_cfg)
  52. self.conv2 = conv(
  53. hidden_channels,
  54. out_channels,
  55. 3,
  56. stride=1,
  57. padding=1,
  58. conv_cfg=conv_cfg,
  59. norm_cfg=norm_cfg,
  60. act_cfg=act_cfg)
  61. self.add_identity = \
  62. add_identity and in_channels == out_channels
  63. def forward(self, x: Tensor) -> Tensor:
  64. """Forward function."""
  65. identity = x
  66. out = self.conv1(x)
  67. out = self.conv2(out)
  68. if self.add_identity:
  69. return out + identity
  70. else:
  71. return out
  72. class CSPNeXtBlock(BaseModule):
  73. """The basic bottleneck block used in CSPNeXt.
  74. Args:
  75. in_channels (int): The input channels of this Module.
  76. out_channels (int): The output channels of this Module.
  77. expansion (float): Expand ratio of the hidden channel. Defaults to 0.5.
  78. add_identity (bool): Whether to add identity to the out. Only works
  79. when in_channels == out_channels. Defaults to True.
  80. use_depthwise (bool): Whether to use depthwise separable convolution.
  81. Defaults to False.
  82. kernel_size (int): The kernel size of the second convolution layer.
  83. Defaults to 5.
  84. conv_cfg (dict): Config dict for convolution layer. Defaults to None,
  85. which means using conv2d.
  86. norm_cfg (dict): Config dict for normalization layer.
  87. Defaults to dict(type='BN', momentum=0.03, eps=0.001).
  88. act_cfg (dict): Config dict for activation layer.
  89. Defaults to dict(type='SiLU').
  90. init_cfg (:obj:`ConfigDict` or dict or list[dict] or
  91. list[:obj:`ConfigDict`], optional): Initialization config dict.
  92. Defaults to None.
  93. """
  94. def __init__(self,
  95. in_channels: int,
  96. out_channels: int,
  97. expansion: float = 0.5,
  98. add_identity: bool = True,
  99. use_depthwise: bool = False,
  100. kernel_size: int = 5,
  101. conv_cfg: OptConfigType = None,
  102. norm_cfg: ConfigType = dict(
  103. type='BN', momentum=0.03, eps=0.001),
  104. act_cfg: ConfigType = dict(type='SiLU'),
  105. init_cfg: OptMultiConfig = None) -> None:
  106. super().__init__(init_cfg=init_cfg)
  107. hidden_channels = int(out_channels * expansion)
  108. conv = DepthwiseSeparableConvModule if use_depthwise else ConvModule
  109. self.conv1 = conv(
  110. in_channels,
  111. hidden_channels,
  112. 3,
  113. stride=1,
  114. padding=1,
  115. norm_cfg=norm_cfg,
  116. act_cfg=act_cfg)
  117. self.conv2 = DepthwiseSeparableConvModule(
  118. hidden_channels,
  119. out_channels,
  120. kernel_size,
  121. stride=1,
  122. padding=kernel_size // 2,
  123. conv_cfg=conv_cfg,
  124. norm_cfg=norm_cfg,
  125. act_cfg=act_cfg)
  126. self.add_identity = \
  127. add_identity and in_channels == out_channels
  128. def forward(self, x: Tensor) -> Tensor:
  129. """Forward function."""
  130. identity = x
  131. out = self.conv1(x)
  132. out = self.conv2(out)
  133. if self.add_identity:
  134. return out + identity
  135. else:
  136. return out
  137. class CSPLayer(BaseModule):
  138. """Cross Stage Partial Layer.
  139. Args:
  140. in_channels (int): The input channels of the CSP layer.
  141. out_channels (int): The output channels of the CSP layer.
  142. expand_ratio (float): Ratio to adjust the number of channels of the
  143. hidden layer. Defaults to 0.5.
  144. num_blocks (int): Number of blocks. Defaults to 1.
  145. add_identity (bool): Whether to add identity in blocks.
  146. Defaults to True.
  147. use_cspnext_block (bool): Whether to use CSPNeXt block.
  148. Defaults to False.
  149. use_depthwise (bool): Whether to use depthwise separable convolution in
  150. blocks. Defaults to False.
  151. channel_attention (bool): Whether to add channel attention in each
  152. stage. Defaults to True.
  153. conv_cfg (dict, optional): Config dict for convolution layer.
  154. Defaults to None, which means using conv2d.
  155. norm_cfg (dict): Config dict for normalization layer.
  156. Defaults to dict(type='BN')
  157. act_cfg (dict): Config dict for activation layer.
  158. Defaults to dict(type='Swish')
  159. init_cfg (:obj:`ConfigDict` or dict or list[dict] or
  160. list[:obj:`ConfigDict`], optional): Initialization config dict.
  161. Defaults to None.
  162. """
  163. def __init__(self,
  164. in_channels: int,
  165. out_channels: int,
  166. expand_ratio: float = 0.5,
  167. num_blocks: int = 1,
  168. add_identity: bool = True,
  169. use_depthwise: bool = False,
  170. use_cspnext_block: bool = False,
  171. channel_attention: bool = False,
  172. conv_cfg: OptConfigType = None,
  173. norm_cfg: ConfigType = dict(
  174. type='BN', momentum=0.03, eps=0.001),
  175. act_cfg: ConfigType = dict(type='Swish'),
  176. init_cfg: OptMultiConfig = None) -> None:
  177. super().__init__(init_cfg=init_cfg)
  178. block = CSPNeXtBlock if use_cspnext_block else DarknetBottleneck
  179. mid_channels = int(out_channels * expand_ratio)
  180. self.channel_attention = channel_attention
  181. self.main_conv = ConvModule(
  182. in_channels,
  183. mid_channels,
  184. 1,
  185. conv_cfg=conv_cfg,
  186. norm_cfg=norm_cfg,
  187. act_cfg=act_cfg)
  188. self.short_conv = ConvModule(
  189. in_channels,
  190. mid_channels,
  191. 1,
  192. conv_cfg=conv_cfg,
  193. norm_cfg=norm_cfg,
  194. act_cfg=act_cfg)
  195. self.final_conv = ConvModule(
  196. 2 * mid_channels,
  197. out_channels,
  198. 1,
  199. conv_cfg=conv_cfg,
  200. norm_cfg=norm_cfg,
  201. act_cfg=act_cfg)
  202. self.blocks = nn.Sequential(*[
  203. block(
  204. mid_channels,
  205. mid_channels,
  206. 1.0,
  207. add_identity,
  208. use_depthwise,
  209. conv_cfg=conv_cfg,
  210. norm_cfg=norm_cfg,
  211. act_cfg=act_cfg) for _ in range(num_blocks)
  212. ])
  213. if channel_attention:
  214. self.attention = ChannelAttention(2 * mid_channels)
  215. def forward(self, x: Tensor) -> Tensor:
  216. """Forward function."""
  217. x_short = self.short_conv(x)
  218. x_main = self.main_conv(x)
  219. x_main = self.blocks(x_main)
  220. x_final = torch.cat((x_main, x_short), dim=1)
  221. if self.channel_attention:
  222. x_final = self.attention(x_final)
  223. return self.final_conv(x_final)