• YOLOv5 Head解耦


    Decoupled_Detect

    一、common.py文件中加入DecoupledHead

    1. class DecoupledHead(nn.Module):
    2. def __init__(self, ch=256, nc=80, anchors=()):
    3. super().__init__()
    4. self.nc = nc # number of classes
    5. self.nl = len(anchors) # number of detection layers
    6. self.na = len(anchors[0]) // 2 # number of anchors
    7. self.merge = Conv(ch, 256 , 1, 1)
    8. self.cls_convs1 = Conv(256 , 256 , 3, 1, 1)
    9. self.cls_convs2 = Conv(256 , 256 , 3, 1, 1)
    10. self.reg_convs1 = Conv(256 , 256 , 3, 1, 1)
    11. self.reg_convs2 = Conv(256 , 256 , 3, 1, 1)
    12. self.cls_preds = nn.Conv2d(256 , self.nc * self.na, 1)
    13. self.reg_preds = nn.Conv2d(256 , 4 * self.na, 1)
    14. self.obj_preds = nn.Conv2d(256 , 1 * self.na, 1)
    15. def forward(self, x):
    16. x = self.merge(x)
    17. x1 = self.cls_convs1(x)
    18. x1 = self.cls_convs2(x1)
    19. x1 = self.cls_preds(x1)
    20. x2 = self.reg_convs1(x)
    21. x2 = self.reg_convs2(x2)
    22. x21 = self.reg_preds(x2)
    23. x22 = self.obj_preds(x2)
    24. out = torch.cat([x21, x22, x1], 1)
    25. return out

    二、yolo.py文件中加入加入Decoupled_Detect

    1. class Decoupled_Detect(nn.Module):
    2. stride = None # strides computed during build
    3. onnx_dynamic = False # ONNX export parameter
    4. export = False # export mode
    5. def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer
    6. super().__init__()
    7. self.nc = nc # number of classes
    8. self.no = nc + 5 # number of outputs per anchor
    9. self.nl = len(anchors) # number of detection layers
    10. self.na = len(anchors[0]) // 2 # number of anchors
    11. self.grid = [torch.zeros(1)] * self.nl # init grid
    12. self.anchor_grid = [torch.zeros(1)] * self.nl # init anchor grid
    13. self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2)
    14. self.m = nn.ModuleList(DecoupledHead(x, nc, anchors) for x in ch)
    15. self.inplace = inplace # use in-place ops (e.g. slice assignment)
    16. def forward(self, x):
    17. z = [] # inference output
    18. for i in range(self.nl):
    19. x[i] = self.m[i](x[i]) # conv
    20. bs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85)
    21. x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()
    22. if not self.training: # inference
    23. if self.onnx_dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]:
    24. self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i)
    25. y = x[i].sigmoid()
    26. if self.inplace:
    27. y[..., 0:2] = (y[..., 0:2] * 2 + self.grid[i]) * self.stride[i] # xy
    28. y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh
    29. else: # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953
    30. xy, wh, conf = y.split((2, 2, self.nc + 1), 4) # y.tensor_split((2, 4, 5), 4) # torch 1.8.0
    31. xy = (xy * 2 + self.grid[i]) * self.stride[i] # xy
    32. wh = (wh * 2) ** 2 * self.anchor_grid[i] # wh
    33. y = torch.cat((xy, wh, conf), 4)
    34. z.append(y.view(bs, -1, self.no))
    35. return x if self.training else (torch.cat(z, 1),) if self.export else (torch.cat(z, 1), x)
    36. def _make_grid(self, nx=20, ny=20, i=0, torch_1_10=check_version(torch.__version__, '1.10.0')):
    37. d = self.anchors[i].device
    38. t = self.anchors[i].dtype
    39. shape = 1, self.na, ny, nx, 2 # grid shape
    40. y, x = torch.arange(ny, device=d, dtype=t), torch.arange(nx, device=d, dtype=t)
    41. yv, xv = torch.meshgrid(y, x, indexing='ij') if torch_1_10 else torch.meshgrid(y, x) # torch>=0.7 compatibility
    42. grid = torch.stack((xv, yv), 2).expand(shape) - 0.5 # add grid offset, i.e. y = 2.0 * x - 0.5
    43. anchor_grid = (self.anchors[i] * self.stride[i]).view((1, self.na, 1, 1, 2)).expand(shape)
    44. return grid, anchor_grid

    在yolo.py文件Model类中做如下修改 

     在yolo.py文件parse_model函数下做如下修改

    三、yaml文件中的Detect改为Decoupled_Detect

    ASFF_Detect

    一、common.py文件中加入ASFFV5

    1. class ASFFV5(nn.Module):
    2. def __init__(self, level, multiplier=1, rfb=False, vis=False, act_cfg=True):
    3. """
    4. ASFF version for YoloV5 .
    5. different than YoloV3
    6. multiplier should be 1, 0.5
    7. which means, the channel of ASFF can be
    8. 512, 256, 128 -> multiplier=1
    9. 256, 128, 64 -> multiplier=0.5
    10. For even smaller, you need change code manually.
    11. """
    12. super(ASFFV5, self).__init__()
    13. self.level = level
    14. self.dim = [int(1024 * multiplier), int(512 * multiplier),
    15. int(256 * multiplier)]
    16. # print(self.dim)
    17. self.inter_dim = self.dim[self.level]
    18. if level == 0:
    19. self.stride_level_1 = Conv(int(512 * multiplier), self.inter_dim, 3, 2)
    20. self.stride_level_2 = Conv(int(256 * multiplier), self.inter_dim, 3, 2)
    21. self.expand = Conv(self.inter_dim, int(
    22. 1024 * multiplier), 3, 1)
    23. elif level == 1:
    24. self.compress_level_0 = Conv(
    25. int(1024 * multiplier), self.inter_dim, 1, 1)
    26. self.stride_level_2 = Conv(
    27. int(256 * multiplier), self.inter_dim, 3, 2)
    28. self.expand = Conv(self.inter_dim, int(512 * multiplier), 3, 1)
    29. elif level == 2:
    30. self.compress_level_0 = Conv(
    31. int(1024 * multiplier), self.inter_dim, 1, 1)
    32. self.compress_level_1 = Conv(
    33. int(512 * multiplier), self.inter_dim, 1, 1)
    34. self.expand = Conv(self.inter_dim, int(
    35. 256 * multiplier), 3, 1)
    36. # when adding rfb, we use half number of channels to save memory
    37. compress_c = 8 if rfb else 16
    38. self.weight_level_0 = Conv(
    39. self.inter_dim, compress_c, 1, 1)
    40. self.weight_level_1 = Conv(
    41. self.inter_dim, compress_c, 1, 1)
    42. self.weight_level_2 = Conv(
    43. self.inter_dim, compress_c, 1, 1)
    44. self.weight_levels = Conv(
    45. compress_c * 3, 3, 1, 1)
    46. self.vis = vis
    47. def forward(self, x): # l,m,s
    48. """
    49. # 128, 256, 512
    50. 512, 256, 128
    51. from small -> large
    52. """
    53. x_level_0 = x[2] # l
    54. x_level_1 = x[1] # m
    55. x_level_2 = x[0] # s
    56. # print('x_level_0: ', x_level_0.shape)
    57. # print('x_level_1: ', x_level_1.shape)
    58. # print('x_level_2: ', x_level_2.shape)
    59. if self.level == 0:
    60. level_0_resized = x_level_0
    61. level_1_resized = self.stride_level_1(x_level_1)
    62. level_2_downsampled_inter = F.max_pool2d(
    63. x_level_2, 3, stride=2, padding=1)
    64. level_2_resized = self.stride_level_2(level_2_downsampled_inter)
    65. elif self.level == 1:
    66. level_0_compressed = self.compress_level_0(x_level_0)
    67. level_0_resized = F.interpolate(
    68. level_0_compressed, scale_factor=2, mode='nearest')
    69. level_1_resized = x_level_1
    70. level_2_resized = self.stride_level_2(x_level_2)
    71. elif self.level == 2:
    72. level_0_compressed = self.compress_level_0(x_level_0)
    73. level_0_resized = F.interpolate(
    74. level_0_compressed, scale_factor=4, mode='nearest')
    75. x_level_1_compressed = self.compress_level_1(x_level_1)
    76. level_1_resized = F.interpolate(
    77. x_level_1_compressed, scale_factor=2, mode='nearest')
    78. level_2_resized = x_level_2
    79. # print('level: {}, l1_resized: {}, l2_resized: {}'.format(self.level,
    80. # level_1_resized.shape, level_2_resized.shape))
    81. level_0_weight_v = self.weight_level_0(level_0_resized)
    82. level_1_weight_v = self.weight_level_1(level_1_resized)
    83. level_2_weight_v = self.weight_level_2(level_2_resized)
    84. # print('level_0_weight_v: ', level_0_weight_v.shape)
    85. # print('level_1_weight_v: ', level_1_weight_v.shape)
    86. # print('level_2_weight_v: ', level_2_weight_v.shape)
    87. levels_weight_v = torch.cat(
    88. (level_0_weight_v, level_1_weight_v, level_2_weight_v), 1)
    89. levels_weight = self.weight_levels(levels_weight_v)
    90. levels_weight = F.softmax(levels_weight, dim=1)
    91. fused_out_reduced = level_0_resized * levels_weight[:, 0:1, :, :] + \
    92. level_1_resized * levels_weight[:, 1:2, :, :] + \
    93. level_2_resized * levels_weight[:, 2:, :, :]
    94. out = self.expand(fused_out_reduced)
    95. if self.vis:
    96. return out, levels_weight, fused_out_reduced.sum(dim=1)
    97. else:
    98. return out

    二、yolo.py文件中加入加入ASFF_Detect

    1. class ASFF_Detect(nn.Module): #add ASFFV5 layer and Rfb
    2. stride = None # strides computed during build
    3. onnx_dynamic = False # ONNX export parameter
    4. export = False # export mode
    5. def __init__(self, nc=80, anchors=(), ch=(), multiplier=0.5,rfb=False,inplace=True): # detection layer
    6. super().__init__()
    7. self.nc = nc # number of classes
    8. self.no = nc + 5 # number of outputs per anchor
    9. self.nl = len(anchors) # number of detection layers
    10. self.na = len(anchors[0]) // 2 # number of anchors
    11. self.grid = [torch.zeros(1)] * self.nl # init grid
    12. self.l0_fusion = ASFFV5(level=0, multiplier=multiplier,rfb=rfb)
    13. self.l1_fusion = ASFFV5(level=1, multiplier=multiplier,rfb=rfb)
    14. self.l2_fusion = ASFFV5(level=2, multiplier=multiplier,rfb=rfb)
    15. self.anchor_grid = [torch.zeros(1)] * self.nl # init anchor grid
    16. self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2)
    17. self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv
    18. self.inplace = inplace # use in-place ops (e.g. slice assignment)
    19. def forward(self, x):
    20. z = [] # inference output
    21. result=[]
    22. result.append(self.l2_fusion(x))
    23. result.append(self.l1_fusion(x))
    24. result.append(self.l0_fusion(x))
    25. x=result
    26. for i in range(self.nl):
    27. x[i] = self.m[i](x[i]) # conv
    28. bs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85)
    29. x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()
    30. if not self.training: # inference
    31. if self.onnx_dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]:
    32. self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i)
    33. y = x[i].sigmoid()
    34. if self.inplace:
    35. y[..., 0:2] = (y[..., 0:2] * 2 + self.grid[i]) * self.stride[i] # xy
    36. y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh
    37. else: # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953
    38. xy, wh, conf = y.split((2, 2, self.nc + 1), 4) # y.tensor_split((2, 4, 5), 4) # torch 1.8.0
    39. xy = (xy * 2 + self.grid[i]) * self.stride[i] # xy
    40. wh = (wh * 2) ** 2 * self.anchor_grid[i] # wh
    41. y = torch.cat((xy, wh, conf), 4)
    42. z.append(y.view(bs, -1, self.no))
    43. return x if self.training else (torch.cat(z, 1),) if self.export else (torch.cat(z, 1), x)
    44. def _make_grid(self, nx=20, ny=20, i=0,torch_1_10=check_version(torch.__version__, '1.10.0')):
    45. d = self.anchors[i].device
    46. t = self.anchors[i].dtype
    47. shape = 1, self.na, ny, nx, 2 # grid shape
    48. y, x = torch.arange(ny, device=d, dtype=t), torch.arange(nx, device=d, dtype=t)
    49. if torch_1_10: # torch>=1.10.0 meshgrid workaround for torch>=0.7 compatibility
    50. yv, xv = torch.meshgrid(y, x, indexing='ij')
    51. else:
    52. yv, xv = torch.meshgrid(y, x)
    53. grid = torch.stack((xv, yv), 2).expand(shape) - 0.5 # add grid offset, i.e. y = 2.0 * x - 0.5
    54. anchor_grid = (self.anchors[i] * self.stride[i]).view((1, self.na, 1, 1, 2)).expand(shape)
    55. #print(anchor_grid)
    56. return grid, anchor_grid

    在yolo.py文件Model类中做如下修改

     在yolo.py文件parse_model函数下做如下修改

    三、yaml文件中的Detect改为ASFF_Detect

  • 相关阅读:
    【测试代码 & 基于Pytorch】的卷积神经网络(CNN) || 【基于Pytorch】的深度卷积神经网络(DCNN)
    js基础算法
    【dgl学习】dgl处理图中的节点/边的属性/特征/类型
    vue 封装水球图
    【RocketMQ集群】Linux搭建RocketMQ双主双从集群
    IBM Semeru Windows 下的安装
    多维时序 | Matlab实现GRU-Adaboost和GRU多变量时间序列预测对比
    wpf menu 菜单 快捷键
    UNIX环境高级编程-第一章
    windows查看登陆的IP
  • 原文地址:https://blog.csdn.net/m0_56247038/article/details/126741535