YOLO26 增加 LoRA 支持(参数高效微调 PEFT)

什么是 LoRA(Low-Rank Adaptation)

  • 不训练完整模型权重,只训练低秩小矩阵
  • 冻结主干网络,仅训练 1%~2% 参数
  • 速度快、显存占用低、不会过拟合
  • 推理时可直接融合进原权重,不增加延迟
bash 复制代码
原始权重矩阵 W (D × K)
          ↓  冻结不动
LoRA 插入两个小矩阵 A、B
          A: D × r
          B: r × K
          r ≪ min(D,K)  # 秩非常小(默认8/16)

前向传播:
h = W x + α * B A x

推理融合:
W_final = W + (B A) * α
完全变成普通卷积,无额外计算

1. 配置文件

yaml 复制代码
# YOLO26 训练配置 yolo26-lora.yaml
lora: True  # 开启 LoRA
lora_rank: 8
lora_alpha: 16
lora_dropout: 0.0
freeze_backbone: True  # 冻结主干,只训练 LoRA

2. lora.py 文件

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F

# ---------------------------
# LoRA 卷积层(适配 YOLO26 Conv)
# ---------------------------
class LoRAConv2d(nn.Module):
    def __init__(self, conv, r=8, lora_alpha=16, dropout=0.0):
        super().__init__()
        self.conv = conv  # 原始卷积(冻结)
        self.r = r
        self.lora_alpha = lora_alpha
        self.scaling = lora_alpha / r

        # 冻结原始权重
        for p in self.conv.parameters():
            p.requires_grad = False

        # LoRA 低秩矩阵
        in_channels = conv.in_channels
        out_channels = conv.out_channels
        ksize = conv.kernel_size[0]

        # 只对 1x1 / 3x3 卷积做 LoRA
        if ksize == 1:
            self.lora_down = nn.Conv2d(in_channels, r, 1, bias=False)
            self.lora_up = nn.Conv2d(r, out_channels, 1, bias=False)
        elif ksize == 3:
            self.lora_down = nn.Conv2d(in_channels, r, 3, padding=1, groups=1, bias=False)
            self.lora_up = nn.Conv2d(r, out_channels, 1, bias=False)
        else:
            self.lora_down = None
            self.lora_up = None

        # 初始化
        nn.init.normal_(self.lora_down.weight, std=1e-5)
        nn.init.zeros_(self.lora_up.weight)

        self.dropout = nn.Dropout(dropout) if dropout > 0 else nn.Identity()

    def forward(self, x):
        # 原始卷积输出
        out = self.conv(x)
        
        # LoRA 增量
        if self.lora_down is not None:
            lora_out = self.lora_up(self.dropout(self.lora_down(x))) * self.scaling
            out = out + lora_out
        return out

# ---------------------------
# LoRA 线性层(适配 YOLO26 Detect)
# ---------------------------
class LoRALinear(nn.Module):
    def __init__(self, linear, r=8, lora_alpha=16, dropout=0.0):
        super().__init__()
        self.linear = linear
        for p in linear.parameters():
            p.requires_grad = False

        self.r = r
        self.scaling = lora_alpha / r

        in_features = linear.in_features
        out_features = linear.out_features

        self.lora_down = nn.Linear(in_features, r, bias=False)
        self.lora_up = nn.Linear(r, out_features, bias=False)
        nn.init.normal_(self.lora_down.weight, std=1e-5)
        nn.init.zeros_(self.lora_up.weight)

        self.dropout = nn.Dropout(dropout)

    def forward(self, x):
        out = self.linear(x)
        lora_out = self.lora_up(self.dropout(self.lora_down(x))) * self.scaling
        return out + lora_out

# ---------------------------
# 自动注入 LoRA(核心!无模型侵入)
# ---------------------------
def inject_lora(model, r=8, alpha=16, dropout=0.0, target_modules=None):
    """
    自动给 YOLO26 注入 LoRA
    不修改模型代码,不破坏结构
    """
    if target_modules is None:
        target_modules = [
            'conv', 'cv1', 'cv2', 'cv3',  # Conv 模块
            'q', 'k', 'v', 'proj',       # Transformer(如果有)
            'fc', 'linear'               # 检测头线性层
        ]

    # 递归替换层
    for name, module in model.named_children():
        # 替换 Conv2d
        if isinstance(module, nn.Conv2d) and any(k in name for k in target_modules):
            if module.weight.requires_grad:  # 只替换可训练层
                setattr(model, name, LoRAConv2d(module, r, alpha, dropout))
        
        # 替换 Linear
        elif isinstance(module, nn.Linear) and any(k in name for k in target_modules):
            setattr(model, name, LoRALinear(module, r, alpha, dropout))
        
        # 递归
        else:
            inject_lora(module, r, alpha, dropout, target_modules)

