文章目录

YOLO 版本简介

YOLOv1(2016):开创「端到端实时检测」先河

核心定位:首次提出将目标检测视为「回归问题」,摆脱传统两阶段检测(如 R-CNN)的繁琐流程。
关键改进 / 特点:
用单一 CNN 网络完成「目标定位 + 类别预测」,无需分区域提取候选框,端到端训练 / 推理;
将输入图片划分为 7×7 网格,每个网格预测 2 个边界框 + 类别概率;
速度极快(45 FPS),但缺点明显:小目标检测差、定位精度低、召回率(漏检率)高。

YOLOv2(2017,YOLO9000):精度 + 速度双提升

核心定位:解决 v1 精度差的问题,支持更多类别检测(命名 YOLO9000)。
关键改进:
引入锚框(Anchor Boxes):不再依赖网格直接回归,而是基于预定义的锚框预测偏移,大幅提升定位精度;
新增Batch Normalization:稳定训练,提升模型泛化能力;
高分辨率预训练:先用 224×224 训练,再用 448×448 微调,适配检测任务的高分辨率输入;
维度聚类:用数据集自动聚类锚框尺寸,而非人工设定;
速度提升至 67 FPS,支持 9000 + 类别的联合训练。

YOLOv3(2018):多尺度检测 + 更强骨干网

核心定位:结合当时先进的特征融合技术,平衡精度和速度。
关键改进:
替换骨干网为Darknet-53:比 v2 的 Darknet-19 更深,引入残差连接,特征提取能力更强;
引入特征金字塔(FPN):多尺度预测(3 个尺度),解决小目标检测差的问题;
用逻辑回归替代 Softmax:支持多标签分类(如一个目标同时属于「人」+「戴帽子」);
精度显著提升,速度仍保持实时(30+ FPS),成为当时工业界主流。

YOLOv4(2020):集大成的工业级方案

核心定位:整合当时所有主流优化技巧,打造「开箱即用」的高性能检测模型。
关键改进:
骨干网升级为CSPDarknet53:引入 CSP 结构,减少计算量同时保持特征能力;
Neck 部分新增SPP 模块(空间金字塔池化) + PANet:增强多尺度特征融合;
训练策略优化:Mosaic 数据增强(4 张图拼接)、CIoU 损失(更精准的边界框回归)、DropBlock 正则化;
精度远超 v3,且无需额外算力,适合工业部署。

YOLOv5(2020,Ultralytics):易用性 + 轻量化的天花板

核心定位:非官方版本(原作者停更 YOLO),但生态最火,主打「易用、轻量化、部署友好」。
关键改进:
多尺度模型设计:提供 n/s/m/l/x 5 个版本(从超轻量到高性能),适配不同硬件;
新增Focus 结构:切片操作减少计算量,提升特征提取效率;
自适应优化:自适应锚框计算、自适应图片缩放(避免黑边);
全流程工具链:PyTorch 原生实现,支持一键导出 ONNX/TensorRT 等格式,部署成本极低;
速度和精度平衡极佳(n 版本可达 140 FPS),成为新手入门首选。

YOLOv6(2022,美团):工业级实时检测优化

核心定位:针对美团业务场景,优化「实时性 + 部署效率」。
关键改进:
骨干网用RepVGG:训练时多分支,推理时重参数化为单分支,速度大幅提升;
改用Anchor-free 检测头:摆脱锚框依赖,减少人工调参;
新增 SimOTA 标签分配策略:更精准地匹配预测框和真实框;
速度比 YOLOv5 更快,适合高并发的工业场景(如外卖配送视觉检测)。

YOLOv7(2022,原 YOLOv4 团队):精度优先的实时检测

核心定位:在相同速度下,把检测精度做到极致。
关键改进:
引入ELAN/E-ELAN 模块:高效特征融合,提升模型表达能力;
模型重参数化:训练和推理阶段的网络结构解耦,兼顾训练效果和推理速度;
辅助头训练:新增分类辅助头,提升检测精度;
动态标签分配:自适应分配正负样本,减少漏检;
相同速度下,精度远超 YOLOv5/v6,支持 5~160 FPS 的全范围速度需求。

