公司动态

YOLO26轻量化改进:LSB模块原理与实战部署

📅 2026/9/2 6:01:05
YOLO26轻量化改进:LSB模块原理与实战部署
之前在自己的检测项目里尝试给 YOLO 系列做轻量化改进时一直绕不开两个问题浅层位置信息丰富但语义不足深层语义强但细节丢失。常见的特征金字塔虽然缓解了一部分问题但在小目标和低光场景下仍然不够稳定。最近看到 CVPR 2025 nnWNet 中提出的 LSB 模块核心思路是“局部特征连续传输”结构轻量、不依赖复杂算子可以直接插入 YOLO26 的 neck 或者 backbone 后部。本文把这套改进思路完整梳理了一遍包含模块设计原理、YOLO26 接入方式、训练与部署注意事项适合正在做 YOLO 系列改进、目标检测竞赛或工程落地的开发者。1. 背景与核心概念1.1 YOLO26 改进为什么值得关注YOLO 系列一直是目标检测领域落地最方便的一类框架。YOLO26 作为新版本整体结构延续了 anchor-free、多尺度检测头、CSP 风格骨干网络等设计但它依然面临一个长期存在的矛盾网络加深之后深层特征图分辨率低小目标细节信息不足浅层特征图虽然分辨率高却缺少足够的语义上下文。很多改进思路都在尝试解决这个矛盾比如在 neck 中增加跨尺度连接加强特征融合。引入注意力机制让网络更关注重要区域。使用更复杂的特征金字塔结构例如 BiFPN、ASFF。这些方法有效果但也带来一些问题结构变复杂、部署不友好、训练收敛变慢。尤其是把模型部署到 RK3588 这类边缘设备时太复杂的算子会明显拉低推理速度。LSB 模块的设计思路跟上面几种不太一样。它不追求在某一层做“大融合”而是把局部特征沿着网络逐层连续传输让每一层都能同时保留细节和语义。这个思路实现起来不复杂却非常适合工程调整。1.2 nnWNet 与 LSB 模块先说明一下命名避免产生误解。LSB 这个名字在计算机领域通常会联想到“最低有效位”但在 nnWNet 这篇工作里LSB 指的是局部连续传输模块论文中强调的核心点是“局部特征连续传输即插即用”。nnWNet 是 CVPR 2025 上的一个检测网络工作重心放在多尺度窗口交互与连续特征传递上。LSB 模块从 nnWNet 中提炼出来之后可以脱离原网络单独使用这也是“即插即用”的由来。LSB 模块的核心可以概括成一句话把局部特征以连续的、逐层传递的方式送入后续网络层而不是只靠某一次 concat 或者 add 来融合。这样做有几个好处局部细节信息不会在深层特征图里被“冲淡”。模块本身是卷积和逐元素操作组合没有自定义算子方便导出 ONNX也方便 RK3588 这类边缘设备部署。插入位置灵活既可以放在 backbone 末端也可以放在 neck 的多个分支上。1.3 适用场景LSB 模块比较适合以下几类场景小目标检测小目标主要依赖浅层细节LSB 能把这些细节持续传递到检测头。低光环境检测低光图像纹理弱需要网络在保留弱细节的同时增强语义判别力。边缘设备部署模块不引入复杂算子对量化、RKNN 转换比较友好。已有 YOLO26 训练流程的快速改进不需要从零重写检测框架只需要加模块、改配置。2. LSB 模块设计原理拆解2.1 局部特征连续传输的含义要理解 LSB可以把特征传递分为两种方式。第一种是单点融合。比如某个特征图经过一次卷积后直接与另一个特征图相加或拼接。这种方式实现简单但融合只发生一次后续层再想获取局部信息就只能依赖融合后的结果细节可能已经损失了一部分。第二种是连续传输。局部特征不只在某一层出现一次而是沿着网络路径逐层传递下去。每一层在接收主干特征的同时也会接收来自前一层传递过来的局部特征。这样即使在深层特征图上依然能保留清晰的局部纹路和边缘信息。LSB 模块做的就是第二种。它内部拆成两个分支局部分支负责提取当前层的细节特征传输分支负责把上一模块传递过来的局部信息继续向后传递。两个分支在模块内部进行轻量交互最终输出同时包含“当前层语义”和“历史局部细节”。2.2 模块组成从代码实现角度看LSB 模块可以拆成三个部分局部特征提取分支 使用小卷积核提取当前特征图上的局部模式例如边缘、角点、纹路。这部分输出的空间分辨率与输入一致。连续传输分支 接收上一个 LSB 模块传来的局部特征通过 1x1 卷积或恒等映射继续向后传递。这一步的作用是避免细节信息在多次卷积之后消失。语义融合节点 将局部分支输出和传输分支输出进行融合。融合方式可以根据计算资源选择相加、拼接或者带权相加。这里需要补充一点LSB 模块本身是一个模块设计思想不同的论文复现实现会有细节差异。本文给出的实现是面向 YOLO26 改造的简化版本重点演示如何接入而不是完全复刻论文源码。2.3 与注意力机制的区别有人可能会问SE 模块、CBAM 也是在加强特征表达LSB 和它们有什么不同SE 和 CBAM 的核心是“特征重标定”也就是学习权重告诉网络哪些通道或空间位置更重要。它们不改变特征的传递路径。LSB 的核心是“特征传递路径重构”它把局部特征从一条容易被深层卷积“淹没”的路径上拆出来单独维护一条连续传递的路径。所以 LSB 和注意力模块并不冲突。实际改进时可以先加 LSB 传递细节再配合注意力模块增强关键区域表达。不过要控制模块数量否则训练收敛速度和推理速度都会受影响。3. 环境准备与版本说明3.1 基础环境本文的示例以 YOLO26 训练流程为基础。YOLO26 相关源码目前更新比较快不同仓库的代码结构有差异所以下面的环境版本只作为参考实际使用时以你自己的仓库依赖为准。推荐环境如下操作系统Ubuntu 20.04 或 Windows 10/11Python3.8 或 3.10PyTorch1.13 或 2.xCUDA11.7 或更高GPU 训练时深度学习框架Ultralytics YOLO 系列或其他兼容 YOLO26 结构的学习框架如果你是在 CPU 环境下做验证也可以运行但训练速度会非常慢。建议至少准备一张显存 8GB 以上的显卡。3.2 项目结构为了让示例清楚本文假设你的 YOLO26 项目结构如下yolo26-project/ ├── models/ │ ├── yolo26.py │ ├── lsb.py │ └── yolo26-lsb.yaml ├── data/ │ └── your_dataset.yaml ├── train.py ├── detect.py └── requirements.txt如果你使用的 YOLO26 仓库已经有自己的模块管理方式核心思路是一样的把新的模块文件放入 models 目录然后在 yaml 文件中引用。3.3 关于版本适配的建议YOLO26 并不是像 yolo5、yolo8 那样只有一个固定仓库不同开发者发布的 YOLO26 源码在模块名称和配置格式上会有差异。因此本文给出的代码统一采用“示例思路”的写法强调模块定义与接入位置不把具体源码路径写死。如果你发现自己的 YOLO26 源码中模块注册方式不同请先阅读仓库里已有的模块定义文件再按相同的模式注册 LSB 模块。4. YOLO26 接入 LSB 模块完整实战4.1 编写 LSB 模块代码新建文件models/lsb.py写入下面的代码。这是一个轻量化的 LSB 模块实现核心逻辑如下local_conv提取局部特征。transmit_conv对传入的局部特征做通道变换。最后将两者相加得到既包含当前层语义、又包含历史局部信息的输出。# 文件路径models/lsb.py import torch import torch.nn as nn class LSBBlock(nn.Module): LSB 模块局部特征连续传输 该模块参考 nnWNet 中 LSB 模块的设计思路 1. 局部分支提取当前层细节特征 2. 传输分支将上一阶段传递下来的局部特征继续向后传递 3. 融合后输出保留局部细节的同时增强语义。 def __init__(self, in_channels, mid_channelsNone, kernel_size3): super().__init__() if mid_channels is None: mid_channels in_channels # 局部特征提取分支 self.local_conv nn.Sequential( nn.Conv2d(in_channels, mid_channels, kernel_size, paddingkernel_size // 2, biasFalse), nn.BatchNorm2d(mid_channels), nn.SiLU(inplaceTrue), ) # 传输分支对传入的局部特征做通道对齐 self.transmit_conv nn.Conv2d(mid_channels, mid_channels, 1, biasFalse) # 融合后输出卷积 self.out_conv nn.Sequential( nn.Conv2d(mid_channels, in_channels, 1, biasFalse), nn.BatchNorm2d(in_channels), nn.SiLU(inplaceTrue), ) def forward(self, x, local_featNone): Args: x: 当前层的特征图shape 为 (B, C, H, W) local_feat: 上一模块传递下来的局部特征shape 为 (B, C, H, W)可以是 None Returns: out: 融合后的特征图 local_feat: 新的局部特征继续向后传递 # 当前层局部特征 current_local self.local_conv(x) if local_feat is not None: # 将上一阶段局部特征传入当前阶段 transmitted self.transmit_conv(local_feat) # 与当前局部特征相加完成连续传输 local_feat transmitted current_local else: local_feat current_local # 将局部特征回注到主分支 out self.out_conv(local_feat) x return out, local_feat class LSB(nn.Module): YOLO26 接入用的 LSB 容器模块 为了配合 YOLO 系列 yaml 配置的注册方式这里做一层封装。 插入多个 LSB 模块时内部会维护一条连续传输路径。 def __init__(self, in_channels, num_blocks1): super().__init__() self.lsb nn.ModuleList([ LSBBlock(in_channels) for _ in range(num_blocks) ]) def forward(self, x): local_feat None for block in self.lsb: x, local_feat block(x, local_feat) return x代码说明LSBBlock是基础模块可以单独使用。LSB容器用来组合多个 LSB 模块形成连续传输路径。模块返回的local_feat会在内部自动向后传递外部不需要额外维护。这里使用的激活函数是 SiLU和 YOLO 系列保持一致的风格。4.2 在 YOLO26 网络结构中注册 LSB如果你的 YOLO26 源码是基于 Ultralytics 风格构建的需要把 LSB 模块加入模块注册表。一般在models/yolo.py或对应的__init__.py中会有一段模块映射代码例如# 文件路径models/yolo.py示例片段 from .lsb import LSB然后在模块映射表里增加一行if m in {LSB}: args [ch[f], *args]如果你使用的是基于配置文件解析的 YOLO26 仓库一般只需要在 yaml 中直接写模块名并在模型构造函数中完成LSB类与名称的绑定。4.3 修改 yaml 配置下面是一个 YOLO26 接入 LSB 模块后的 yaml 配置示例。它演示了如何把 LSB 模块插入骨干网络之后、neck 之前以及插入到 neck 的不同分支中。# 文件路径models/yolo26-lsb.yaml # LSB 模块插入示例具体参数需要根据你的 YOLO26 版本调整 backbone: - [-1, 1, Conv, [64, 3, 2]] # 0 - [-1, 1, Conv, [128, 3, 2]] # 1 - [-1, 3, C3k2, [256]] # 2 - [-1, 1, Conv, [256, 3, 2]] # 3 - [-1, 6, C3k2, [512]] # 4 - [-1, 1, Conv, [512, 3, 2]] # 5 - [-1, 6, C3k2, [1024]] # 6 - [-1, 1, Conv, [1024, 3, 2]] # 7 - [-1, 3, C3k2, [1024]] # 8 # 在 backbone 后插入 LSB 模块 neck: - [-1, 1, LSB, [1024, 1]] # 9 - [-1, 1, Conv, [512, 1, 1]] # 10 - [-1, 1, nn.Upsample, [None, 2, nearest]] # 11 - [-1, 1, Concat, [4]] # 12 - [-1, 1, C3k2, [512]] # 13 - [-1, 1, LSB, [512, 1]] # 14 - [-1, 1, Conv, [256, 1, 1]] # 15 - [-1, 1, nn.Upsample, [None, 2, nearest]] # 16 - [-1, 1, Concat, [2]] # 17 - [-1, 1, C3k2, [256]] # 18 - [-1, 1, LSB, [256, 1]] # 19 head: - [4, 13, 19] # 多尺度检测头输入 ...注意上面的 yaml 只展示接入思路你需要根据自己使用的 YOLO26 源码中C3k2、Concat等模块名称进行替换。如果源码中是C2f、C3或其他模块名保持原有名称即可。4.4 训练配置数据配置文件your_dataset.yaml按常规 YOLO 格式编写即可这里不再展开。训练命令大致如下# 训练 LSB 改进后的 YOLO26 python train.py --cfg models/yolo26-lsb.yaml --data data/your_dataset.yaml --weights yolov26.pt --batch-size 16 --epochs 300如果使用 Ultralytics 风格项目可能是yolo train modelyolo26-lsb.yaml datadata/your_dataset.yaml epochs300 imgsz640 batch16建议先用小数据集或少量 epoch 验证模块是否正常收敛python train.py --cfg models/yolo26-lsb.yaml --data data/your_dataset.yaml --epochs 5 --batch-size 8如果前几个 epoch 的 loss 能正常下降说明模块接入没有问题再进入完整训练。4.5 验证与结果说明训练完成后通过验证集观察指标变化。重点看以下三个指标mAP0.5整体检测精度。mAP0.5:0.95更严格的精度指标能反映边界框质量。小目标类别 APLSB 模块对小目标的提升通常更明显。如果发现 mAP 没有明显提升不要急着否定模块。先检查训练是否已经完全收敛。数据增强策略是否适合当前数据集。学习率、epoch 数是否足够。LSB 模块插入位置是否合理。在低光场景或小目标较多的数据集上LSB 模块的效果一般会比普通目标检测数据集更明显因为它保留细节的能力在弱纹理环境下更有价值。4.6 完整代码演示如果你使用的是自定义训练脚本可以参考下面的最小调用示例# 文件路径models/demo_lsb_forward.py import torch from lsb import LSB # 模拟输入特征图 (batch2, channel256, height32, width32) x torch.randn(2, 256, 32, 32) # 实例化 LSB 模块 model LSB(in_channels256, num_blocks2) # 前向传播 out model(x) print(输入尺寸:, x.shape) print(输出尺寸:, out.shape) print(LSB 模块前向传播正常)预期输出类似输入尺寸: torch.Size([2, 256, 32, 32]) 输出尺寸: torch.Size([2, 256, 32, 32]) LSB 模块前向传播正常这一步可以快速验证模块本身没有语法错误、维度不匹配问题。5. 低光环境检测与 RK3588 部署优化5.1 低光环境检测中的 LSB 模块优势低光环境检测是 YOLO26 改进的热门方向之一。图像在低光条件下对比度低、细节纹理弱常规网络很容易把目标与背景混淆。LSB 模块通过连续传输局部特征相当于在深层特征图中保留了一条“细节快车道”。这些细节不经过深层卷积的多次非线性变换减少了信息损耗。因此在低光检测任务中LSB 的改进效果相对明显。如果你想要进一步提高低光效果可以搭配以下策略输入端增加弱光增强预处理例如直方图均衡化、Retinex 类算法。训练时使用低光数据增强包括亮度抖动、对比度抖动、噪声注入。将 LSB 模块与注意力模块串联例如在 LSB 输出后再加一个轻量通道注意力。不过要注意增强预处理会增加推理耗时。边缘设备部署时需要评估实时性要求。5.2 RK3588 部署注意事项RK3588 是瑞芯微推出的高性能边缘计算平台常用于摄像头检测设备。把加了 LSB 模块的 YOLO26 部署到 RK3588 上需要走 RKNN 工具链。部署流程大致如下将 PyTorch 模型导出为 ONNX。使用 RKNN-Toolkit2 将 ONNX 转换为 RKNN 格式。在板端加载 RKNN 模型进行推理。由于 LSB 模块只使用 Conv、BatchNorm、SiLU、Add 这类标准算子导出 ONNX 时一般不会遇到算子不支持的问题。这比包含自定义算子或可变形卷积的改进方案更适合边缘部署。导出 ONNX 的示例命令python export.py --cfg models/yolo26-lsb.yaml --weights runs/train/exp/weights/best.pt --include onnx --opset 11导出后可以用onnxruntime做一次对齐测试确认导出模型与 PyTorch 模型输出差异在可接受范围内。5.3 C 部署流程简述如果你需要在 RK3588 上使用 C 部署RKNN Toolkit 提供了 C 接口。核心流程是初始化 RKNN 上下文。加载 RKNN 模型。将输入图像转为 RGB888 或 NV12 格式。执行推理。对输出进行解码和后处理。LSB 模块的改进不会改变 YOLO26 的输出结构因此后处理代码可以沿用原有方案。6. 常见问题与排查思路6.1 训练时报错KeyError: LSB问题现象常见原因解决思路训练启动时提示找不到 LSB 模块模块没有在源码的注册表中登记在模型构造函数中加入 LSB 类并绑定名称模型加载正常但输出维度不对yaml 中参数不匹配检查输入通道参数是否正确必要时打印每一层输出 shape如果遇到KeyError: LSB优先排查模块注册位置。以 Ultralytics 风格源码为例模块实例化通常通过parse_model函数完成。当 yaml 中出现LSB时解析函数需要知道LSB对应哪个类。修复方式是在模块解析区域内添加判断分支if m in {LSB}: args [ch[f]]6.2 维度不匹配错误这个错误通常出现在local_feat的通道数与当前模块输入不一致的场景。比如第一个 LSB 模块输出的局部特征是 1024 通道但第二个 LSB 模块的输入是 512 通道。解决方法是确保同一传输路径上的 LSB 模块通道数一致或者在传输分支中加入通道对齐卷积。前面的代码示例中transmit_conv已经承担了这项任务因此只要每个 LSB 块的参数配置合理不会出现维度错误。6.3 显存溢出LSB 模块的显存开销主要来自多个中间特征图。如果插入数量太多训练 batch size 需要适当调低。建议先只在最大尺度的特征层插入一个 LSB 模块。验证效果后再逐步增加。开启梯度检查点gradient checkpointing可以缓解显存压力但会降低训练速度。6.4 训练不收敛或 mAP 反而下降可能原因模块插入位置不合理扰乱了原有网络路径。学习率不合适。数据集训练轮数不够。数据标签有问题。排查建议先在相同配置下训练原始 YOLO26 作为对照。使用相同随机种子和训练超参数。把 LSB 模块插入数量减到 1排除模块堆叠带来的负面影响。6.5 导出 ONNX 后推理结果不一致原因通常是 BatchNorm 与卷积融合导致的细微数值差异也可能是导出时固定了动态轴。建议在导出时设置动态输入尺寸python export.py --dynamic --include onnx导出后使用onnxruntime或rknn-toolkit2的 simulator 检查输出差异。7. 最佳实践与工程建议7.1 控制模块数量LSB 模块虽然轻量但也不是越多越好。模块数量过多会带来三方面问题训练显存上升。推理延迟增加。模型过拟合风险上升。建议优先在以下位置插入 LSB 模块backbone 的最后一层输出用于增强深层语义的细节表达。neck 中每次上采样之后用于增强小目标分支的细节。最大检测头分支前用于保留浅层细节。7.2 对比实验设计做 YOLO26 改进时对比实验要严谨。建议至少包含以下几组实验组配置说明基线原始 YOLO26LSB-1YOLO26 1 个 LSB 模块LSB-3YOLO26 3 个 LSB 模块LSB 注意力YOLO26 LSB 轻量注意力模块每组实验使用相同的数据集划分、训练超参数和评估脚本才能公平对比模块带来的增益。7.3 关注训练稳定性新增模块后网络初始化时的 loss 分布可能发生变化。如果出现第一个 epoch 的 loss 过高可以适当降低初始学习率或者增加 warmup 轮数。另外使用预训练权重时新增模块的权重是随机初始化的。建议先冻结 backbone 训练 20 到 50 个 epoch让新增模块先稳定下来再解冻全部参数微调。7.4 部署前检查清单在把改进后的模型部署到边缘设备之前可以按下面清单确认模型文件是导出的 ONNX 或 RKNN 格式不是 PyTorch 权重。输入图像的尺寸、通道顺序、归一化方式与训练时一致。输出解码逻辑是否与模型训练时的 anchor-free 配置匹配。在开发板上用真实推理环境测试耗时不要只看 GPU 上的推理速度。7.5 安全与合规如果 YOLO26 改进模型最终用于工业检测、安防或车端等场景需要确保训练数据来源合法不涉及个人隐私或敏感信息。模型部署在合法授权环境下不绕过任何安全限制。涉及数据删除、更新、模型替换等操作时先在测试环境验证再在正式环境执行。8. 总结与下一步学习建议这篇内容围绕 YOLO26 改进展开完整介绍了 nnWNet 中 LSB 模块的核心思想、模块设计、YOLO26 接入方式、训练验证流程以及边缘设备部署注意事项。关键点如下LSB 模块的核心是“局部特征连续传输”它不同于一次性的特征融合。模块实现不复杂主要包含局部卷积分支和连续传输分支。在 YOLO26 中接入时重点处理好模块注册和 yaml 参数配置。低光场景和小目标场景中LSB 模块的改进潜力更大。部署到 RK3588 时模块的标准算子设计让 ONNX 导出和 RKNN 转换更顺利。接下来你可以继续做这几件事在自己数据集上跑一组基线实验记录原始 YOLO26 的 mAP 和推理速度。按本文方式插入 LSB 模块跑同样的训练流程做对比。如果效果正向再尝试把 LSB 与注意力机制、数据增强、低光预处理组合进一步提升模型能力。如果准备部署尽早把 ONNX 导出流程和 RK3588 推理流程跑通避免模型训练后期发现算子兼容问题。如果你在接入 LSB 模块时踩了坑欢迎对照文中的排查表逐项检查。尤其是模块注册和 yaml 参数这两个环节大多数问题都出在这里。