YOLOv11改进 | 细节涨点篇 | 2024最新高效上采样模块EUCB助力yolov11有效涨点(全网独家创新)

一、本文介绍

本文给大家带来的最新改进机制是2024最新高效 上采样 模块 EUCB ,EUCB 用于逐步上采样 特征图 ,使其尺寸和分辨率与后续跳跃连接相匹配。这种对齐增强了不同层级和阶段间的信息融合(这个模块对于分割网络效果更佳), EUCB 首先进行上采样操作 ,将输入特征图的尺度放大 2 倍,然后应用 DWC,接着进行批归一化(BN)和 ReLU 激活,这些步骤能够在不增加显著计算开销的情况下高效地增强特征图。最后进行 1x1 卷积以减少通道数,使上采样后的特征图与下一阶段的通道数相匹配,这对于解码路径中的平滑集成至关重要, 本文内容为独家整理, 同时该结构可以和其他Neck结构进行融合形成二次创新。

欢迎大家订阅我的专栏一起学习YOLO!


目录

一、本文介绍

二、原理介绍

三、核心代码

四、手把手教你添加EUCB

4.1 修改一

4.2 修改二

4.3 修改三

4.4 修改四

五、正式训练

5.1 yaml文件1

5.2 训练代码

5.3 训练过程截图

五、本文总结


二、原理介绍

论文地址: 官方论文地址

代码地址: 官方代码地址


Efficient Up-Convolution Block (EUCB) 机制的主要原理:

1. 目的和功能:
- EUCB 用于逐步上采样特征图,使其尺寸和 分辨率 与后续跳跃连接相匹配。这种对齐增强了不同层级和阶段间的信息融合,对于在分割过程中保持空间一致性至关重要。

2. 核心过程:

  • EUCB 机制首先进行上采样操作,将输入特征图的尺度放大 2 倍。
  • 然后应用 3x3 深度卷积(DWC),接着进行批归一化(BN)和 ReLU 激活,这些步骤能够在不增加显著计算开销的情况下高效地增强特征图。
  • 最后进行 1x1 卷积以减少通道数,使上采样后的特征图与下一阶段的通道数相匹配,这对于解码路径中的平滑集成至关重要。

3. 优势:
在 EUCB 中使用深度卷积实现高效计算,减少了标准 3x3 卷积通常带来的开销。这使得 EUCB 特别适合于对计算效率要求较高的应用场景,如便携式医疗影像系统。

4. 总体影响:
EUCB 通过高效地进行多阶段特征聚合和精细化,帮助 EMCAD 在减少计算资源的同时,生成高质量、高分辨率的分割结果。


三、核心代码