YOLOv8(2023,Ultralytics):统一多任务的终极版本

核心定位:YOLOv5 的全面升级,统一「检测 / 分割 / 分类 / 姿态估计」多任务。
关键改进:
骨干网替换为C2f 模块:替代 v5 的 C3 模块,特征融合更高效;
Neck 部分简化:去除冗余的上采样步骤,计算量降低;
全面改用Anchor-free 检测头:无需预计算锚框,适配更多场景;
新标签分配策略(Task-Aligned Assigner):更精准匹配任务目标;
损失函数优化:分类用 CE 损失,回归用 DFL+CIoU 损失;
支持多任务:一套框架搞定检测、实例分割、图像分类、人体姿态估计,训练效率提升 30
%+。

通俗解释

我用「打靶」这个生活化的比喻,把 YOLOv1 到 v8 的进步讲得明明白白,全程不用专业术语,只说核心变化:

YOLOv1(2016):第一次用「一杆枪」打完所有靶

原来的做法:先在靶纸上画一堆候选框(找可能有靶的区域),再逐个判断是不是靶、是啥靶(两阶段),又慢又麻烦。
v1 的进步:直接用「一杆枪」瞄准整张靶纸,把靶纸分成 49 个小格子,每个格子直接说「有没有靶、靶在哪、是啥靶」。
缺点:枪法糙 —— 小靶打不准、靶的位置估不准,还容易漏靶,但胜在快(45 发 / 秒)。

YOLOv2(2017):给枪装了「瞄准镜」

核心进步:不再瞎猜靶的位置,而是先定几个常用的「靶框尺寸」(锚框),就像给枪装了瞄准镜,先对准大概率有靶的位置再微调,打靶精度直接提上来。
额外优化:提前用高清靶纸练枪(高分辨率预训练),还能同时打 9000 种不同的靶(YOLO9000),又快(67 发 / 秒)又准了点。

YOLOv3(2018):换了「更稳的枪身」+「多倍镜」

核心进步 1:把原来的「普通枪身」换成「Darknet-53」(带残差的深网络),枪更稳,能看清靶纸上的细节;
核心进步 2:加了「多倍镜」(特征金字塔),远的小靶(小目标)、近的大靶都能看清,不会再漏小靶;
额外优化:一个靶上有多个标签(比如「人 + 戴帽子」)也能认出来,精度又上一个台阶。

YOLOv4(2020):把所有「打靶技巧」都整合了

核心进步:相当于找了 10 个顶尖射手,把他们的技巧全学了 —— 换了「更轻但更硬的枪身」(CSPDarknet53)、加了「多角度瞄准器」(SPP+PANet)、练枪时故意混着不同靶纸练(Mosaic 增强);
结果:不用换更贵的枪(额外算力),但打靶精度远超 v3,工业上直接能用。

YOLOv5(2020):做了「多款定制枪」+「傻瓜式操作」

核心进步 1:不再只做一把枪,而是做了 5 款(n/s/m/l/x)—— 小枪(n 版)轻便,适合手机 / 边缘设备(140 发 / 秒),长枪(x 版)精准,适合服务器;
核心进步 2:枪上装了「自动校准」—— 不用手动调靶框尺寸、不用手动裁靶纸,新手拿过来就能用,还能一键把枪改成适配不同场地的版本(导出 ONNX/TensorRT);
结果:生态最火,新手入门首选,又好用又省心。

YOLOv6(2022):把枪改成「一键连发」

核心进步:枪的内部结构优化(RepVGG 重参数化)—— 练枪时是复杂结构(打得准),实际用的时候变成简单结构(打得快),像「一键连发」,美团外卖场景下高并发打靶也不卡;
额外优化:不用再提前定靶框尺寸(Anchor-free),不管靶是大是小,都能直接打,少了调参的麻烦。

YOLOv7(2022):同款枪,打得更准

核心进步:在和 v5/v6 同款射速的情况下,把「瞄准算法」做到极致 —— 练枪时加了「辅助瞄准」(分类辅助头)、自动选该打哪些靶(动态标签分配);
结果:同样是 100 发 / 秒,v7 能打中 95 个靶,v5 只能打中 88 个,精度拉满。

