yolov7_af_backbone.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import torch
  2. import torch.nn as nn
  3. try:
  4. from .yolov7_af_basic import BasicConv, MDown, ELANLayer
  5. except:
  6. from yolov7_af_basic import BasicConv, MDown, ELANLayer
  7. # IN1K pretrained weight
  8. pretrained_urls = {
  9. 't': None,
  10. 'l': None,
  11. 'x': None,
  12. }
  13. # ELANNet
  14. class Yolov7TBackbone(nn.Module):
  15. def __init__(self, cfg):
  16. super(Yolov7TBackbone, self).__init__()
  17. # ---------------- Basic parameters ----------------
  18. self.model_scale = cfg.scale
  19. self.bk_act = cfg.bk_act
  20. self.bk_norm = cfg.bk_norm
  21. self.bk_depthwise = cfg.bk_depthwise
  22. self.elan_depth = 1
  23. self.feat_dims = [round(64 * cfg.width), round(128 * cfg.width),
  24. round(256 * cfg.width), round(512 * cfg.width), round(1024 * cfg.width)]
  25. # ---------------- Model parameters ----------------
  26. self.layer_1 = self.make_stem(3, self.feat_dims[0])
  27. self.layer_2 = self.make_block(self.feat_dims[0], self.feat_dims[1], expansion=0.5)
  28. self.layer_3 = self.make_block(self.feat_dims[1], self.feat_dims[2], expansion=0.5)
  29. self.layer_4 = self.make_block(self.feat_dims[2], self.feat_dims[3], expansion=0.5)
  30. self.layer_5 = self.make_block(self.feat_dims[3], self.feat_dims[4], expansion=0.5)
  31. # Initialize all layers
  32. self.init_weights()
  33. def init_weights(self):
  34. """Initialize the parameters."""
  35. for m in self.modules():
  36. if isinstance(m, torch.nn.Conv2d):
  37. # In order to be consistent with the source code,
  38. # reset the Conv2d initialization parameters
  39. m.reset_parameters()
  40. def make_stem(self, in_dim, out_dim):
  41. stem = BasicConv(in_dim, out_dim, kernel_size=6, padding=2, stride=2,
  42. act_type=self.bk_act, norm_type=self.bk_norm, depthwise=self.bk_depthwise)
  43. return stem
  44. def make_block(self, in_dim, out_dim, expansion=0.5):
  45. block = nn.Sequential(
  46. nn.MaxPool2d((2, 2), stride=2),
  47. ELANLayer(in_dim, out_dim,
  48. expansion=expansion, num_blocks=self.elan_depth,
  49. act_type=self.bk_act, norm_type=self.bk_norm, depthwise=self.bk_depthwise),
  50. )
  51. return block
  52. def forward(self, x):
  53. c1 = self.layer_1(x)
  54. c2 = self.layer_2(c1)
  55. c3 = self.layer_3(c2)
  56. c4 = self.layer_4(c3)
  57. c5 = self.layer_5(c4)
  58. outputs = [c3, c4, c5]
  59. return outputs
  60. class Yolov7LBackbone(nn.Module):
  61. def __init__(self, cfg):
  62. super(Yolov7LBackbone, self).__init__()
  63. # ---------------- Basic parameters ----------------
  64. self.model_scale = cfg.scale
  65. self.bk_act = cfg.bk_act
  66. self.bk_norm = cfg.bk_norm
  67. self.bk_depthwise = cfg.bk_depthwise
  68. self.elan_depth = 2
  69. self.feat_dims = [round(64 * cfg.width), round(128 * cfg.width), round(256 * cfg.width),
  70. round(512 * cfg.width), round(1024 * cfg.width), round(1024 * cfg.width)]
  71. # ---------------- Model parameters ----------------
  72. self.layer_1 = self.make_stem(3, self.feat_dims[0])
  73. self.layer_2 = self.make_block(self.feat_dims[0], self.feat_dims[1], self.feat_dims[2], expansion=0.5, conv_downsample=True)
  74. self.layer_3 = self.make_block(self.feat_dims[2], self.feat_dims[2], self.feat_dims[3], expansion=0.5)
  75. self.layer_4 = self.make_block(self.feat_dims[3], self.feat_dims[3], self.feat_dims[4], expansion=0.5)
  76. self.layer_5 = self.make_block(self.feat_dims[4], self.feat_dims[4], self.feat_dims[5], expansion=0.25)
  77. # Initialize all layers
  78. self.init_weights()
  79. # Load imagenet pretrained weight
  80. if cfg.use_pretrained:
  81. self.load_pretrained()
  82. def init_weights(self):
  83. """Initialize the parameters."""
  84. for m in self.modules():
  85. if isinstance(m, torch.nn.Conv2d):
  86. # In order to be consistent with the source code,
  87. # reset the Conv2d initialization parameters
  88. m.reset_parameters()
  89. def load_pretrained(self):
  90. url = pretrained_urls[self.model_scale]
  91. if url is not None:
  92. print('Loading backbone pretrained weight from : {}'.format(url))
  93. # checkpoint state dict
  94. checkpoint = torch.hub.load_state_dict_from_url(
  95. url=url, map_location="cpu", check_hash=True)
  96. checkpoint_state_dict = checkpoint.pop("model")
  97. # model state dict
  98. model_state_dict = self.state_dict()
  99. # check
  100. for k in list(checkpoint_state_dict.keys()):
  101. if k in model_state_dict:
  102. shape_model = tuple(model_state_dict[k].shape)
  103. shape_checkpoint = tuple(checkpoint_state_dict[k].shape)
  104. if shape_model != shape_checkpoint:
  105. checkpoint_state_dict.pop(k)
  106. else:
  107. checkpoint_state_dict.pop(k)
  108. print('Unused key: ', k)
  109. # load the weight
  110. self.load_state_dict(checkpoint_state_dict)
  111. else:
  112. print('No pretrained weight for model scale: {}.'.format(self.model_scale))
  113. def make_stem(self, in_dim, out_dim):
  114. stem = nn.Sequential(
  115. BasicConv(in_dim, out_dim//2, kernel_size=3, padding=1, stride=1,
  116. act_type=self.bk_act, norm_type=self.bk_norm, depthwise=self.bk_depthwise),
  117. BasicConv(out_dim//2, out_dim, kernel_size=3, padding=1, stride=2,
  118. act_type=self.bk_act, norm_type=self.bk_norm, depthwise=self.bk_depthwise),
  119. BasicConv(out_dim, out_dim, kernel_size=3, padding=1, stride=1,
  120. act_type=self.bk_act, norm_type=self.bk_norm, depthwise=self.bk_depthwise)
  121. )
  122. return stem
  123. def make_block(self, in_dim, out_dim_1, out_dim_2, expansion=0.5, conv_downsample=False):
  124. if conv_downsample:
  125. block = nn.Sequential(
  126. BasicConv(in_dim, out_dim_1, kernel_size=3, padding=1, stride=2,
  127. act_type=self.bk_act, norm_type=self.bk_norm, depthwise=self.bk_depthwise),
  128. ELANLayer(out_dim_1, out_dim_2,
  129. expansion=expansion, num_blocks=self.elan_depth,
  130. act_type=self.bk_act, norm_type=self.bk_norm, depthwise=self.bk_depthwise),
  131. )
  132. else:
  133. block = nn.Sequential(
  134. MDown(in_dim, out_dim_1,
  135. act_type=self.bk_act, norm_type=self.bk_norm, depthwise=self.bk_depthwise),
  136. ELANLayer(out_dim_1, out_dim_2,
  137. expansion=expansion, num_blocks=self.elan_depth,
  138. act_type=self.bk_act, norm_type=self.bk_norm, depthwise=self.bk_depthwise),
  139. )
  140. return block
  141. def forward(self, x):
  142. c1 = self.layer_1(x)
  143. c2 = self.layer_2(c1)
  144. c3 = self.layer_3(c2)
  145. c4 = self.layer_4(c3)
  146. c5 = self.layer_5(c4)
  147. outputs = [c3, c4, c5]
  148. return outputs
  149. if __name__ == '__main__':
  150. import time
  151. from thop import profile
  152. class BaseConfig(object):
  153. def __init__(self) -> None:
  154. self.bk_act = 'silu'
  155. self.bk_norm = 'BN'
  156. self.bk_depthwise = False
  157. self.width = 0.5
  158. self.depth = 0.34
  159. self.scale = "l"
  160. cfg = BaseConfig()
  161. model = Yolov7TBackbone(cfg)
  162. x = torch.randn(1, 3, 640, 640)
  163. t0 = time.time()
  164. outputs = model(x)
  165. t1 = time.time()
  166. print('Time: ', t1 - t0)
  167. for out in outputs:
  168. print(out.shape)
  169. x = torch.randn(1, 3, 640, 640)
  170. print('==============================')
  171. flops, params = profile(model, inputs=(x, ), verbose=False)
  172. print('==============================')
  173. print('GFLOPs : {:.2f}'.format(flops / 1e9 * 2))
  174. print('Params : {:.2f} M'.format(params / 1e6))