# ---------------------------
# 合并 LoRA 权重(推理提速)
# ---------------------------
def merge_lora(model):
    """将 LoRA 合并到原始权重,推理速度和原生模型完全一致"""
    for name, module in model.named_modules():
        if isinstance(module, (LoRAConv2d, LoRALinear)):
            # 合并卷积
            if isinstance(module, LoRAConv2d):
                w = module.conv.weight
                lora_w = module.lora_up.weight @ module.lora_down.weight * module.scaling
                if module.conv.kernel_size == (1,1):
                    w.data += lora_w
                elif module.conv.kernel_size == (3,3):
                    w.data += lora_w.view(w.shape)

            # 合并线性
            elif isinstance(module, LoRALinear):
                w = module.linear.weight
                lora_w = module.lora_up.weight @ module.lora_down.weight * module.scaling
                w.data += lora_w

3. 集成到 YOLO26

python 复制代码
from lora import inject_lora, merge_lora

# 加载 YOLO26 模型
model = YOLO26(cfg='yolo26.yaml').cuda()

# ------------------  LoRA 开启  ------------------
if cfg.get('lora', False):
    print("✅ 启用 LoRA 参数高效微调")
    inject_lora(
        model,
        r=cfg.get('lora_rank', 8),
        alpha=cfg.get('lora_alpha', 16),
        dropout=cfg.get('lora_dropout', 0.0)
    )

# 训练后合并(推理)
# merge_lora(model)

4. 训练配置文件

yolo26_lora_train.yaml

yaml 复制代码
epochs: 100
batch: 16
imgsz: 640
freeze_backbone: True  # 冻结主干

# LoRA 设置
lora: True
lora_rank: 8
lora_alpha: 16
lora_dropout: 0.0

optimizer: AdamW
lr0: 0.001
weight_decay: 0.0001
相关推荐
Uncertainty!!1 小时前
大模型基础架构之Transformer
人工智能·深度学习·transformer
通信大模型2 小时前
IEEE JSTSP| FlashSAM:低空无线网络中多无人机Token通信的轻量级视觉模型
人工智能·深度学习·无人机
EasyGBS3 小时前
社区、校园安防难统一?国标GB28181公网平台EasyGBS视频系统,打破安全监管难题!
深度学习·安全·自动化
陈嘿萌3 小时前
CVPR 2026 | 全新的五模态信息融合数据集,包括RGB、事件、热成像、4D 雷达与 LiDAR
人工智能·深度学习·计算机视觉·自动驾驶·学术研究与理论基础·点云雷达
通信大模型3 小时前
VLA模型与世界模型的协同:面向低空无线网络的Embodied Agentic AI 框架
人工智能·深度学习·信息与通信
艾派森3 小时前
深度学习实战-基于EfficientNetB0的鞋类品牌图像分类模型
人工智能·深度学习·分类
论文复现现场4 小时前
自动驾驶 BEV 模型训练,2 张 A100 80GB 够不够?显存、双卡训练与租赁成本
人工智能·深度学习·机器学习·自动驾驶·分布式训练·a100·bevformer
陈嘿萌4 小时前
TPAMI 2026|红外、SAR、深度与地图能否用一套特征匹配?北理工HIMO给出无需预训练的通用路线
图像处理·人工智能·深度学习·计算机视觉·图像匹配·学术研究与理论基础
在所不辞兄4 小时前
为什么物理嵌入神经网络的收敛性和泛化误差缺乏统一的理论保证?
人工智能·深度学习·神经网络·机器学习·有限元
朝朝辞暮i4 小时前
VLA 系统学习第 21 课——DDPM 与 Noise Scheduler:扩散模型究竟怎样从随机噪声生成机器人动作?
人工智能·深度学习·神经网络·transformer·vla