YOLOv8(2023):一把枪能打「所有类型的靶」

核心进步 1:枪身再升级(C2f 模块),更轻更准,还去掉了没用的瞄准步骤,效率更高;
核心进步 2:彻底不用提前定靶框(全 Anchor-free),不管啥靶都能打;
核心进步 3:一把枪适配所有场景 —— 既能打普通靶(检测)、又能打带分割线的靶(分割)、还能打人体姿态靶(姿态估计),不用换枪,一套搞定。

总结
用「打靶」总结 YOLO 的核心进步:
从「瞎打」到「精准打」:v1 瞎猜位置,v2-v7 不断优化瞄准方式,v8 直接不用预设靶框;
从「一把枪」到「多用途枪」:v1-v4 只打检测靶,v8 能打检测、分割、姿态等多种靶;
从「专业选手用」到「普通人用」:v1-v4 需要调参,v5-v8 越来越傻瓜化,新手也能上手,还适配各种设备。

基础的四种改进方向

加注意力机制

  1. 加注意力机制:给枪装「智能瞄准镜」
    原来的问题:YOLO 看图片时,把背景和目标平分注意力(比如打「行人靶」时,还盯着路边的树),小靶 / 模糊靶容易漏。
    优化逻辑:给模型加「注意力模块」,就像瞄准镜自动聚焦靶的核心区域(比如行人的躯干 / 头部),忽略无关背景,把算力和注意力都用在关键地方。
    效果:小目标、遮挡目标的命中率显著提升,大目标定位更准

做堆叠

多把枪「层层瞄准 / 投票」
原来的问题:单把枪打靶,偶尔会看错(比如把「猫靶」认成「狗靶」),精度有上限。
优化逻辑:两种堆叠思路(新手优先选简单的):
「模块堆叠」:把 YOLO 的核心模块(比如特征融合的 C2f 模块)多叠一层,就像第一把枪粗瞄找靶的大致位置,第二把枪精瞄靶框,层层递进;
「模型堆叠」:训练 3 个不同版本的 YOLO 模型,打靶时取 3 个模型的投票结果(2 个以上说「是行人」才算中),减少误判。
效果:精度提升 3%~8%(代价是速度略降,可按需取舍)

优化损失函数

调整「打靶评分规则」
原来的问题:YOLOv8 的损失函数对「小靶打偏」「难识别靶(比如模糊靶)」的惩罚不够,练枪时进步慢。
优化逻辑:重新设计评分规则:
原来只看「靶框和实际位置差多少」(CIoU),现在升级为「EIoU」—— 不仅看位置,还看靶框的长宽是否匹配(比如把「瘦长的行人框」打成「矮胖的框」,惩罚更重);
加「Focal Loss」—— 对难打的靶(小靶、遮挡靶)多练,对容易打的靶(清晰大靶)少练,避免模型「偏科」。
效果:练枪效率更高,难检测的目标(小 / 遮挡 / 模糊)命中率提升。

结合多模态

给枪加「多感官辅助」
原来的问题:YOLO 只靠「视觉(图片)」找靶,比如图片里有「红色车」和「白色车」,想只打「红色车」时,单靠视觉容易漏 / 错;或者图片模糊时,完全认不出靶。
优化逻辑:给模型加「多模态输入」—— 除了图片,还喂文本(比如「找红色的轿车」)、雷达数据、语音等,就像打靶时有人告诉你「靶的特征」,模型能精准锁定目标。
效果:复杂场景(模糊、多同类目标、跨场景)下的检测准确率大幅提升,还能实现「指定类别 / 特征检测」。

具体改进措施

1. 加注意力机制(CBAM,轻量易落地)

CBAM 是最适合 YOLO 的轻量注意力模块(计算量小,不影响速度),加到 YOLOv8 的 C2f 模块里

import torch
import torch.nn as nn

