yolov7_pafpn.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import torch
  2. import torch.nn as nn
  3. import torch.nn.functional as F
  4. from .yolov7_basic import Conv, ELANBlockFPN, DownSample
  5. # PaFPN-ELAN (YOLOv7's)
  6. class Yolov7PaFPN(nn.Module):
  7. def __init__(self,
  8. in_dims=[512, 1024, 512],
  9. out_dim=None,
  10. channel_width : float = 1.0,
  11. branch_width : int = 4.0,
  12. branch_depth : int = 1.0,
  13. act_type='silu',
  14. norm_type='BN',
  15. depthwise=False):
  16. super(Yolov7PaFPN, self).__init__()
  17. # ----------------------------- Basic parameters -----------------------------
  18. self.fpn_dims = in_dims
  19. self.channel_width = channel_width
  20. self.branch_width = branch_width
  21. self.branch_depth = branch_depth
  22. c3, c4, c5 = self.fpn_dims
  23. # ----------------------------- Top-down FPN -----------------------------
  24. ## P5 -> P4
  25. self.reduce_layer_1 = Conv(c5, round(256*channel_width), k=1, norm_type=norm_type, act_type=act_type)
  26. self.reduce_layer_2 = Conv(c4, round(256*channel_width), k=1, norm_type=norm_type, act_type=act_type)
  27. self.top_down_layer_1 = ELANBlockFPN(in_dim=round(256*channel_width) + round(256*channel_width),
  28. out_dim=round(256*channel_width),
  29. squeeze_ratio=0.5,
  30. branch_width=branch_width,
  31. branch_depth=branch_depth,
  32. act_type=act_type,
  33. norm_type=norm_type,
  34. depthwise=depthwise
  35. )
  36. ## P4 -> P3
  37. self.reduce_layer_3 = Conv(round(256*channel_width), round(128*channel_width), k=1, norm_type=norm_type, act_type=act_type)
  38. self.reduce_layer_4 = Conv(c3, round(128*channel_width), k=1, norm_type=norm_type, act_type=act_type)
  39. self.top_down_layer_2 = ELANBlockFPN(in_dim=round(128*channel_width) + round(128*channel_width),
  40. out_dim=round(128*channel_width),
  41. squeeze_ratio=0.5,
  42. branch_width=branch_width,
  43. branch_depth=branch_depth,
  44. act_type=act_type,
  45. norm_type=norm_type,
  46. depthwise=depthwise
  47. )
  48. # ----------------------------- Bottom-up FPN -----------------------------
  49. ## P3 -> P4
  50. self.downsample_layer_1 = DownSample(round(128*channel_width), round(256*channel_width), act_type, norm_type, depthwise)
  51. self.bottom_up_layer_1 = ELANBlockFPN(in_dim=round(256*channel_width) + round(256*channel_width),
  52. out_dim=round(256*channel_width),
  53. squeeze_ratio=0.5,
  54. branch_width=branch_width,
  55. branch_depth=branch_depth,
  56. act_type=act_type,
  57. norm_type=norm_type,
  58. depthwise=depthwise
  59. )
  60. ## P4 -> P5
  61. self.downsample_layer_2 = DownSample(round(256*channel_width), round(512*channel_width), act_type, norm_type, depthwise)
  62. self.bottom_up_layer_2 = ELANBlockFPN(in_dim=round(512*channel_width) + c5,
  63. out_dim=round(512*channel_width),
  64. squeeze_ratio=0.5,
  65. branch_width=branch_width,
  66. branch_depth=branch_depth,
  67. act_type=act_type,
  68. norm_type=norm_type,
  69. depthwise=depthwise
  70. )
  71. # ----------------------------- Output Proj -----------------------------
  72. ## Head convs
  73. self.head_conv_1 = Conv(round(128*channel_width), round(256*channel_width), k=3, s=1, p=1, act_type=act_type, norm_type=norm_type)
  74. self.head_conv_2 = Conv(round(256*channel_width), round(512*channel_width), k=3, s=1, p=1, act_type=act_type, norm_type=norm_type)
  75. self.head_conv_3 = Conv(round(512*channel_width), round(1024*channel_width), k=3, s=1, p=1, act_type=act_type, norm_type=norm_type)
  76. ## Output projs
  77. if out_dim is not None:
  78. self.out_layers = nn.ModuleList([
  79. Conv(in_dim, out_dim, k=1, act_type=act_type, norm_type=norm_type)
  80. for in_dim in [round(256*channel_width), round(512*channel_width), round(1024*channel_width)]
  81. ])
  82. self.out_dim = [out_dim] * 3
  83. else:
  84. self.out_layers = None
  85. self.out_dim = [round(256*channel_width), round(512*channel_width), round(1024*channel_width)]
  86. def forward(self, features):
  87. c3, c4, c5 = features
  88. # Top down
  89. ## P5 -> P4
  90. c6 = self.reduce_layer_1(c5)
  91. c7 = F.interpolate(c6, scale_factor=2.0)
  92. c8 = torch.cat([c7, self.reduce_layer_2(c4)], dim=1)
  93. c9 = self.top_down_layer_1(c8)
  94. ## P4 -> P3
  95. c10 = self.reduce_layer_3(c9)
  96. c11 = F.interpolate(c10, scale_factor=2.0)
  97. c12 = torch.cat([c11, self.reduce_layer_4(c3)], dim=1)
  98. c13 = self.top_down_layer_2(c12)
  99. # Bottom up
  100. ## p3 -> P4
  101. c14 = self.downsample_layer_1(c13)
  102. c15 = torch.cat([c14, c9], dim=1)
  103. c16 = self.bottom_up_layer_1(c15)
  104. ## P4 -> P5
  105. c17 = self.downsample_layer_2(c16)
  106. c18 = torch.cat([c17, c5], dim=1)
  107. c19 = self.bottom_up_layer_2(c18)
  108. c20 = self.head_conv_1(c13)
  109. c21 = self.head_conv_2(c16)
  110. c22 = self.head_conv_3(c19)
  111. out_feats = [c20, c21, c22] # [P3, P4, P5]
  112. # output proj layers
  113. if self.out_layers is not None:
  114. out_feats_proj = []
  115. for feat, layer in zip(out_feats, self.out_layers):
  116. out_feats_proj.append(layer(feat))
  117. return out_feats_proj
  118. return out_feats
  119. def build_fpn(cfg, in_dims, out_dim=None):
  120. model = cfg['fpn']
  121. # build pafpn
  122. if model == 'yolov7_pafpn':
  123. fpn_net = Yolov7PaFPN(in_dims = in_dims,
  124. out_dim = out_dim,
  125. channel_width = cfg['channel_width'],
  126. branch_width = cfg['branch_width'],
  127. branch_depth = cfg['branch_depth'],
  128. act_type = cfg['fpn_act'],
  129. norm_type = cfg['fpn_norm'],
  130. depthwise = cfg['fpn_depthwise']
  131. )
  132. return fpn_net