rtcdet_v2_neck.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import torch
  2. import torch.nn as nn
  3. from .rtcdet_v2_basic import Conv
  4. # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
  5. class SPPF(nn.Module):
  6. """
  7. This code referenced to https://github.com/ultralytics/yolov5
  8. """
  9. def __init__(self, cfg, in_dim, out_dim, expand_ratio=0.5):
  10. super().__init__()
  11. inter_dim = int(in_dim * expand_ratio)
  12. self.out_dim = out_dim
  13. self.cv1 = Conv(in_dim, inter_dim, k=1, act_type=cfg['neck_act'], norm_type=cfg['neck_norm'])
  14. self.cv2 = Conv(inter_dim * 4, out_dim, k=1, act_type=cfg['neck_act'], norm_type=cfg['neck_norm'])
  15. self.m = nn.MaxPool2d(kernel_size=cfg['pooling_size'], stride=1, padding=cfg['pooling_size'] // 2)
  16. def forward(self, x):
  17. x = self.cv1(x)
  18. y1 = self.m(x)
  19. y2 = self.m(y1)
  20. return self.cv2(torch.cat((x, y1, y2, self.m(y2)), 1))
  21. # Mixed Spatial Pyramid Pooling
  22. class MixedSPP(nn.Module):
  23. def __init__(self, cfg, in_dim, out_dim, expand_ratio=2.0):
  24. super().__init__()
  25. # ------------- Basic parameters -------------
  26. self.in_dim = in_dim
  27. self.out_dim = out_dim
  28. self.expand_dim = round(in_dim * expand_ratio)
  29. self.num_maxpools = len(cfg['pooling_size']) + 1
  30. # ------------- Network parameters -------------
  31. self.input_proj = Conv(in_dim, self.expand_dim, k=1, act_type=cfg['neck_act'], norm_type=cfg['neck_norm'])
  32. self.maxpools = nn.ModuleList()
  33. for ksize in cfg['pooling_size']:
  34. self.maxpools.append(nn.MaxPool2d(kernel_size=ksize, stride=1, padding=ksize// 2))
  35. self.output_proj = Conv(self.expand_dim, out_dim, k=1, act_type=cfg['neck_act'], norm_type=cfg['neck_norm'])
  36. def forward(self, x):
  37. x = self.input_proj(x)
  38. x_chunks = torch.chunk(x, self.num_maxpools, dim=1)
  39. out = [x_chunks[0]]
  40. for x_chunk, maxpool in zip(x_chunks[1:], self.maxpools):
  41. out.append(maxpool(x_chunk))
  42. out = torch.cat(out, dim=1)
  43. return self.output_proj(out)
  44. # SPPF block with CSP module
  45. class SPPFBlockCSP(nn.Module):
  46. """
  47. CSP Spatial Pyramid Pooling Block
  48. """
  49. def __init__(self, cfg, in_dim, out_dim, expand_ratio):
  50. super(SPPFBlockCSP, self).__init__()
  51. inter_dim = int(in_dim * expand_ratio)
  52. self.out_dim = out_dim
  53. self.cv1 = Conv(in_dim, inter_dim, k=1, act_type=cfg['neck_act'], norm_type=cfg['neck_norm'])
  54. self.cv2 = Conv(in_dim, inter_dim, k=1, act_type=cfg['neck_act'], norm_type=cfg['neck_norm'])
  55. self.m = nn.Sequential(
  56. Conv(inter_dim, inter_dim, k=3, p=1,
  57. act_type=cfg['neck_act'], norm_type=cfg['neck_norm'],
  58. depthwise=cfg['neck_depthwise']),
  59. SPPF(cfg, inter_dim, inter_dim, expand_ratio=1.0),
  60. Conv(inter_dim, inter_dim, k=3, p=1,
  61. act_type=cfg['neck_act'], norm_type=cfg['neck_norm'],
  62. depthwise=cfg['neck_depthwise'])
  63. )
  64. self.cv3 = Conv(inter_dim * 2, self.out_dim, k=1, act_type=cfg['neck_act'], norm_type=cfg['neck_norm'])
  65. def forward(self, x):
  66. x1 = self.cv1(x)
  67. x2 = self.cv2(x)
  68. x3 = self.m(x2)
  69. y = self.cv3(torch.cat([x1, x3], dim=1))
  70. return y
  71. # build neck
  72. def build_neck(cfg, in_dim, out_dim):
  73. model = cfg['neck']
  74. print('==============================')
  75. print('Neck: {}'.format(model))
  76. # build neck
  77. if model == 'sppf':
  78. neck = SPPF(cfg, in_dim, out_dim, cfg['neck_expand_ratio'])
  79. elif model == 'csp_sppf':
  80. neck = SPPFBlockCSP(cfg, in_dim, out_dim, cfg['neck_expand_ratio'])
  81. elif model == 'mixed_spp':
  82. neck = MixedSPP(cfg, in_dim, out_dim, cfg['neck_expand_ratio'])
  83. return neck