# 第一步:定义CBAM注意力模块(新手不用深究细节,直接用)
class CBAM(nn.Module):
    def __init__(self, channels, reduction=16):
        super().__init__()
        # 通道注意力:关注哪些通道的特征重要(比如「行人通道」比「背景通道」重要)
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.max_pool = nn.AdaptiveMaxPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(channels, channels//reduction),
            nn.ReLU(),
            nn.Linear(channels//reduction, channels)
        )
        # 空间注意力:关注哪些位置的特征重要(比如行人的躯干位置)
        self.spatial = nn.Sequential(
            nn.Conv2d(2, 1, 7, padding=3, bias=False),
            nn.Sigmoid()
        )
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        # 通道注意力计算
        avg_out = self.fc(self.avg_pool(x).view(x.size(0), -1)).view(x.size(0), -1, 1, 1)
        max_out = self.fc(self.max_pool(x).view(x.size(0), -1)).view(x.size(0), -1, 1, 1)
        channel_att = self.sigmoid(avg_out + max_out)
        x = x * channel_att  # 给重要通道加权
        # 空间注意力计算
        avg_out = torch.mean(x, dim=1, keepdim=True)
        max_out, _ = torch.max(x, dim=1, keepdim=True)
        spatial_att = self.spatial(torch.cat([avg_out, max_out], dim=1))
        x = x * spatial_att  # 给重要位置加权
        return x

# 第二步:把CBAM加到YOLOv8的C2f模块(核心特征融合模块)
class C2fWithAttention(nn.Module):
    def __init__(self, c1, c2, n=1):  # c1=输入通道, c2=输出通道, n=模块数
        super().__init__()
        self.cv1 = nn.Conv2d(c1, c2, 1)  # 基础卷积
        self.cv2 = nn.Conv2d(c1, c2, 1)  # 基础卷积
        self.attention = CBAM(c2)  # 加入注意力模块
        self.relu = nn.ReLU()

    def forward(self, x):
        x1 = self.cv1(x)
        x2 = self.cv2(x)
        out = x1 + x2  # 特征融合
        out = self.attention(out)  # 注意力加权
        out = self.relu(out)
        return out

# 测试:模拟输入(batch=1, 通道=64, 尺寸=32×32)
x = torch.randn(1, 64, 32, 32)
model = C2fWithAttention(64, 64)
print(model(x).shape)  # 输出:torch.Size([1, 64, 32, 32]) → 注意力模块生效

2.做堆叠:模块堆叠(最简单的落地方式)

直接把上面带注意力的 C2f 模块多叠几层,实现「层层特征细化」

# 堆叠3层带注意力的C2f模块
class StackedC2f(nn.Module):
    def __init__(self, c1, c2):
        super().__init__()
        self.layer1 = C2fWithAttention(c1, c2)
        self.layer2 = C2fWithAttention(c2, c2)
        self.layer3 = C2fWithAttention(c2, c2)  # 多叠一层,层层精瞄

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        return x

# 测试
x = torch.randn(1, 64, 32, 32)
stack_model = StackedC2f(64, 64)
print(stack_model(x).shape)  # 输出:torch.Size([1, 64, 32, 32]) → 堆叠生效

3. 优化损失函数:EIoU + Focal Loss

替换 YOLOv8 原有的损失函数,重点优化「框回归」和「类别预测」

import torch.nn.functional as F

# 第一步:EIoU损失(比CIoU更关注框的长宽匹配)
def eiou_loss(box_pred, box_true):
    # box_pred:预测框 [x1,y1,x2,y2],box_true:真实框 [x1,y1,x2,y2]
    # 1. 计算框的中心、长宽
    pred_xy = (box_pred[..., :2] + box_pred[..., 2:]) / 2
    pred_wh = box_pred[..., 2:] - box_pred[..., :2]
    true_xy = (box_true[..., :2] + box_true[..., 2:]) / 2
    true_wh = box_true[..., 2:] - box_true[..., :2]
    
    # 2. 计算中心距离、长宽损失
    xy_loss = torch.sum((pred_xy - true_xy)**2, dim=-1)
    wh_loss = torch.sum((torch.log(pred_wh) - torch.log(true_wh))**2, dim=-1)
    # 3. EIoU = 中心损失 + 长宽损失 + 交并比损失(简化版,新手够用)
    iou = box_iou(box_pred, box_true)  # YOLO自带的IoU计算函数
    eiou = 1 - iou + xy_loss + wh_loss
    return eiou.mean()

# 第二步:Focal Loss(解决小目标/难样本漏检)
def focal_loss(pred, target, alpha=0.25, gamma=2):
    # alpha:平衡正负样本,gamma:惩罚易分样本
    ce_loss = F.cross_entropy(pred, target, reduction='none')
    pt = torch.exp(-ce_loss)  # 预测正确的概率
    focal = alpha * (1 - pt) ** gamma * ce_loss
    return focal.mean()

# 第三步:组合损失函数(框回归+类别预测)
def custom_loss(box_pred, box_true, cls_pred, cls_true):
    box_loss = eiou_loss(box_pred, box_true)  # 框回归用EIoU
    cls_loss = focal_loss(cls_pred, cls_true)  # 类别预测用Focal Loss
    total_loss = box_loss + cls_loss  # 总损失
    return total_loss

# 测试:模拟输入
box_pred = torch.randn(1, 4)  # 预测框
box_true = torch.tensor([[10,10,50,50]], dtype=torch.float32)  # 真实框
cls_pred = torch.randn(1, 80)  # 预测类别(80类是COCO数据集)
cls_true = torch.tensor([0])  # 真实类别(0=行人)
print(custom_loss(box_pred, box_true, cls_pred, cls_true))  # 输出损失值

4 结合多模态:图像 + 文本(最易落地的多模态)

from transformers import CLIPModel, CLIPProcessor

# 第一步:加载CLIP(文本+图像特征提取)
clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")

# 第二步:融合CLIP文本特征和YOLO图像特征
class MultiModalYOLO(nn.Module):
    def __init__(self, yolo_backbone, num_classes=80):
        super().__init__()
        self.yolo_backbone = yolo_backbone  # YOLOv8的图像特征提取骨干
        self.clip_text_proj = nn.Linear(512, 256)  # CLIP文本特征降维
        self.yolo_img_proj = nn.Linear(256, 256)    # YOLO图像特征降维
        self.fusion = nn.Conv2d(256*2, 256, 1)     # 特征融合
        self.head = nn.Conv2d(256, num_classes+4, 1)  # 检测头(类别+框)

    def forward(self, img, text):
        # 1. 提取YOLO图像特征
        img_feat = self.yolo_backbone(img)  # [1,256,32,32]
        # 2. 提取CLIP文本特征(比如「红色轿车」)
        text_inputs = clip_processor(text=text, return_tensors="pt", padding=True)
        text_feat = clip_model.get_text_features(**text_inputs)  # [1,512]
        text_feat = self.clip_text_proj(text_feat)  # [1,256]
        # 3. 文本特征扩维,和图像特征匹配
        text_feat = text_feat.unsqueeze(-1).unsqueeze(-1)  # [1,256,1,1]
        text_feat = text_feat.expand_as(img_feat)  # [1,256,32,32]
        # 4. 特征融合
        img_feat = self.yolo_img_proj(img_feat.permute(0,2,3,1)).permute(0,3,1,2)
        fusion_feat = torch.cat([img_feat, text_feat], dim=1)  # 拼接
        fusion_feat = self.fusion(fusion_feat)
        # 5. 检测输出
        out = self.head(fusion_feat)
        return out

# 测试:模拟输入
yolo_backbone = nn.Conv2d(3, 256, 3, padding=1)  # 简化YOLO骨干
mm_yolo = MultiModalYOLO(yolo_backbone)
img = torch.randn(1, 3, 640, 640)  # 输入图像
text = ["red car"]  # 文本提示:找红色轿车
print(mm_yolo(img, text).shape)  # 输出:torch.Size([1, 84, 320, 320]) → 多模态生效

总结:
注意力机制:给 YOLO 加「智能瞄准镜」,聚焦目标核心区域,优先选 CBAM(轻量)加到 C2f 模块;
堆叠:新手优先选「模块堆叠」(多叠几层核心模块),精度提升且易落地,模型堆叠适合追求更高精度的场景;
优化损失函数:用 EIoU 替代 CIoU(框回归更准),加 Focal Loss(解决小目标漏检),训练效率更高;
多模态:新手先试「图像 + 文本」(CLIP+YOLO),实现指定类别检测,适配复杂场景

代码的具体使用方法

YOLOv8 核心目录结构(基础参考)

ultralytics/          # 根目录
├── nn/               # 网络结构核心目录(重点修改区)
│   ├── backbones/    # 骨干网(C2f、CBAM等模块)
│   │   └── __init__.py
│   ├── head.py       # 检测头(损失函数、输出层)
│   ├── modules.py    # 基础模块(注意力、C2f等)
│   └── tasks.py      # 任务封装(多模态可加这里)
├── engine/           # 训练引擎
│   └── trainer.py    # 训练逻辑(损失函数调用)
├── models/           # 模型配置
│   └── yolo/
│       ├── detect/
│       │   ├── model.py  # 检测模型封装(多模态融合)
│       │   └── loss.py   # 损失函数定义(重点)
│       └── __init__.py
└── __init__.py

1.注意力机制(CBAM + C2fWithAttention)

  1. 存放文件:ultralytics/nn/modules.py
  2. 具体位置:
    打开modules.py,找到C2f类的定义处(约 200-300 行,不同版本行数略有差异);
    在C2f类上方添加CBAM类的代码;
    在C2f类下方添加C2fWithAttention类的代码;

3 关键修改:

# 在modules.py中新增(示例片段)
class CBAM(nn.Module):  # 直接复制之前的CBAM代码
    def __init__(self, channels, reduction=16):
        super().__init__()
        # ... 省略完整代码(和之前一致)

class C2f(nn.Module):  # 官方原有C2f类
    # ... 官方原有代码

class C2fWithAttention(nn.Module):  # 新增带注意力的C2f
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # 对齐官方C2f参数
        super().__init__()
        self.c = int(c2 * e)  # 对齐官方C2f的通道计算
        self.cv1 = Conv(c1, 2 * self.c, 1, 1)  # 改用官方Conv类(避免报错)
        self.cv2 = Conv((2 + n) * self.c, c2, 1)  # 对齐官方
        self.attention = CBAM(2 * self.c)  # 加入注意力
        self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))

    def forward(self, x):
        y = list(self.cv1(x).chunk(2, 1))
        y.extend(m(y[-1]) for m in self.m)
        y = torch.cat(y, 1)
        y = self.attention(y)  # 注意力加权(核心修改)
        return self.cv2(y)
  1. 生效方式:
    修改ultralytics/nn/tasks.py中DetectionModel的__init__,把原有C2f替换为C2fWithAttention即可。

