YOLO11 改进 – 主干网络_ LSKNet大型选择性核网络:大核深度卷积与空间选择机制协同动态调整感受野,增强旋转目标检测
前言
本文介绍了将大型选择性核网络(LSKNet)与YOLOv11相结合的方法。LSKNet引入了LSKblock Attention注意力机制,能动态调整感受野,适应不同目标的上下文特征。该网络由LSK module、LSK Block等组成,通过解耦大核卷积和空间选择机制,有效处理不同目标的广泛上下文。我们将LSKNet引入YOLOv11,对相关代码进行修改和注册,并配置了yolov11 - LSKNet.yaml文件。通过实验脚本进行训练,结果显示该结合方式在目标检测任务中具有一定效果。
文章目录: YOLOv11改进大全:卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总
专栏链接: YOLOv11改进专栏
文章目录
[TOC]
介绍
摘要
近期遥感目标检测研究主要聚焦于提升定向边界框的表征能力,然而普遍忽视了遥感场景中特有的先验知识体系。此类先验知识具有重要价值,因为在缺乏充分长范围上下文参考的情况下,微小遥感目标易出现误检现象,且不同类型目标所需的长范围上下文特征存在显著差异。针对这一问题,本文充分考虑上述先验知识,创新性地提出了大型选择性核网络(LSKNet)。该网络能够动态调整其大尺度空间感受野,从而更精确地建模遥感场景中各类目标的上下文范围特征。据我们所知,这是首次在遥感目标检测领域系统探索大型选择性核机制的研究工作。在无需引入额外复杂设计的前提下,我们提出的轻量级LSKNet架构在标准遥感图像分类、目标检测及语义分割基准测试中均实现了新的最先进性能水平。
创新点
-
LSKblock Attention :LSKNet引入了LSKblock Attention作为一种注意力机制,通过空间选择性机制动态调整感受野,以更有效地处理不同目标类型的广泛上下文。这种机制允许模型根据输入自适应地确定大型核的权重,从而在空间维度上调整每个目标的感受野。
-
大型选择性核网络 :LSKNet是首个在遥感目标检测领域探索大型和选择性核机制的模型。它通过加权处理大型深度核的特征,并在空间上将它们合并,以适应不同目标类型的不同上下文细微差异。
-
适应性感受野调整 :LSKNet能够动态调整感受野以更好地模拟远程感知场景中各种对象的范围上下文,从而更有效地处理不同目标类型的广泛上下文。
-
性能优越 :LSKNet在标准基准数据集上取得了新的最先进成绩,如HRSC2016、DOTA-v1.0和FAIR1M-v1.0,证明了其在遥感目标检测任务中的卓越性能和有效性。
文章链接
论文地址: 论文地址
代码地址: 代码地址
基本原理
LSKNet的结构
LSKNet的结构包括以下几个关键组成部分:
-
LSK module :LSK module是LSKNet中的一个重要组件,由大核卷积序列和空间选择机制组成。大核卷积序列用于捕获长距离上下文信息,而空间选择机制则根据输入数据动态调整大核的权重,以适应不同目标类型的上下文特征。
-
LSK Block :LSK Block是LSKNet的基本构建块,由LK Selection和FFN两个子块组成。LK Selection子块用于动态调整网络的感受野,而FFN子块用于通道混合和特征细化。每个LSK Block包含一个LSK module,用于处理特征提取和空间选择。
-
LSKNet :LSKNet由多个LSK Block组成,每个LSK Block都包含一个LSK module。整个网络结构通过堆叠多个LSK Block来构建,以实现对不同目标类型的广泛上下文的有效建模和处理。LSKNet利用这种层级结构和空间选择机制,能够适应不同目标的特征和上下文需求,从而在遥感目标检测任务中取得优越性能。
3.2 大核卷积
因为不同类型的目标对背景信息的需求不同,这就需要模型能够自适应选择不同大小的背景范围。因此,作者通过解耦出一系列具有大卷积核、且不断扩张的Depth-wise 卷积,构建了一个更大感受野的网络。具体来说,序列中第i个深度卷积的核大小 $k_i$ 、膨胀率 $d_i$ 以及接收场 $RF_i$ 的扩展定义如下:
$$ k_{i-1} \leq k_i; \quad d1 = 1, \quad d{i-1} < di \leq RF{i-1}, \quad (1) $$
$$ RF_1 = k_1, \quad RF_i = d_i(ki - 1) + RF{i-1}. \quad (2) $$
核大小和膨胀率的增加确保了接收场足够快地扩展。我们设定膨胀率的上限以保证膨胀卷积不会在特征图之间引入间隙。例如,我们可以将一个大核分解为2个或3个深度卷积,如表2所示,它们分别具有23和29的理论接收场。
这种设计有两个优点。首先,它明确产生了具有不同大接收场的多个特征,这使得后来的核选择更加容易。其次,序列分解比简单应用一个更大的核更有效率。如表2所示,在相同的理论接收场下,我们的分解大大减少了与标准大核卷积相比的参数数量。为了从不同范围获取富含上下文信息的特征,对输入 $X$ 应用一系列不同接收场的分解深度卷积:
$$ U0 = X, \quad U{i+1} = F^{dw}_i(U_i), \quad (3) $$
其中 $F^{dw}_i(\cdot)$ 是具有核 $k_i$ 和膨胀 $d_i$ 的深度卷积。假设有 $N$ 个分解核,每一个都通过一个 $1 \times 1$ 卷积层 $F^{1 \times 1}(\cdot)$ 进一步处理:
$$ \widetilde{U}_i = F^{1 \times 1}_i(U_i), \quad \text{对于} \quad i \in [1, N], \quad (4) $$
允许每个空间特征向量的通道混合。然后,提出了一种选择机制,基于获得的多尺度特征动态选择不同对象的核,接下来将介绍这一点。
3.3 空间核选择
为了增强网络关注最相关的空间上下文区域以检测目标的能力,我们使用一个空间选择机制,在不同尺度上从大核卷积中空间选择特征图。首先,我们将从不同核获得的具有不同接收范围的特征进行连接:
$$ \widetilde{U} = [\widetilde{U}_1; \ldots; \widetilde{U}_i], \quad (5) $$
然后通过应用基于通道的平均和最大池化(表示为 $P{avg}(\cdot)$ 和 $P{max}(\cdot)$ )到 $~\widetilde{U}$ 上,高效提取空间关系:
$$ SA{avg} = P{avg}(\widetilde{U}), \quad SA{max} = P{max}(\widetilde{U}), \quad (6) $$
其中 $SA{avg}$ 和 $SA{max}$ 是平均和最大池化的空间特征描述符。为了允许不同空间描述符之间的信息交互,我们将空间池化特征进行连接,并使用一个卷积层 $F^{2 \rightarrow N}(\cdot)$ 将池化特征(有2个通道)转换为 $N$ 个空间注意力图:
$$ \hat{SA} = F^{2 \rightarrow N}([SA{avg}; SA{max}]). \quad (7) $$
对于每一个空间注意力图 $\hat{SA}_i$ ,应用sigmoid激活函数以获得每个分解大核对应的个体空间选择掩模:
$$ \widetilde{SA}_i = \sigma(\hat{SA}_i), \quad (8)
$$
其中 $\sigma(\cdot)$ 表示sigmoid函数。然后,通过其相应的空间选择掩模加权分解大核序列的特征,并通过一个卷积层 $F(\cdot)$ 融合,以获得注意力特征 $S$ :
$$ S = F\left(\sum_{i=1}^N (\widetilde{SA}_i \cdot \widetilde{U}_i)\right). \quad (9) $$
LSK(大核选择)模块的最终输出是输入特征 $X$ 与 $S$ 的元素级乘积,与文献[17, 18, 25]中相似:
$$ Y = X \cdot S. \quad (10) $$
核心代码
class LSKNet(nn.Module):
def __init__(self, img_size=224, in_chans=3, embed_dims=[64, 128, 256, 512],
mlp_ratios=[8, 8, 4, 4], drop_rate=0., drop_path_rate=0., norm_layer=partial(nn.LayerNorm, eps=1e-6),
depths=[3, 4, 6, 3], num_stages=4,
norm_cfg=None):
super().__init__()
self.depths = depths
self.num_stages = num_stages
dpr = [x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))] # stochastic depth decay rule
cur = 0
for i in range(num_stages):
patch_embed = OverlapPatchEmbed(img_size=img_size if i == 0 else img_size // (2 ** (i + 1)),
patch_size=7 if i == 0 else 3,
stride=4 if i == 0 else 2,
in_chans=in_chans if i == 0 else embed_dims[i - 1],
embed_dim=embed_dims[i], norm_cfg=norm_cfg)
block = nn.ModuleList([Block(
dim=embed_dims[i], mlp_ratio=mlp_ratios[i], drop=drop_rate, drop_path=dpr[cur + j],norm_cfg=norm_cfg)
for j in range(depths[i])])
norm = norm_layer(embed_dims[i])
cur += depths[i]
setattr(self, f"patch_embed{i + 1}", patch_embed)
setattr(self, f"block{i + 1}", block)
setattr(self, f"norm{i + 1}", norm)
self.channel = [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]
def forward(self, x):
B = x.shape[0]
outs = []
for i in range(self.num_stages):
patch_embed = getattr(self, f"patch_embed{i + 1}")
block = getattr(self, f"block{i + 1}")
norm = getattr(self, f"norm{i + 1}")
x, H, W = patch_embed(x)
for blk in block:
x = blk(x)
x = x.flatten(2).transpose(1, 2)
x = norm(x)
x = x.reshape(B, H, W, -1).permute(0, 3, 1, 2).contiguous()
outs.append(x)
return outs
实验
脚本
import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO
if __name__ == '__main__':
# 修改为自己的配置文件地址
model = YOLO('/root/ultralytics-main/ultralytics/cfg/models/11/yolov11-LSKNet.yaml')
# 修改为自己的数据集地址
model.train(data='/root/ultralytics-main/ultralytics/cfg/datasets/coco8.yaml',
cache=False,
imgsz=640,
epochs=10,
single_cls=False, # 是否是单类别检测
batch=8,
close_mosaic=10,
workers=0,
optimizer='SGD',
amp=True,
project='runs/train',
name='LSKNet',
)