核心代码的使用方式看章节四!

  1. import torch
  2. import torch.nn as nn
  3. from functools import partial
  4. import math
  5. from timm.models.layers import trunc_normal_tf_
  6. from timm.models.helpers import named_apply
  7. __all__ = ['EUCB']
  8. def gcd(a, b):
  9. while b:
  10. a, b = b, a % b
  11. return a
  12. # Other types of layers can go here (e.g., nn.Linear, etc.)
  13. def _init_weights(module, name, scheme=''):
  14. if isinstance(module, nn.Conv2d) or isinstance(module, nn.Conv3d):
  15. if scheme == 'normal':
  16. nn.init.normal_(module.weight, std=.02)
  17. if module.bias is not None:
  18. nn.init.zeros_(module.bias)
  19. elif scheme == 'trunc_normal':
  20. trunc_normal_tf_(module.weight, std=.02)
  21. if module.bias is not None:
  22. nn.init.zeros_(module.bias)
  23. elif scheme == 'xavier_normal':
  24. nn.init.xavier_normal_(module.weight)
  25. if module.bias is not None:
  26. nn.init.zeros_(module.bias)
  27. elif scheme == 'kaiming_normal':
  28. nn.init.kaiming_normal_(module.weight, mode='fan_out', nonlinearity='relu')
  29. if module.bias is not None:
  30. nn.init.zeros_(module.bias)
  31. else:
  32. # efficientnet like
  33. fan_out = module.kernel_size[0] * module.kernel_size[1] * module.out_channels
  34. fan_out //= module.groups
  35. nn.init.normal_(module.weight, 0, math.sqrt(2.0 / fan_out))
  36. if module.bias is not None:
  37. nn.init.zeros_(module.bias)
  38. elif isinstance(module, nn.BatchNorm2d) or isinstance(module, nn.BatchNorm3d):
  39. nn.init.constant_(module.weight, 1)
  40. nn.init.constant_(module.bias, 0)
  41. elif isinstance(module, nn.LayerNorm):
  42. nn.init.constant_(module.weight, 1)
  43. nn.init.constant_(module.bias, 0)
  44. def act_layer(act, inplace=False, neg_slope=0.2, n_prelu=1):
  45. # activation layer
  46. act = act.lower()
  47. if act == 'relu':
  48. layer = nn.ReLU(inplace)
  49. elif act == 'relu6':
  50. layer = nn.ReLU6(inplace)
  51. elif act == 'leakyrelu':
  52. layer = nn.LeakyReLU(neg_slope, inplace)
  53. elif act == 'prelu':
  54. layer = nn.PReLU(num_parameters=n_prelu, init=neg_slope)
  55. elif act == 'gelu':
  56. layer = nn.GELU()
  57. elif act == 'hswish':
  58. layer = nn.Hardswish(inplace)
  59. else:
  60. raise NotImplementedError('activation layer [%s] is not found' % act)
  61. return layer
  62. def channel_shuffle(x, groups):
  63. batchsize, num_channels, height, width = x.data.size()
  64. channels_per_group = num_channels // groups
  65. # reshape
  66. x = x.view(batchsize, groups,
  67. channels_per_group, height, width)
  68. x = torch.transpose(x, 1, 2).contiguous()
  69. # flatten
  70. x = x.view(batchsize, -1, height, width)
  71. return x
  72. # Multi-scale depth-wise convolution (MSDC)
  73. class MSDC(nn.Module):
  74. def __init__(self, in_channels, kernel_sizes=3, stride=1, activation='relu6', dw_parallel=True):
  75. super(MSDC, self).__init__()
  76. self.in_channels = in_channels
  77. self.kernel_sizes = kernel_sizes
  78. self.activation = activation
  79. self.dw_parallel = dw_parallel
  80. self.dwconvs = nn.ModuleList([
  81. nn.Sequential(
  82. nn.Conv2d(self.in_channels, self.in_channels, kernel_size, stride, kernel_size // 2,
  83. groups=self.in_channels, bias=False),
  84. nn.BatchNorm2d(self.in_channels),
  85. act_layer(self.activation, inplace=True)
  86. )
  87. for kernel_size in self.kernel_sizes
  88. ])
  89. self.init_weights('normal')
  90. def init_weights(self, scheme=''):
  91. named_apply(partial(_init_weights, scheme=scheme), self)
  92. def forward(self, x):
  93. # Apply the convolution layers in a loop
  94. outputs = []
  95. for dwconv in self.dwconvs:
  96. dw_out = dwconv(x)
  97. outputs.append(dw_out)
  98. if self.dw_parallel == False:
  99. x = x + dw_out
  100. # You can return outputs based on what you intend to do with them
  101. return outputs
  102. # Efficient up-convolution block (EUCB)
  103. class EUCB(nn.Module):
  104. def __init__(self, in_channels, kernel_size=3, stride=1, activation='relu'):
  105. super(EUCB, self).__init__()
  106. self.in_channels = in_channels
  107. self.out_channels = in_channels
  108. self.up_dwc = nn.Sequential(
  109. nn.Upsample(scale_factor=2),
  110. nn.Conv2d(self.in_channels, self.in_channels, kernel_size=kernel_size, stride=stride,
  111. padding=kernel_size // 2, groups=self.in_channels, bias=False),
  112. nn.BatchNorm2d(self.in_channels),
  113. act_layer(activation, inplace=True)
  114. )
  115. self.pwc = nn.Sequential(
  116. nn.Conv2d(self.in_channels, self.out_channels, kernel_size=1, stride=1, padding=0, bias=True)
  117. )
  118. self.init_weights('normal')
  119. def init_weights(self, scheme=''):
  120. named_apply(partial(_init_weights, scheme=scheme), self)
  121. def forward(self, x):
  122. x = self.up_dwc(x)
  123. x = channel_shuffle(x, self.in_channels)
  124. x = self.pwc(x)
  125. return x
  126. if __name__ == "__main__":
  127. # Generating Sample image
  128. image_size = (1, 64, 240, 240)
  129. image = torch.rand(*image_size)
  130. # Model
  131. mobilenet_v1 = EUCB(64)
  132. out = mobilenet_v1(image)
  133. print(out.size())


四、手把手教你添加EUCB

4.1 修改一

第一还是建立文件,我们找到如下 ultralytics /nn文件夹下建立一个目录名字呢就是'Addmodules'文件夹( !然后在其内部建立一个新的py文件将核心代码复制粘贴进去即可。


4.2 修改二

第二步我们在该目录下创建一个新的py文件名字为'__init__.py'( ,然后在其内部导入我们的检测头如下图所示。

​​


4.3 修改三

第三步我门中到如下文件'ultralytics/nn/tasks.py'进行导入和注册我们的模块( !

​​


4.4 修改四

按照我的添加在parse_model里添加即可。

​​


到此就修改完成了,大家可以复制下面的yaml文件运行。


五、正式训练


5.1 yaml文件1

训练信息:YOLO11-EUCB summary: 333 layers, 2,676,563 parameters, 2,676,547 gradients, 6.9 GFLOPs

  1. # Ultralytics YOLO 🚀, AGPL-3.0 license
  2. # YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect
  3. # Parameters
  4. nc: 80 # number of classes
  5. scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
  6. # [depth, width, max_channels]
  7. n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
  8. s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
  9. m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
  10. l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
  11. x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs
  12. # YOLO11n backbone
  13. backbone:
  14. # [from, repeats, module, args]
  15. - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
  16. - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
  17. - [-1, 2, C3k2, [256, False, 0.25]]
  18. - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
  19. - [-1, 2, C3k2, [512, False, 0.25]]
  20. - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
  21. - [-1, 2, C3k2, [512, True]]
  22. - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
  23. - [-1, 2, C3k2, [1024, True]]
  24. - [-1, 1, SPPF, [1024, 5]] # 9
  25. - [-1, 2, C2PSA, [1024]] # 10
  26. # YOLO11n head
  27. head:
  28. - [-1, 1, EUCB, []]
  29. - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  30. - [-1, 2, C3k2, [512, False]] # 13
  31. - [-1, 1, EUCB, []]
  32. - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  33. - [-1, 2, C3k2, [256, False]] # 16 (P3/8-small)
  34. - [-1, 1, Conv, [256, 3, 2]]
  35. - [[-1, 13], 1, Concat, [1]] # cat head P4
  36. - [-1, 2, C3k2, [512, False]] # 19 (P4/16-medium)
  37. - [-1, 1, Conv, [512, 3, 2]]
  38. - [[-1, 10], 1, Concat, [1]] # cat head P5
  39. - [-1, 2, C3k2, [1024, True]] # 22 (P5/32-large)
  40. - [[16, 19, 22], 1, Detect, [nc]] # Detect(P3, P4, P5)


5.2 训练代码

大家可以创建一个py文件将我给的代码复制粘贴进去,配置好自己的文件路径即可运行。

  1. import warnings
  2. warnings.filterwarnings('ignore')
  3. from ultralytics import YOLO
  4. if __name__ == '__main__':
  5. model = YOLO('模型配置文件')
  6. # 如何切换模型版本, 上面的ymal文件可以改为 yolov8s.yaml就是使用的v8s,
  7. # 类似某个改进的yaml文件名称为yolov8-XXX.yaml那么如果想使用其它版本就把上面的名称改为yolov8l-XXX.yaml即可(改的是上面YOLO中间的名字不是配置文件的)!
  8. # model.load('yolov8n.pt') # 是否加载预训练权重,科研不建议大家加载否则很难提升精度
  9. model.train(data=r"C:\Users\Administrator\PycharmProjects\yolov5-master\yolov5-master\Construction Site Safety.v30-raw-images_latestversion.yolov8\data.yaml",
  10. # 如果大家任务是其它的'ultralytics/cfg/default.yaml'找到这里修改task可以改成detect, segment, classify, pose
  11. cache=False,
  12. imgsz=640,
  13. epochs=150,
  14. single_cls=False, # 是否是单类别检测
  15. batch=16,
  16. close_mosaic=0,
  17. workers=0,
  18. device='0',
  19. optimizer='SGD', # using SGD
  20. # resume='runs/train/exp21/weights/last.pt', # 如过想续训就设置last.pt的地址
  21. amp=True, # 如果出现训练损失为Nan可以关闭amp
  22. project='runs/train',
  23. name='exp',
  24. )


5.3 训练过程截图


五、本文总结

到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv11改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~