2.堆叠(StackedC2f)

  1. 存放文件:ultralytics/nn/modules.py
  2. 具体位置:
    在C2fWithAttention类下方添加StackedC2f类的代码;
  3. 关键修改:
# 在modules.py中C2fWithAttention下方新增
class StackedC2f(nn.Module):
    def __init__(self, c1, c2, n=3):  # n=堆叠层数
        super().__init__()
        self.layer1 = C2fWithAttention(c1, c2)
        self.layer2 = C2fWithAttention(c2, c2)
        self.layer3 = C2fWithAttention(c2, c2)

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        return x
  1. 生效方式:
    在tasks.py中把需要堆叠的C2f模块替换为StackedC2f(比如 Neck 部分的 C2f)

3.优化损失函数(EIoU + Focal Loss)

  1. 存放文件:ultralytics/models/yolo/detect/loss.py

  2. 具体位置:
    打开loss.py,找到DetectionLoss类(官方损失类);
    在DetectionLoss类内部新增eiou_loss和focal_loss方法;
    重写__call__方法(损失计算核心);

  3. 关键修改:

# 在loss.py的DetectionLoss类中修改
class DetectionLoss(nn.Module):
    def __init__(self, model):
        super().__init__()
        # ... 官方原有初始化代码

    # 新增EIoU损失方法
    def eiou_loss(self, box_pred, box_true):
        # 复制之前的eiou_loss代码,注意适配官方张量格式
        pred_xy = (box_pred[..., :2] + box_pred[..., 2:]) / 2
        pred_wh = box_pred[..., 2:] - box_pred[..., :2]
        true_xy = (box_true[..., :2] + box_true[..., 2:]) / 2
        true_wh = box_true[..., 2:] - box_true[..., :2]
        
        xy_loss = torch.sum((pred_xy - true_xy)**2, dim=-1)
        wh_loss = torch.sum((torch.log(pred_wh + 1e-8) - torch.log(true_wh + 1e-8))**2, dim=-1)  # 加1e-8防除0
        iou = self.bbox_iou(box_pred, box_true, CIoU=False)  # 调用官方IoU函数
        eiou = 1 - iou + xy_loss + wh_loss
        return eiou.mean()

    # 新增Focal Loss方法
    def focal_loss(self, pred, target, alpha=0.25, gamma=2):
        ce_loss = F.cross_entropy(pred, target, reduction='none')
        pt = torch.exp(-ce_loss)
        focal = alpha * (1 - pt) ** gamma * ce_loss
        return focal.mean()

    # 重写损失计算核心方法
    def __call__(self, preds, batch):
        # ... 省略官方原有前处理代码(获取box_pred, box_true, cls_pred, cls_true)
        
        # 替换原有损失计算
        box_loss = self.eiou_loss(box_pred, box_true)  # 用EIoU替代CIoU
        cls_loss = self.focal_loss(cls_pred, cls_true)  # 用Focal Loss替代普通CE
        
        total_loss = box_loss + cls_loss * self.hyp['cls']  # 对齐官方权重
        return total_loss * batch['batch_size'], torch.cat((box_loss, cls_loss)).detach()

