一、本文介绍
本文记录的是基于FCAttention模块的YOLOv10目标检测改进方法研究。FCAttention
是图像去雾领域新提出的模块能够有效整合全局和局部信息、合理分配权重的通道注意力机制,使得网络能够更准确地强调有用特征,抑制不太有用的特征,在目标检测领域中同样有效。
文章目录
- 一、本文介绍
- 二、FCA原理
- 2.1 原理
- 2.2 优势
- 三、FCAttention的实现代码
- 四、创新模块
- 4.1 改进点1
- 4.2 改进点2⭐
- 五、添加步骤
- 5.1 修改ultralytics/nn/modules/block.py
- 5.2 修改ultralytics/nn/modules/__init__.py
- 5.3 修改ultralytics/nn/modules/tasks.py
- 六、yaml模型文件
- 6.1 模型改进版本一
- 6.2 模型改进版本二⭐
- 七、成功运行结果
二、FCA原理
用于图像去雾的无监督双向对比重建和自适应细粒度通道注意网络
FCA(Adaptive Fine - Grained Channel Attention)
模块设计的原理及优势如下:
2.1 原理
- 特征图处理:首先,对包含全局空间信息的特征图F进行全局平均池化,将其转换为通道描述符U,用于获取通道信息。具体公式为: U n = G A P ( F n ) = 1 H × W ∑ i = 1 H ∑ j = 1 W F n ( i , j ) U_{n}=GAP(F_{n})=\frac{1}{H×W}\sum_{i=1}^{H}\sum_{j=1}^{W}F_{n}(i, j) Un=GAP(Fn)=H×W1∑i=1H∑j=1WFn(i,j),其中 F ∈ R C × H × W F \in \mathbb{R}^{C×H×W} F∈RC×H×W, C C C、 H H H和 W W W分别代表通道数、长度和宽度, U ∈ R C U \in \mathbb{R}^{C} U∈RC, G A P ( x ) GAP(x) GAP(x)为全局平均 pooling 函数。
- 局部信息获取:为了在获取少量模型参数的同时获得局部通道信息,使用带矩阵B进行局部通道交互,设置 B = [ b 1 , b 2 , b 3 , . . . , b k ] B=[b_{1}, b_{2}, b_{3},..., b_{k}] B=[b1,b2,b3,...,bk],通过 U l c = ∑ i = 1 k U ⋅ b i U_{lc}=\sum_{i=1}^{k}U\cdot b_{i} Ulc=∑i=1kU⋅bi计算局部信息 U l c U_{lc} Ulc,其中 U U U为通道描述符, k k k为相邻通道数。
- 全局信息获取:利用对角矩阵D捕获所有通道之间的依赖关系作为全局信息,设置 D = [ d 1 , d 2 , d 3 , . . . , d c ] D=[d_{1}, d_{2}, d_{3},..., d_{c}] D=[d1,d2,d3,...,dc],通过 U g c = ∑ i = 1 c U ⋅ d i U_{gc}=\sum_{i=1}^{c}U\cdot d_{i} Ugc=∑i=1cU⋅di计算全局信息 U g c U_{gc} Ugc,其中 c c c为通道数。
- 相关性捕获:通过交叉相关操作将全局信息 U g c U_{gc} Ugc与局部信息 U l c U_{lc} Ulc相结合,得到相关性矩阵 M = U g c ⋅ U l c T M = U_{gc}\cdot U_{lc}^{T} M=Ugc⋅UlcT,以捕获两者在不同粒度上的相关性。
- 自适应融合:从相关性矩阵及其转置中提取行和列信息作为全局和局部信息的权重向量,通过可学习因子实现动态融合。具体公式为: U g c w = ∑ j c M i , j , i ∈ 1 , 2 , 3... c U_{gc}^{w}=\sum_{j}^{c}M_{i, j}, i \in 1,2,3...c Ugcw=∑jcMi,j,i∈1,2,3...c, U l c w = ∑ j c ( U l c ⋅ U g c T ) i , j = ∑ j c M i , j T , i ∈ 1 , 2 , 3... c U_{lc}^{w}=\sum_{j}^{c}(U_{lc}\cdot U_{gc}^{T})_{i, j}=\sum_{j}^{c}M^{T}_{i, j}, i \in 1,2,3...c Ulcw=∑jc(Ulc⋅UgcT)i,j=∑jcMi,jT,i∈1,2,3...c, W = σ ( σ ( θ ) × σ ( U g c w ) + ( 1 − σ ( θ ) ) × σ ( U l c w ) ) W=\sigma(\sigma(\theta)×\sigma(U_{gc}^{w})+(1 - \sigma(\theta))×\sigma(U_{lc}^{w})) W=σ(σ(θ)×σ(Ugcw)+(1−σ(θ))×σ(Ulcw)),其中KaTeX parse error: Can't use function '\)' in math mode at position 11: U_{gc}^{w}\̲)̲和\(U_{lc}^{w}为融合后的全局和局部通道权重, θ \theta θ表示sigmoid激活函数。
- 权重应用:将得到的权重与输入特征图相乘,得到最终输出特征图,即 τ ∗ = W ⊗ F \tau^{*}=W \otimes F τ∗=W⊗F,其中 F F F为输入特征图, F ∗ F^{*} F∗为最终输出特征图。
2.2 优势
- 有效整合信息:能够有效整合全局和局部信息,通过相关性矩阵捕获两者在不同粒度上的相关性,促进了全局和局部信息的有效交互。
- 合理分配权重:采用自适应融合策略,避免了局部和全局信息之间冗余的交叉相关操作,进一步促进了它们的交互,能够更精确地为去雾相关特征分配权重。
- 提升去雾性能:在网络去雾过程中,充分利用全局和局部通道信息,提高了网络去雾性能,使得网络能够更准确地强调有用特征,抑制不太有用的特征。
论文:https://doi.org/10.1016/j.neunet.2024.106314
源码:https://github.com/Lose-Code/UBRFC-Net
三、FCAttention的实现代码
FCAttention模块
的实现代码如下:
class Mix(nn.Module):def __init__(self, m=-0.80):super(Mix, self).__init__()w = torch.nn.Parameter(torch.FloatTensor([m]), requires_grad=True)w = torch.nn.Parameter(w, requires_grad=True)self.w = wself.mix_block = nn.Sigmoid()def forward(self, fea1, fea2):mix_factor = self.mix_block(self.w)out = fea1 * mix_factor.expand_as(fea1) + fea2 * (1 - mix_factor.expand_as(fea2))return outclass FCAttention(nn.Module):def __init__(self,channel,b=1, gamma=2):super(FCAttention, self).__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1)#全局平均池化#一维卷积t = int(abs((math.log(channel, 2) + b) / gamma))k = t if t % 2 else t + 1self.conv1 = nn.Conv1d(1, 1, kernel_size=k, padding=int(k / 2), bias=False)self.fc = nn.Conv2d(channel, channel, 1, padding=0, bias=True)self.sigmoid = nn.Sigmoid()self.mix = Mix()def forward(self, input):x = self.avg_pool(input)x1 = self.conv1(x.squeeze(-1).transpose(-1, -2)).transpose(-1, -2)#(1,64,1)x2 = self.fc(x).squeeze(-1).transpose(-1, -2)#(1,1,64)out1 = torch.sum(torch.matmul(x1,x2),dim=1).unsqueeze(-1).unsqueeze(-1)#(1,64,1,1)#x1 = x1.transpose(-1, -2).unsqueeze(-1)out1 = self.sigmoid(out1)out2 = torch.sum(torch.matmul(x2.transpose(-1, -2),x1.transpose(-1, -2)),dim=1).unsqueeze(-1).unsqueeze(-1)#out2 = self.fc(x)out2 = self.sigmoid(out2)out = self.mix(out1,out2)out = self.conv1(out.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1)out = self.sigmoid(out)return input*out
四、创新模块
4.1 改进点1
模块改进方法1️⃣:直接加入FCAttention模块
。
FCAttention模块
添加后如下:
注意❗:在5.2和5.3小节
中需要声明的模块名称为:FCAttention
。
4.2 改进点2⭐
模块改进方法2️⃣:基于FCAttention模块
的C2f
。
第二种改进方法是对YOLOv10
中的C2f模块
进行改进,将FCAttention注意力模块
加入后,能够充分利用全局和局部通道信息,使得网络能够更准确地强调有用特征,抑制不太有用的特征。并且其中的自适应融合策略,避免了局部和全局信息之间冗余的交叉相关操作,进一步促进了它们的交互,能够更精确地进行特征分配权重。
改进代码如下:
class C2f_FCA(nn.Module):"""Faster Implementation of CSP Bottleneck with 2 convolutions."""def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):"""Initialize CSP bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups,expansion."""super().__init__()self.c = int(c2 * e) # hidden channelsself.cv1 = Conv(c1, 2 * self.c, 1, 1)self.cv2 = Conv((2 + n) * self.c, c2, 1) # optional act=FReLU(c2)self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))self.att = FCAttention(c2)def forward(self, x):"""Forward pass through C2f layer."""y = list(self.cv1(x).chunk(2, 1))y.extend(m(y[-1]) for m in self.m)return self.att(self.cv2(torch.cat(y, 1)))def forward_split(self, x):"""Forward pass using split() instead of chunk()."""y = list(self.cv1(x).split((self.c, self.c), 1))y.extend(m(y[-1]) for m in self.m)return self.att(self.cv2(torch.cat(y, 1)))
注意❗:在5.2和5.3小节
中需要声明的模块名称为:C2f_FCA
。
五、添加步骤
5.1 修改ultralytics/nn/modules/block.py
此处需要修改的文件是ultralytics/nn/modules/block.py
block.py中定义了网络结构的通用模块
,我们想要加入新的模块就只需要将模块代码放到这个文件内即可。
将FCAttention
和C2f_FCA
模块代码添加到此文件下。
5.2 修改ultralytics/nn/modules/init.py
此处需要修改的文件是ultralytics/nn/modules/__init__.py
__init__.py
文件中定义了所有模块的初始化,我们只需要将block.py
中的新的模块命添加到对应的函数即可。
FCAttention
和C2f_FCA
在block.py
中实现,所有要添加在from .block import
:
from .block import (C1,C2,...FCAttention,C2f_FCA
)
5.3 修改ultralytics/nn/modules/tasks.py
在tasks.py
文件中,需要在两处位置添加各模块类名称。
首先:在函数声明中引入FCAttention
和C2f_FCA
其次:在parse_model函数
中注册FCAttention
和C2f_FCA
模块
六、yaml模型文件
6.1 模型改进版本一
在代码配置完成后,配置模型的YAML文件。
此处以ultralytics/cfg/models/v10/yolov10m.yaml
为例,在同目录下创建一个用于自己数据集训练的模型文件yolov10m-FCA.yaml
。
将yolov10m.yaml
中的内容复制到yolov10m-FCA.yaml
文件下,修改nc
数量等于自己数据中目标的数量。
在骨干网络的最后一层添加FCAttention模块
,只需要填入一个参数,通道数。
# 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: 1 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'# [depth, width, max_channels]m: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 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, [128, True]]- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8- [-1, 6, C2f, [256, True]]- [-1, 1, SCDown, [512, 3, 2]] # 5-P4/16- [-1, 6, C2f, [512, True]]- [-1, 1, SCDown, [1024, 3, 2]] # 7-P5/32- [-1, 3, C2fCIB, [1024, True]]- [-1, 1, FCAttention, [1024]]- [-1, 1, SPPF, [1024, 5]] # 10- [-1, 1, PSA, [1024]] # 11# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 6], 1, Concat, [1]] # cat backbone P4- [-1, 3, C2f, [512]] # 14- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 4], 1, Concat, [1]] # cat backbone P3- [-1, 3, C2f, [256]] # 17 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 14], 1, Concat, [1]] # cat head P4- [-1, 3, C2fCIB, [512, True]] # 20 (P4/16-medium)- [-1, 1, SCDown, [512, 3, 2]]- [[-1, 11], 1, Concat, [1]] # cat head P5- [-1, 3, C2fCIB, [1024, True]] # 23 (P5/32-large)- [[17, 20, 23], 1, v10Detect, [nc]] # Detect(P3, P4, P5)
6.2 模型改进版本二⭐
此处同样以ultralytics/cfg/models/v10/yolov10m.yaml
为例,在同目录下创建一个用于自己数据集训练的模型文件yolov10m-C2f_FCA.yaml
。
将yolov10m.yaml
中的内容复制到yolov10m-C2f_FCA.yaml
文件下,修改nc
数量等于自己数据中目标的数量。
📌 模型的修改方法是将骨干网络中的所有C2f模块
替换成C2f_FCA模块
。
# 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: 1 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'# [depth, width, max_channels]m: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 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_FCA, [128, True]]- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8- [-1, 6, C2f_FCA, [256, True]]- [-1, 1, SCDown, [512, 3, 2]] # 5-P4/16- [-1, 6, C2f_FCA, [512, True]]- [-1, 1, SCDown, [1024, 3, 2]] # 7-P5/32- [-1, 3, C2fCIB, [1024, True]]- [-1, 1, SPPF, [1024, 5]] # 9- [-1, 1, PSA, [1024]] # 10# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 6], 1, Concat, [1]] # cat backbone P4- [-1, 3, C2f, [512]] # 13- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 4], 1, Concat, [1]] # cat backbone P3- [-1, 3, C2f, [256]] # 16 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 13], 1, Concat, [1]] # cat head P4- [-1, 3, C2fCIB, [512, True]] # 19 (P4/16-medium)- [-1, 1, SCDown, [512, 3, 2]]- [[-1, 10], 1, Concat, [1]] # cat head P5- [-1, 3, C2fCIB, [1024, True]] # 22 (P5/32-large)- [[16, 19, 22], 1, v10Detect, [nc]] # Detect(P3, P4, P5)
七、成功运行结果
分别打印网络模型可以看到FCA模块
和C2f_FCA
已经加入到模型中,并可以进行训练了。
yolov10m-FCA:
from n params module arguments 0 -1 1 1392 ultralytics.nn.modules.conv.Conv [3, 48, 3, 2] 1 -1 1 41664 ultralytics.nn.modules.conv.Conv [48, 96, 3, 2] 2 -1 2 111360 ultralytics.nn.modules.block.C2f [96, 96, 2, True] 3 -1 1 166272 ultralytics.nn.modules.conv.Conv [96, 192, 3, 2] 4 -1 4 813312 ultralytics.nn.modules.block.C2f [192, 192, 4, True] 5 -1 1 78720 ultralytics.nn.modules.block.SCDown [192, 384, 3, 2] 6 -1 4 3248640 ultralytics.nn.modules.block.C2f [384, 384, 4, True] 7 -1 1 228672 ultralytics.nn.modules.block.SCDown [384, 576, 3, 2] 8 -1 2 1689984 ultralytics.nn.modules.block.C2fCIB [576, 576, 2, True] 9 -1 1 332646 ultralytics.nn.modules.block.FCAttention [576, 576] 10 -1 1 831168 ultralytics.nn.modules.block.SPPF [576, 576, 5] 11 -1 1 1253088 ultralytics.nn.modules.block.PSA [576, 576] 12 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] 13 [-1, 6] 1 0 ultralytics.nn.modules.conv.Concat [1] 14 -1 2 1993728 ultralytics.nn.modules.block.C2f [960, 384, 2] 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] 16 [-1, 4] 1 0 ultralytics.nn.modules.conv.Concat [1] 17 -1 2 517632 ultralytics.nn.modules.block.C2f [576, 192, 2] 18 -1 1 332160 ultralytics.nn.modules.conv.Conv [192, 192, 3, 2] 19 [-1, 14] 1 0 ultralytics.nn.modules.conv.Concat [1] 20 -1 2 831744 ultralytics.nn.modules.block.C2fCIB [576, 384, 2, True] 21 -1 1 152448 ultralytics.nn.modules.block.SCDown [384, 384, 3, 2] 22 [-1, 11] 1 0 ultralytics.nn.modules.conv.Concat [1] 23 -1 2 1911168 ultralytics.nn.modules.block.C2fCIB [960, 576, 2, True] 24 [17, 20, 23] 1 2282134 ultralytics.nn.modules.head.v10Detect [1, [192, 384, 576]]
YOLOv10m-FCA summary: 505 layers, 16817932 parameters, 16817916 gradients, 64.0 GFLOPs
yolov10m-C2f_FCA:
from n params module arguments 0 -1 1 1392 ultralytics.nn.modules.conv.Conv [3, 48, 3, 2] 1 -1 1 41664 ultralytics.nn.modules.conv.Conv [48, 96, 3, 2] 2 -1 2 148808 ultralytics.nn.modules.block.C2f_FCA [96, 96, True] 3 -1 1 166272 ultralytics.nn.modules.conv.Conv [96, 192, 3, 2] 4 -1 4 1185048 ultralytics.nn.modules.block.C2f_FCA [192, 192, True] 5 -1 1 78720 ultralytics.nn.modules.block.SCDown [192, 384, 3, 2] 6 -1 4 4729368 ultralytics.nn.modules.block.C2f_FCA [384, 384, True] 7 -1 1 228672 ultralytics.nn.modules.block.SCDown [384, 576, 3, 2] 8 -1 2 1689984 ultralytics.nn.modules.block.C2fCIB [576, 576, 2, True] 9 -1 1 831168 ultralytics.nn.modules.block.SPPF [576, 576, 5] 10 -1 1 1253088 ultralytics.nn.modules.block.PSA [576, 576] 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] 12 [-1, 6] 1 0 ultralytics.nn.modules.conv.Concat [1] 13 -1 2 1993728 ultralytics.nn.modules.block.C2f [960, 384, 2] 14 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] 15 [-1, 4] 1 0 ultralytics.nn.modules.conv.Concat [1] 16 -1 2 517632 ultralytics.nn.modules.block.C2f [576, 192, 2] 17 -1 1 332160 ultralytics.nn.modules.conv.Conv [192, 192, 3, 2] 18 [-1, 13] 1 0 ultralytics.nn.modules.conv.Concat [1] 19 -1 2 831744 ultralytics.nn.modules.block.C2fCIB [576, 384, 2, True] 20 -1 1 152448 ultralytics.nn.modules.block.SCDown [384, 384, 3, 2] 21 [-1, 10] 1 0 ultralytics.nn.modules.conv.Concat [1] 22 -1 2 1911168 ultralytics.nn.modules.block.C2fCIB [960, 576, 2, True] 23 [16, 19, 22] 1 2282134 ultralytics.nn.modules.head.v10Detect [1, [192, 384, 576]]
YOLOv10m-C2f_FCA summary: 627 layers, 18375198 parameters, 18375182 gradients, 70.7 GFLOPs