秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转
💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡
专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有100+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进——点击即可跳转
本文介绍的Multi-Scale是基于不同核大小的卷积如何影响不同尺度对象的检测性能研究。其成果是一种新策略,可以显著增强实时目标检测器在多尺度特征表示上的能力。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。
专栏地址:YOLOv8改进——更新各种有效涨点方法——点击即可跳转
目录
1. 原理
2. 将C2f_MSBlock添加到yolov8网络中
2.1 C2f_MSBlock代码实现
2.2 C2f_MSBlock的神经网络模块代码解析
2.3 更改init.py文件
2.4 添加yaml文件
2.5 注册模块
2.6 执行程序
3. 完整代码分享
4. GFLOPs
5. 进阶
6. 总结
1. 原理
论文地址:YOLO-MS: Rethinking Multi-Scale Representation Learning for Real-time Object Detection——点击即可跳转
官方代码:官方代码仓库——点击即可跳转
多尺度块(MS-Block)是增强实时物体检测中多尺度特征表示能力的关键组件。以下是其主要原理的分解:
-
分层特征融合:MS-Block 采用受 Res2Net 模型启发的分层特征融合策略。它将输入特征图分成多个组,每个组单独处理。第一组不做任何修改就通过,而后续组则通过倒置瓶颈层处理,这些层涉及具有不同内核大小的深度卷积。这使网络能够有效地捕获多尺度特征。
-
带深度卷积的倒置瓶颈:MS-Block 使用带深度卷积的倒置瓶颈结构,而不是标准卷积。这种方法可以有效地使用大内核,从而增强了块捕获不同尺度特征的能力,而不会产生过多的计算成本。
-
通道交互:经过反向瓶颈层处理后,特征图被连接起来并通过 1x1 卷积。这最后一步促进了前面步骤中提取的不同尺度特征之间的交互,确保输出特征图包含丰富的多尺度表示。
-
多尺度表示效率:MS-Block 旨在平衡计算效率和捕获多尺度特征的能力。通过调整深度卷积中使用的分支数量和内核大小,可以优化该块以在对象检测任务中实现速度和准确性之间的更好权衡。
MS在实时对象检测中特别有用,因为速度和准确性都至关重要,因为它允许模型有效地学习和表示多个尺度的特征,同时保持较高的推理速度。
2. 将C2f_MSBlock添加到yolov8网络中
2.1 C2f_MSBlock代码实现
关键步骤一: 将下面代码粘贴到在/ultralytics/ultralytics/nn/modules/block.py中,并在该文件的__all__中添加“C2f_MSBlock”
class MSBlockLayer(nn.Module):
def __init__(self, inc, ouc, k) -> None:
super().__init__()
self.in_conv = Conv(inc, ouc, 1)
self.mid_conv = Conv(ouc, ouc, k, g=ouc)
self.out_conv = Conv(ouc, inc, 1)
def forward(self, x):
return self.out_conv(self.mid_conv(self.in_conv(x)))
class MSBlock(nn.Module):
def __init__(self, inc, ouc, kernel_sizes, in_expand_ratio=3., mid_expand_ratio=2., layers_num=3, in_down_ratio=2.) -> None:
super().__init__()
in_channel = int(inc * in_expand_ratio // in_down_ratio)
self.mid_channel = in_channel // len(kernel_sizes)
groups = int(self.mid_channel * mid_expand_ratio)
self.in_conv = Conv(inc, in_channel)
self.mid_convs = []
for kernel_size in kernel_sizes:
if kernel_size == 1:
self.mid_convs.append(nn.Identity())
continue
mid_convs = [MSBlockLayer(self.mid_channel, groups, k=kernel_size) for _ in range(int(layers_num))]
self.mid_convs.append(nn.Sequential(*mid_convs))
self.mid_convs = nn.ModuleList(self.mid_convs)
self.out_conv = Conv(in_channel, ouc, 1)
self.attention = None
def forward(self, x):
out = self.in_conv(x)
channels = []
for i,mid_conv in enumerate(self.mid_convs):
channel = out[:,i * self.mid_channel:(i+1) * self.mid_channel,...]
if i >= 1:
channel = channel + channels[i-1]
channel = mid_conv(channel)
channels.append(channel)
out = torch.cat(channels, dim=1)
out = self.out_conv(out)
if self.attention is not None:
out = self.attention(out)
return out
class C3_MSBlock(C3):
def __init__(self, c1, c2, n=1, kernel_sizes=[1, 3, 3], in_expand_ratio=3., mid_expand_ratio=2., layers_num=3, in_down_ratio=2., shortcut=False, g=1, e=0.5):
super().__init__(c1, c2, n, shortcut, g, e)
c_ = int(c2 * e) # hidden channels
self.m = nn.Sequential(*(MSBlock(c_, c_, kernel_sizes, in_expand_ratio, mid_expand_ratio, layers_num, in_down_ratio) for _ in range(n)))
class C2f_MSBlock(C2f):
def __init__(self, c1, c2, n=1, kernel_sizes=[1, 3, 3], in_expand_ratio=3., mid_expand_ratio=2., layers_num=3, in_down_ratio=2., shortcut=False, g=1, e=0.5):
super().__init__(c1, c2, n, shortcut, g, e)
self.m = nn.ModuleList(MSBlock(self.c, self.c, kernel_sizes, in_expand_ratio, mid_expand_ratio, layers_num, in_down_ratio) for _ in range(n))
2.2 C2f_MSBlock的神经网络模块代码解析
这段代码实现了一个多尺度特征提取模块,分为三个主要类:MSBlockLayer
、MSBlock
和 C2f_MSBlock
。以下是每个类的详细解释:
1. MSBlockLayer
类
-
功能: 实现一个基本的卷积层序列,用于处理特定尺度的特征图。
-
构造函数参数:
-
inc
: 输入通道数。 -
ouc
: 输出通道数。 -
k
: 卷积核大小。
-
-
构造函数内容:
-
self.in_conv
: 1x1卷积,用于调整输入通道数。 -
self.mid_conv
: 使用深度可分离卷积(group convolution)的中间卷积层,卷积核大小为k
。 -
self.out_conv
: 1x1卷积,将通道数还原为输入通道数。
-
-
forward
函数: 顺序执行in_conv
、mid_conv
和out_conv
,返回处理后的特征图。
2. MSBlock
类
-
功能: 实现一个多尺度特征块,包含多个
MSBlockLayer
组成的分支,每个分支对应不同的卷积核大小。 -
构造函数参数:
-
inc
: 输入通道数。 -
ouc
: 输出通道数。 -
kernel_sizes
: 卷积核大小的列表,用于指定每个分支的卷积核大小。 -
in_expand_ratio
: 输入通道扩展倍率。 -
mid_expand_ratio
: 中间通道扩展倍率。 -
layers_num
: 每个分支中MSBlockLayer
的层数。 -
in_down_ratio
: 输入通道缩减倍率。
-
-
构造函数内容:
-
in_channel
: 计算扩展后的输入通道数。 -
self.mid_channel
: 每个分支的通道数。 -
groups
: 深度卷积的组数(与通道数有关)。 -
self.in_conv
: 用于调整输入特征图通道数的卷积层。 -
self.mid_convs
: 一个包含多个分支的模块列表,每个分支使用不同的卷积核大小。 -
self.out_conv
: 用于将多分支输出融合成最终输出的1x1卷积。 -
self.attention
: 暂时未使用的注意力机制模块。
-
-
forward
函数: 先通过in_conv
处理输入,然后在各个分支中进行特征提取,最后通过拼接和卷积生成输出。如果定义了注意力机制,还会对输出进行进一步处理。
3. C2f_MSBlock
类
-
功能: 继承自
C2f
类,是一个容器类,用于在其中集成多个MSBlock
。 -
构造函数参数:
-
c1
: 输入通道数。 -
c2
: 输出通道数。 -
n
:MSBlock
的数量。 -
kernel_sizes
: 卷积核大小的列表。 -
其他参数 (
in_expand_ratio
,mid_expand_ratio
,layers_num
,in_down_ratio
,shortcut
,g
,e
): 用于配置MSBlock
和C2f
类的各种特性。
-
-
构造函数内容:
-
self.m
: 包含多个MSBlock
的模块列表,每个MSBlock
按照指定参数进行初始化。
-
总结
这个代码通过 MSBlockLayer
实现了基础的多尺度特征提取单元,再通过 MSBlock
将这些单元组合成多分支模块,每个分支负责提取不同尺度的特征。最后,C2f_MSBlock
类将多个 MSBlock
组合在一起,用于构建更复杂的多尺度特征提取网络。这种设计能够有效地捕捉图像中不同尺度的特征,提高模型的检测能力。
2.3 更改init.py文件
关键步骤二:修改modules文件夹下的__init__.py文件,先导入函数
然后在下面的__all__中声明函数
2.4 添加yaml文件
关键步骤三:在/ultralytics/ultralytics/cfg/models/v8下面新建文件yolov8_C2f_MSBlock.yaml文件,粘贴下面的内容
- OD【目标检测】
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
# [depth, width, max_channels]
n: [0.33, 0.25, 1024] # YOLOv8n summary: 225 layers, 3157200 parameters, 3157184 gradients, 8.9 GFLOPs
s: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients, 28.8 GFLOPs
m: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 GFLOPs
l: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
x: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs
# YOLOv8.0n backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 3, C2f_MSBlock, [128, [1, 3, 3], 3, 2, 3, 2]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 6, C2f_MSBlock, [256, [1, 5, 5], 3, 2, 3, 2]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f_MSBlock, [512, [1, 7, 7], 3, 2, 3, 2]]
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 3, C2f_MSBlock, [1024, [1, 9, 9], 3, 2, 3, 2]]
- [-1, 1, SPPF, [1024, 5]] # 9
# YOLOv8.0n head
head:
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2f, [512]] # 12
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2f, [256]] # 15 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 12], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 18 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P5
- [-1, 3, C2f, [1024]] # 21 (P5/32-large)
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
- RTDETR
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
# [depth, width, max_channels]
n: [0.33, 0.25, 1024] # YOLOv8n summary: 225 layers, 3157200 parameters, 3157184 gradients, 8.9 GFLOPs
s: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients, 28.8 GFLOPs
m: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 GFLOPs
l: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
x: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs
# YOLOv8.0n backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 3, C2f_MSBlock, [128, [1, 3, 3], 3, 2, 3, 2]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 6, C2f_MSBlock, [256, [1, 5, 5], 3, 2, 3, 2]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f_MSBlock, [512, [1, 7, 7], 3, 2, 3, 2]]
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 3, C2f_MSBlock, [1024, [1, 9, 9], 3, 2, 3, 2]]
- [-1, 1, SPPF, [1024, 5]] # 9
# YOLOv8.0n head
head:
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2f, [512]] # 12
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2f, [256]] # 15 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 12], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 18 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P5
- [-1, 3, C2f, [1024]] # 21 (P5/32-large)
- [[15, 18, 21], 1, RTDETRDecoder, [nc]] # Detect(P3, P4, P5)
- Seg【语义分割】
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
# [depth, width, max_channels]
n: [0.33, 0.25, 1024] # YOLOv8n summary: 225 layers, 3157200 parameters, 3157184 gradients, 8.9 GFLOPs
s: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients, 28.8 GFLOPs
m: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 GFLOPs
l: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
x: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs
# YOLOv8.0n backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 3, C2f_MSBlock, [128, [1, 3, 3], 3, 2, 3, 2]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 6, C2f_MSBlock, [256, [1, 5, 5], 3, 2, 3, 2]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f_MSBlock, [512, [1, 7, 7], 3, 2, 3, 2]]
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 3, C2f_MSBlock, [1024, [1, 9, 9], 3, 2, 3, 2]]
- [-1, 1, SPPF, [1024, 5]] # 9
# YOLOv8.0n head
head:
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2f, [512]] # 12
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2f, [256]] # 15 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 12], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 18 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P5
- [-1, 3, C2f, [1024]] # 21 (P5/32-large)
- [[15, 18, 21], 1, Segment, [nc, 32, 256]] # Segment(P3, P4, P5)
温馨提示:因为本文只是对yolov8基础上添加模块,如果要对yolov8n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。不明白的同学可以看这篇文章: yolov8yaml文件解读——点击即可跳转
# YOLOv8n
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # layer channel multiple
max_channels: 1024 # max_channels
# YOLOv8s
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
max_channels: 1024 # max_channels
# YOLOv8l
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
max_channels: 512 # max_channels
# YOLOv8m
depth_multiple: 0.67 # model depth multiple
width_multiple: 0.75 # layer channel multiple
max_channels: 768 # max_channels
# YOLOv8x
depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple
max_channels: 512 # max_channels
2.5 注册模块
关键步骤四:在task.py的parse_model函数中注册
2.6 执行程序
在train.py中,将model的参数路径设置为yolov8_C2f_MSBlock.yaml的路径
建议大家写绝对路径,确保一定能找到
from ultralytics import YOLO
import warnings
warnings.filterwarnings('ignore')
from pathlib import Path
if __name__ == '__main__':
# 加载模型
model = YOLO("ultralytics/cfg/v8/yolov8.yaml") # 你要选择的模型yaml文件地址
# Use the model
results = model.train(data=r"你的数据集的yaml文件地址",
epochs=100, batch=16, imgsz=640, workers=4, name=Path(model.cfg).stem) # 训练模型
🚀运行程序,如果出现下面的内容则说明添加成功🚀
from n params module arguments
0 -1 1 464 ultralytics.nn.modules.conv.Conv [3, 16, 3, 2]
1 -1 1 4672 ultralytics.nn.modules.conv.Conv [16, 32, 3, 2]
2 -1 1 6416 ultralytics.nn.modules.block.C2f_MSBlock [32, 32, 1, [1, 3, 3], 3, 2, 3, 2]
3 -1 1 18560 ultralytics.nn.modules.conv.Conv [32, 64, 3, 2]
4 -1 2 42816 ultralytics.nn.modules.block.C2f_MSBlock [64, 64, 2, [1, 5, 5], 3, 2, 3, 2]
5 -1 1 73984 ultralytics.nn.modules.conv.Conv [64, 128, 3, 2]
6 -1 2 165504 ultralytics.nn.modules.block.C2f_MSBlock [128, 128, 2, [1, 7, 7], 3, 2, 3, 2]
7 -1 1 295424 ultralytics.nn.modules.conv.Conv [128, 256, 3, 2]
8 -1 1 379008 ultralytics.nn.modules.block.C2f_MSBlock [256, 256, 1, [1, 9, 9], 3, 2, 3, 2]
9 -1 1 164608 ultralytics.nn.modules.block.SPPF [256, 256, 5]
10 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']
11 [-1, 6] 1 0 ultralytics.nn.modules.conv.Concat [1]
12 -1 1 148224 ultralytics.nn.modules.block.C2f [384, 128, 1]
13 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']
14 [-1, 4] 1 0 ultralytics.nn.modules.conv.Concat [1]
15 -1 1 37248 ultralytics.nn.modules.block.C2f [192, 64, 1]
16 -1 1 36992 ultralytics.nn.modules.conv.Conv [64, 64, 3, 2]
17 [-1, 12] 1 0 ultralytics.nn.modules.conv.Concat [1]
18 -1 1 123648 ultralytics.nn.modules.block.C2f [192, 128, 1]
19 -1 1 147712 ultralytics.nn.modules.conv.Conv [128, 128, 3, 2]
20 [-1, 9] 1 0 ultralytics.nn.modules.conv.Concat [1]
21 -1 1 493056 ultralytics.nn.modules.block.C2f [384, 256, 1]
22 [15, 18, 21] 1 897664 ultralytics.nn.modules.head.Detect [80, [64, 128, 256]]
YOLOv8_C2f_MSBlock summary: 609 layers, 3036000 parameters, 3035984 gradients, 8.6 GFLOPs
3. 完整代码分享
https://pan.baidu.com/s/1CYdp-yXZZFv0ye9sDEZw2w?pwd=vwri
提取码: vwri
4. GFLOPs
关于GFLOPs的计算方式可以查看:百面算法工程师 | 卷积基础知识——Convolution
未改进的YOLOv8nGFLOPs
改进后的GFLOPs
5. 进阶
可以与其他的注意力机制或者损失函数等结合,进一步提升检测效果
6. 总结
Multi-Scale Block (MS-Block) 是一种旨在增强实时目标检测中多尺度特征表示能力的核心组件。它通过分层特征融合策略,将输入特征图分成多个分支,并利用倒置瓶颈结构中的深度可分离卷积对不同分支进行处理。每个分支采用不同大小的卷积核,以有效捕捉不同尺度的特征,同时控制计算开销。之后,这些分支的输出会被拼接,并通过一个1x1卷积层进行通道间的交互,从而整合多尺度信息,生成具有丰富特征表示的输出特征图。MS-Block的设计重点在于在保持计算效率的同时,显著提高多尺度特征的捕捉能力,从而在实时目标检测中实现速度与精度的平衡。