4.结合多模态(CLIP + YOLO)

  1. 核心文件 1:ultralytics/nn/modules.py(多模态融合模块)
    在modules.py末尾新增MultiModalFusion类:
class MultiModalFusion(nn.Module):
    def __init__(self, img_dim=256, text_dim=512, out_dim=256):
        super().__init__()
        self.img_proj = nn.Linear(img_dim, out_dim)
        self.text_proj = nn.Linear(text_dim, out_dim)
        self.fusion_conv = nn.Conv2d(out_dim*2, out_dim, 1)
        # 加载CLIP(仅初始化一次)
        self.clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
        self.clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
        # 冻结CLIP(避免训练时更新)
        for param in self.clip_model.parameters():
            param.requires_grad = False

    def get_text_feat(self, text):
        text_inputs = self.clip_processor(text=text, return_tensors="pt", padding=True)
        text_feat = self.clip_model.get_text_features(**text_inputs)
        return self.text_proj(text_feat)

    def forward(self, img_feat, text):
        # img_feat: [B, C, H, W](YOLO图像特征)
        # text: list[str](文本提示,如["red car"])
        text_feat = self.get_text_feat(text)  # [B, out_dim]
        # 扩维匹配图像特征
        text_feat = text_feat.unsqueeze(-1).unsqueeze(-1).expand_as(img_feat)
        # 图像特征投影
        img_feat = self.img_proj(img_feat.permute(0,2,3,1)).permute(0,3,1,2)
        # 融合
        fusion_feat = torch.cat([img_feat, text_feat], dim=1)
        return self.fusion_conv(fusion_feat)

  1. 核心文件 2:ultralytics/models/yolo/detect/model.py(多模态模型封装)
    打开model.py,找到DetectionModel类,修改forward方法:
class DetectionModel(BaseModel):
    def __init__(self, cfg='yolov8n.yaml', ch=3, nc=None, verbose=True):
        super().__init__()
        # 新增多模态融合模块
        self.multi_modal_fusion = MultiModalFusion()

    def forward(self, x, text=None, *args, **kwargs):
        # x: 图像输入, text: 文本提示(新增)
        img_feat = self.backbone(x)  # 提取YOLO图像特征
        if text is not None:
            img_feat = self.multi_modal_fusion(img_feat, text)  # 多模态融合
        out = self.neck(img_feat)
        out = self.head(out)
        return out
  1. 辅助文件:ultralytics/engine/trainer.py(训练时传入文本)
    在trainer.py的train_step方法中,新增文本输入的传递逻辑(比如从数据集读取文本标签)
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