YOLO-World 精读:慢的不是检测器,是文本编码器

项目 内容
标题 YOLO-World: Real-Time Open-Vocabulary Object Detection
作者 Tianheng Cheng、Lin Song(共同一作)、Yixiao Ge(项目负责人)、Wenyu Liu、Xinggang Wang、Ying Shan;腾讯 AI Lab、腾讯 PCG ARC Lab、华中科技大学电子信息与通信学院
来源 arXiv:2401.17270 cs.CV,本笔记依据 v3(2024-02-22);首版 2024-01-30;CVPR 2024
代码 github.com/AILab-CVC/Y... MMYOLO / MMDetection,GPL-3.0);本笔记的实验固定在提交 b1b09f2(2025-02-06),原因见 9.1 节
权重 HF wondervictor/YOLO-World:论文版(官方叫 v1)的 S / M / L(O365+GoldG)与 L(+CC3M-Lite),以及之后的 v2、v2.1 和 X、XL。代码仓库的 LICENSE 和 HF 模型卡都是 GPL-3.0(pyproject.toml 里写的 Apache 2.0 与之不一致)
关键词 开放词表检测、YOLOv8、CLIP 文本编码器、区域-文本对比学习、RepVL-PAN、T-CSPLayer、max-sigmoid 注意力、I-Pooling Attention、重参数化、prompt-then-detect、伪标注、LVIS Fixed AP

1. 一句话总结

YOLO-World 把 YOLOv8 改成了开放词表检测器:分类不再是固定的 80 个输出通道,而是用 CLIP 文本编码器把类名或名词短语编码成文本嵌入,检测头在每个位置输出一个"物体嵌入",两者的余弦相似度经过缩放、平移就是分类分数(Eq. 1)。neck 换成 RepVL-PAN:在 YOLOv8 的 C2f 里加一个按文本做的 max-sigmoid 门控(T-CSPLayer),再用 I-Pooling Attention 把图像信息写回文本嵌入。在 Objects365、GQA、Flickr30k 和伪标注的 CC3M 子集上做区域-文本对比预训练后,YOLO-World-L 在 LVIS minival 上零样本 35.4 AP、V100 上 52.0 FPS,比同期的 GLIP、Grounding DINO、DetCLIP 快 20 倍以上。推理采用 prompt-then-detect:用户的词表事先编码好,文本编码器可以不再参与推理,文本嵌入还能直接折进卷积权重。

(后话:YOLO-World 后来成为工业界最常用的开放词表检测器之一,Ultralytics 也集成了它。官方仓库 2024-02 的 v2 去掉了 I-Pooling Attention、把对比头的 L2 归一化换成 BN,2025-02 的 v2.1 又重做了伪标注数据、加入图像提示;见第 7 节。)


2. 研究背景与动机

2.1 固定词表与开放词表

  • 传统检测器(Faster R-CNN、YOLO 系列等)只认训练集里定义好的类别,比如 COCO 的 80 类;要加一个类就得重新标注、重新训练。
  • 开放词表检测(OVD)想让检测器认出训练类别以外的东西。早期做法按"基类 / 新类"划分(如 OV-COCO 只有 48 个基类),从 CLIP、BERT 这类语言或视觉-语言模型里蒸馏词表知识;训练数据和词表都太少,换个领域就不行。
  • GLIP、Grounding DINO、DetCLIP 等把检测重新表述成区域级的视觉-语言预训练,在检测、grounding、图文数据上大规模训练,零样本效果好。但它们有两个问题:计算量大 (ATSS、DINO 这类检测器配 Swin 骨干)、部署难(每张图都要同时编码图像和整套文本)。
  • 此前没人认真试过:小检测器(YOLO 这种)做视觉-语言预训练,能不能也获得开放词表能力。

2.2 三种检测范式(Fig. 2)

  • (b) 的"在线词表":图像和文本一起作为输入,每张图都要过一遍文本编码器。GLIP 这类图文深度融合的模型,一次输入的文本长度有限,LVIS 的 1203 个类名要切成很多段、每段各跑一次完整前向;Table 2 里 GLIP-T 只有 0.12 FPS,个人推测主要是这个原因(论文没有说明 FPS 怎么测的)。
  • (c) 的 prompt-then-detect:用户先给出要检测的东西(类名、带属性的描述都行),一次性编码成离线词表;之后检测器每张图只跑图像部分,词表可以随时换。

3. 主要贡献

  1. YOLO-World:基于 YOLOv8 的开放词表检测器,S / M / L 三档,面向实时应用。
  2. RepVL-PAN 与区域-文本对比预训练:T-CSPLayer(文本→图像)和 I-Pooling Attention(图像→文本)两个融合模块;推理时文本嵌入可以重参数化进卷积或线性层。
  3. 统一的预训练数据格式与伪标注:检测、grounding、图文数据统一成区域-文本对;对图文数据提出自动标注流程(n-gram 抽名词 → GLIP 打框 → CLIP 重打分过滤),标了 CC3M 的 246k 张图、821k 个框。
  4. 结果:LVIS minival 零样本 35.4 AP、52.0 FPS(V100);微调后在 COCO、LVIS 检测和开放词表实例分割上都有收益;小模型(S,13M 参数)也能学到可用的开放词表能力。

4. 方法(Sec. 3)

4.1 把检测标注改写成区域-文本对(Sec. 3.1)

  • 传统标注是 Ω={Bi,ci }i=1N \Omega = \{B_i, c_i\}{i=1}^N Ω={Bi,ci}i=1N(框 + 类别下标),这里改写成 Ω={Bi,ti }i=1N \Omega = \{B_i, t_i\}{i=1}^N Ω={Bi,ti}i=1N, ti t_i ti 是框对应的文本:类名、名词短语或对物体的描述都可以。
  • 模型输入是图像 II I 和一组名词 TT T,输出预测框 { B^k } \{\hat{B}_k\} {B^k} 和对应的物体嵌入 {ek} \{e_k\} {ek}( ek∈RD e_k \in \mathbb{R}^D ek∈RD)。类别这件事完全由"物体嵌入和哪个词最像"来决定,所以检测类别不再写死在网络结构里。

4.2 整体结构(Sec. 3.2)

三部分:YOLO 检测器、文本编码器、RepVL-PAN。

  • YOLO 检测器:YOLOv8 的 Darknet 骨干 + PAN + 解耦检测头。
  • 文本编码器 :CLIP 的 Transformer 文本编码器,输出 W=TextEncoder(T)∈RC×DW = \text{TextEncoder}(T) \in \mathbb{R}^{C \times D} W=TextEncoder(T)∈RC×D, CC C 是名词个数, DD D 是嵌入维度。作者认为 CLIP 的文本嵌入经过图文对齐,比纯文本的 BERT 更适合连接视觉物体(Table 5 验证)。输入是长描述或指代表达时,先用简单的 n-gram 算法抽名词短语。代码里用的是 openai/clip-vit-base-patch32 的文本塔(63.4M 参数),取投影后的 512 维 text_embeds 再做 L2 归一化,预训练时整体冻结。
  • 文本对比头 :沿用 YOLOv8 的解耦头,两个 3×3 卷积分别回归框 {bk} \{b_k\} {bk} 和物体嵌入 {ek} \{e_k\} {ek}。物体与第 jj j 个词的相似度:

sk,j =α⋅L2-Norm(ek)⋅L2-Norm(wj)⊤+β (1) s_{k,j} = \alpha \cdot \text{L2-Norm}(e_k) \cdot \text{L2-Norm}(w_j)^\top + \beta \tag{1} sk,j=α⋅L2-Norm(ek)⋅L2-Norm(wj)⊤+β(1)

α\alpha α、 β\beta β 是可学习的缩放和平移。作者说 L2 归一化和这个仿射变换对稳定区域-文本训练都很重要。代码里每个尺度各有一套: α=exp⁡(logit_scale)\alpha = \exp(\text{logit\_scale}) α=exp(logit_scale),按 CLIP 初始化为 1/0.071/0.07 1/0.07; β\beta β 初始化为 log⁡(5/C/(640/stride)2)\log\big(5 / C / (640/\text{stride})^2\big) log(5/C/(640/stride)2),即先验概率很小。

  • 训练用在线词表 :每个 mosaic 样本(4 张图拼成)单独组一个词表:这 4 张图里出现的所有正名词,再从数据集里随机采一些负名词,总数最多 M=80M = 80 M=80。代码(RandomLoadText)里不足 80 个用空字符串补齐,补齐项也会被文本编码器编码、当作负样本参与计算。
  • 推理用离线词表:用户定义一组提示词(类名或描述),用文本编码器编码一次得到离线词表嵌入,之后每张图都直接用,词表也可以按需替换。

4.3 RepVL-PAN(Sec. 3.3)

结构上沿用 YOLOv8 PAN 的自顶向下、自底向上路径,由 {C3,C4,C5} \{C_3, C_4, C_5\} {C3,C4,C5} 得到 {P3,P4,P5} \{P_3, P_4, P_5\} {P3,P4,P5},加了两个模块:

  • T-CSPLayer(文本引导的 CSPLayer):在 C2f 最后一个 dark bottleneck 之后加 max-sigmoid 注意力:

Xl′=Xl⋅δ( max⁡j∈{1..C} (XlWj⊤))⊤ (2) X_l' = X_l \cdot \delta\Big(\max_{j \in \{1..C\}} (X_l W_j^\top)\Big)^\top \tag{2} Xl′=Xl⋅δ(j∈{1..C}max(XlWj⊤))⊤(2)

意思是:特征图每个位置都和词表里的所有词算相似度,取最大的那个,过 sigmoid 后作为这个位置的权重。和词表里任何一个词都不像的位置被压下去,像某个词的位置被保留。 Xl′ X_l' Xl′ 再与 C2f 的跨阶段特征拼接输出。

  • I-Pooling Attention(图像池化注意力) :不直接在整张特征图上做交叉注意力(太贵),而是把三层特征各 max-pool 成 3×3,一共 27 个 patch token X~∈R27×D \tilde{X} \in \mathbb{R}^{27 \times D} X~∈R27×D,文本嵌入作为 query:

W′=W+MultiHead-Attention(W,X~,X~) (3) W' = W + \text{MultiHead-Attention}(W, \tilde{X}, \tilde{X}) \tag{3} W′=W+MultiHead-Attention(W,X~,X~)(3)

得到"图像感知"的文本嵌入。

论文写法与代码写法的出入 (读 yolo_world/models/layers/yolo_bricks.py、necks/yolo_world_pafpn.py,并在 8.5 节逐元素对拍过):

论文 代码(v1:MaxSigmoidCSPLayerWithTwoConv、ImagePoolingAttentionModule、YOLOWorldDualPAFPN)
max-sigmoid 注意力 单头,直接 XW⊤X W^\top XW⊤ 多头(每头 32 维);图像先过 1×1 卷积 + BN 投到 embed 维,文本先过一层 Linear;相似度除以 32 \sqrt{32} 32 ,再加每个头一个可学习偏置
被加权的特征 XX X 本身 XX X 先过一个 3×3 卷积 + BN,再乘权重
输出方式 与跨阶段特征拼接 作为 C2f 的额外一支拼进去:最后的 1×1 卷积输入从 (2+n)c(2+n)c (2+n)c 变成 (3+n)c(3+n)c (3+n)c
I-Pooling 的计算 Eq. 3;附录 Eq. 6 写成 W+Softmax(W⊙X~)⊙WW + \text{Softmax}(W \odot \tilde{X}) \odot W W+Softmax(W⊙X~)⊙W(最后一项应是 X~ \tilde{X} X~,像是笔误) 标准多头注意力:三层特征先各自 1×1 卷积到 256 维再池化;query 是 LayerNorm + Linear(512→256),key、value 各自 LayerNorm + Linear,8 头,输出 Linear(256→512) 后加回 WW W
I-Pooling 的个数与去向 Fig. 4 画了两个,第二个输出的"图像感知嵌入"送进检测头(Fig. 3 也这么画) 只有一个,放在自顶向下路径之后; W′W' W′ 只给自底向上的两个 T-CSPLayer 用,检测头算相似度用的仍是原始 WW W

最后一行的影响最大:检测头不依赖图像感知的 W′W' W′,所以检测头整个可以重参数化掉(8.4 节)。

4.4 预训练方案(Sec. 3.4)

区域-文本对比损失 :对 mosaic 样本 II I 和词表 TT T,模型给出 KK K 个预测 {Bk,sk} \{B_k, s_k\} {Bk,sk}。沿用 YOLOv8 的 task-aligned label assignment(TAL)把预测和标注匹配,每个正样本的分类标签是它对应文本在词表里的下标, Lcon \mathcal{L}{con} Lcon 是相似度与分配结果之间的交叉熵。总损失:
L(I)= Lcon +λI⋅( Liou + Ldfl )\mathcal{L}(I) = \mathcal{L}
{con} + \lambda_I \cdot (\mathcal{L}{iou} + \mathcal{L}{dfl}) L(I)=Lcon+λI⋅(Liou+Ldfl)

图像来自检测或 grounding 数据时 λI=1 \lambda_I = 1 λI=1;来自图文数据时框不可靠, λI=0 \lambda_I = 0 λI=0,只算分类。

代码里"交叉熵"其实是 YOLOv8 的 sigmoid 二分类交叉熵(CrossEntropyLoss(use_sigmoid=True)):每个词独立做二分类,目标是 TAL 给出的软分数(与 IoU 挂钩),再除以所有软分数之和;不是在词表上做 softmax。三项权重沿用 YOLOv8:分类 0.5、CIoU 7.5、DFL 0.375(1.5 / 4)。也就是说,所谓"区域-文本对比学习"就是把 YOLOv8 的分类分支换成了"与文本嵌入的缩放余弦相似度",其余训练逻辑没变。

图文数据的伪标注(Sec. 3.4、附录 B):

  1. 抽名词 :n-gram 从描述里抽名词短语 T={tk} T = \{t_k\} T={tk}。
  2. 伪框 :GLIP-L 按这些名词给图打框,得到粗的区域-文本对 {Bi,ti,ci} \{B_i, t_i, c_i\} {Bi,ti,ci}( ci c_i ci 是置信度)。
  3. CLIP 重打分与过滤 :
    • 图文分数 simgs^{img} simg:整图与描述的 CLIP 相似度;区域-文本分数 sir s^r_i sir:裁出框内区域与对应名词的 CLIP 相似度;
    • (可选)重标注:每个裁出的区域与所有名词比,换成最像的那个,纠正 GLIP 标错的;
    • 重打分: c~i = ci⋅sir \tilde{c}_i = \sqrt{c_i \cdot s^r_i} c~i=ci⋅sir ;
    • 区域级过滤:按名词分组做 NMS(阈值 0.5),去掉 c~i <0.3 \tilde{c}_i < 0.3 c~i<0.3 的;
    • 图像级过滤:保留下来的框的平均区域-文本分数为 sregions^{region} sregion, s= simg⋅sregion >0.3 s = \sqrt{s^{img} \cdot s^{region}} > 0.3 s=simg⋅sregion >0.3 的图才留下。

阈值都是看一部分结果凭经验定的,全流程无人工核对。最终从 CC3M 里采样标注了 246k 张图、821k 个伪框(约为 CC3M 的 8%)。

4.5 推理:离线词表与重参数化(附录 A.1)

  • 先用文本编码器算好 W∈RC×DW \in \mathbb{R}^{C \times D} W∈RC×D。
  • T-CSPLayer :把 WW W reshape 成 CC C 个 1×1 卷积核,Eq. 2 变成 X′=X⊙Sigmoid(max⁡(Conv(X,W),dim=1))X' = X \odot \text{Sigmoid}(\max(\text{Conv}(X, W), \text{dim}=1)) X′=X⊙Sigmoid(max(Conv(X,W),dim=1))(Eq. 4),全是卷积和逐元素运算,部署友好。
  • I-Pooling Attention : X~=cat(MP(X3,3),MP(X4,3),MP(X5,3)) \tilde{X} = \text{cat}(\text{MP}(X_3, 3), \text{MP}(X_4, 3), \text{MP}(X_5, 3)) X~=cat(MP(X3,3),MP(X4,3),MP(X5,3))(Eq. 5),再按 Eq. 6 更新 WW W。
  • 检测头:微调到 COCO 后,把 80 个类名的文本嵌入存进分类层的权重(附录 A.2)。

论文没有明说的一点:I-Pooling 的输出 W′W' W′ 随图像变化,用 W′W' W′ 的自底向上 T-CSPLayer 折不进固定权重,v1 模型"重参数化"之后这几处仍要把 WW W 当输入算;能完全折掉的是自顶向下的两个 T-CSPLayer 和检测头(8.4 节)。


5. 实验(Sec. 4)

5.1 实现与预训练设置(Sec. 4.1--4.2)

  • 基于 MMYOLO 和 MMDetection,S / M / L 三档与 YOLOv8 对应;CLIP 文本编码器预训练时冻结。
  • 速度都在一张 V100 上测,不用 FP16、TensorRT 等加速(Table 6 例外,用了 TensorRT)。
  • 预训练:AdamW,初始学习率 0.002,weight decay 0.05;32 张 V100、总 batch 512,训练 100 epoch;数据增强有颜色、随机仿射、翻转、4 图 mosaic(配置里最后 2 个 epoch 关掉 mosaic)。
  • weight decay 与代码对不上:v1 配置写的是 weight_decay = 0.05 / 2,而优化器构造器(YOLOWv5OptimizerConstructor,照搬 YOLOv5 的做法)还会按"总 batch ÷ 64"放大,32 卡 × 16 = 512 时放大 8 倍,按代码推算实际是 0.2。单卡 batch 16 微调时放大倍数是 1。
数据 类型 词表 图像 标注
Objects365V1 检测 365 609k 9,621k
GQA Grounding -- 621k 3,681k
Flickr30k Grounding -- 149k 641k
CC3M† 图文(伪标注) -- 246k 821k

(来源:论文 Table 1。按 GLIP 的做法,GoldG(GQA + Flickr30k)里去掉了 COCO 的图。)

  • 零样本评测:预训练完直接在 LVIS 上测,LVIS 有 1203 类,远多于预训练检测数据的类别数。和前人一样主要用 LVIS minival(MDETR 划出的子集;实测 4809 张图、50,672 个框,全部来自 COCO val2017),报 Fixed AP(Dave et al. 2021),每张图最多 1000 个预测。

5.2 LVIS 零样本(Table 2)

方法 骨干 参数量 预训练数据 FPS AP APr APc APf
MDETR R-101 169M GoldG -- 24.2 20.9 24.3 24.2
GLIP-T Swin-T 232M O365, GoldG 0.12 24.9 17.7 19.5 31.0
GLIP-T Swin-T 232M O365, GoldG, Cap4M 0.12 26.0 20.8 21.4 31.0
GLIPv2-T Swin-T 232M O365, GoldG 0.12 26.9 -- -- --
GLIPv2-T Swin-T 232M O365, GoldG, Cap4M 0.12 29.0 -- -- --
Grounding DINO-T Swin-T 172M O365, GoldG 1.5 25.6 14.4 19.6 32.2
Grounding DINO-T Swin-T 172M O365, GoldG, Cap4M 1.5 27.4 18.1 23.3 32.7
DetCLIP-T Swin-T 155M O365, GoldG 2.3 34.4 26.9 33.9 36.3
YOLO-World-S YOLOv8-S 13M (77M) O365, GoldG 74.1 (19.9) 26.2 19.1 23.6 29.8
YOLO-World-M YOLOv8-M 29M (92M) O365, GoldG 58.1 (18.5) 31.0 23.8 29.2 33.9
YOLO-World-L YOLOv8-L 48M (110M) O365, GoldG 52.0 (17.6) 35.0 27.1 32.8 38.3
YOLO-World-L YOLOv8-L 48M (110M) O365, GoldG, CC3M† 52.0 (17.6) 35.4 27.6 34.1 38.0

(来源:论文 Table 2,LVIS minival、Fixed AP。括号外是重参数化后的参数量和 FPS,括号内是带文本编码器的原始版本;FPS 在 V100 上测,不用 TensorRT。)

  • 同样只用 O365 + GoldG,YOLO-World-L(35.0)比 GLIP-T(24.9)、Grounding DINO-T(25.6)高约 10 AP;去掉文本编码器后的参数量(48M)只有它们的 1/5 到 1/3.6。
  • 和最强的 DetCLIP-T 比:35.4 对 34.4,速度 52.0 对 2.3 FPS(约 22.6 倍,论文说"20×")。
  • 13M 参数的 YOLO-World-S 也有 26.2 AP,与 GLIP-T 相当:小模型也能做视觉-语言预训练。
  • 括号里的数字说明了离线词表的意义:带文本编码器每张图都编码 1203 个类名时,三档模型只有 17.6--19.9 FPS,瓶颈在文本编码器,与检测器大小几乎无关(9.4 节实测)。
  • 这张表和 Table 3 的同一个模型数字对不上(35.0 对 32.5),原因在评测口径,见 9.3 节。

5.3 消融(Sec. 4.3,Table 3--5)

消融都用 YOLO-World-L,只在 Objects365 上预训练(除非另说明),在 LVIS minival 上零样本评测。

预训练数据(Table 3):

预训练数据 AP APr APc APf
O365 23.5 16.2 21.1 27.0
O365, GQA 31.9 22.5 29.9 35.4
O365, GoldG 32.5 22.3 30.6 36.0
O365, GoldG, CC3M† 33.0 23.6 32.0 35.5
  • 加 GQA 涨 8.4 AP:GQA 的名词短语比 O365 的 365 个类名丰富得多,对大词表检测帮助最大。
  • 再加约 8% 的 CC3M 伪标注数据:+0.5 AP、+1.3 APr。
  • 注意:O365, GoldG 这一行(32.5)和加 CC3M 的一行(33.0)与 Table 2 的同配置模型(35.0、35.4)差了约 2.5 AP,论文没有解释;官方模型库给这两个权重标的也是 32.5、33.0。见 9.3 节。

RepVL-PAN(Table 4):

GQA T→I I→T AP APr APc APf
✗ ✗ ✗ 22.4 14.5 20.1 26.0
✗ ✓ ✗ 23.2 15.2 20.6 27.0
✗ ✓ ✓ 23.5 16.2 21.1 27.0
✓ ✗ ✗ 29.7 21.0 27.1 33.6
✓ ✓ ✓ 31.9 22.5 29.9 35.4

(T→I 是 T-CSPLayer,I→T 是 I-Pooling Attention;两者都不加就是 YOLOv8 原来的 PAN。)

  • 只用 O365 时 RepVL-PAN 带来 +1.1 AP(22.4 → 23.5),主要涨在稀有类(APr +1.7);加了 GQA 后收益变成 +2.2 AP。作者的解释:GQA 有丰富的名词短语,RepVL-PAN 在文本信息多时更有用。
  • 两个模块的单独贡献只在 O365 设置下拆开过:T→I +0.8、I→T +0.3。有 GQA 时没有拆。
  • 表格之间的对应:Table 4 最后一行就是 Table 3 的 "O365, GQA";Table 4 第一行(22.4 / 14.5 / 20.1 / 26.0)与 Table 5 的 "CLIP-base 冻结" 完全相同,说明 Table 5 的文本编码器消融是在不带 RepVL-PAN 的基线上做的。

文本编码器(Table 5):

文本编码器 训练方式 AP APr APc APf
BERT-base 冻结 14.6 3.4 10.7 20.0
BERT-base 微调 18.3 6.6 14.6 23.6
CLIP-base 冻结 22.4 14.5 20.1 26.0
CLIP-base 微调 19.3 8.6 15.7 24.8

(微调时文本编码器的学习率是基础学习率的 0.01 倍。)

  • CLIP 明显好于 BERT,稀有类差得最多:冻结时 APr 14.5 对 3.4。正文写"+10.1 AP for rare categories",但表里 14.5 − 3.4 = 11.1,任何一对组合都算不出 10.1,应是笔误。
  • 微调 BERT 有用(+3.7 AP),微调 CLIP 反而掉 3.1 AP、APr 掉 5.9:O365 只有 365 个类,文本太单一,微调会破坏 CLIP 原有的泛化能力。工程上的含义:数据词表不丰富时,文本编码器别动。

5.4 微调(Sec. 4.4)

设置:用预训练权重初始化,80 epoch,AdamW,初始学习率 0.0002,CLIP 文本编码器的学习率乘 0.01。

COCO(Table 6):

方法 预训练 AP AP50 AP75 FPS
YOLOv6-S / M / L ✗ 43.7 / 48.4 / 50.7 60.8 / 65.7 / 68.1 47.0 / 52.7 / 54.8 442 / 277 / 166
YOLOv7-T / L / X ✗ 37.5 / 50.9 / 52.6 55.8 / 69.3 / 70.6 40.2 / 55.3 / 57.3 404 / 182 / 131
YOLOv8-S / M / L ✗ 44.4 / 50.5 / 52.9 61.2 / 67.3 / 69.9 48.1 / 55.0 / 57.7 386 / 238 / 159
YOLO-World-S(零样本) O+G 37.6 52.3 40.7 --
YOLO-World-M(零样本) O+G 42.8 58.3 46.4 --
YOLO-World-L(零样本) O+G 44.4 59.8 48.3 --
YOLO-World-L(零样本) O+G+C 45.1 60.7 48.9 --
YOLO-World-S(微调,带 RepVL-PAN) O+G 45.9 62.3 50.1 --
YOLO-World-M(微调,带 RepVL-PAN) O+G 51.2 68.1 55.9 --
YOLO-World-L(微调,带 RepVL-PAN) O+G+C 53.3 70.1 58.2 --
YOLO-World-S(微调,去掉 RepVL-PAN) O+G 45.7 62.3 49.9 373
YOLO-World-M(微调,去掉 RepVL-PAN) O+G 50.7 67.2 55.1 231
YOLO-World-L(微调,去掉 RepVL-PAN) O+G+C 53.3 70.3 58.1 156

(来源:论文 Table 6。O、G、C 分别是 Objects365、GoldG、CC3M†;YOLOv7、YOLOv8 的数字取自 MMYOLO;FPS 在 V100 上用 TensorRT 测,与 Table 2 口径不同。)

  • 零样本:没见过 COCO 标注的 YOLO-World-L 有 44.4--45.1 AP,与从头训练 500 epoch 的 YOLOv8-S(44.4)相当。
  • 微调:去掉 RepVL-PAN 后(附录 A.2:COCO 只有 80 类,对图文交互依赖小),结构基本就是 YOLOv8 加一个由文本嵌入初始化的分类层,比 YOLOv8 高 +1.3 / +0.2 / +0.4 AP(S / M / L)。也就是说,在 COCO 这种数据充足的场景,138 万到 163 万张图的视觉-语言预训练只换来很小的提升,S 最明显。
  • 带不带 RepVL-PAN 对 COCO 微调结果影响很小(S 45.9 对 45.7、L 53.3 对 53.3)。

LVIS(Table 7):只在 LVIS-base(common + frequent)上微调,在全部 1203 类上评测,稀有类(APr)相当于零样本:

方法 AP APr APc APf
ViLD 27.8 16.7 26.5 34.2
RegionCLIP 28.2 17.1 -- --
Detic 26.8 17.8 -- --
FVLM 24.2 18.6 -- --
DetPro 28.4 20.8 27.8 32.4
BARON 29.5 23.2 29.3 32.5
YOLOv8-S / M / L 19.4 / 23.1 / 26.9 7.4 / 8.4 / 10.2 17.4 / 21.3 / 25.4 27.0 / 31.5 / 35.8
YOLO-World-S / M / L 23.9 / 28.8 / 34.1 12.8 / 15.9 / 20.4 20.4 / 24.6 / 31.1 32.7 / 39.0 / 43.5

(来源:论文 Table 7。YOLOv8 在完整 LVIS(含稀有类)上训练,并用了类别均衡采样。)

  • YOLO-World-L 比 YOLOv8-L 高 7.2 AP、10.2 APr:YOLOv8 见过稀有类的标注,YOLO-World 没见过,稀有类反而高一倍。大词表、长尾的场景是预训练收益最大的地方。
  • 与两阶段的 OVD 方法比,YOLO-World-L 的总 AP(34.1)最高;但稀有类 20.4 低于 BARON(23.2)和 DetPro(20.8)。论文说"整体性能超过两阶段方法",指的是总 AP。

5.5 开放词表实例分割(Sec. 4.5,Table 8)

在 YOLO-World 上加分割头,两种设定:COCO → LVIS(在 COCO 80 类的 mask 上微调,迁移到 1203 类)、LVIS-base → LVIS(在 866 个 common + frequent 类上微调);两种策略:只训分割头、全部微调。评测在 LVIS val 上做,337 个稀有类没见过。

模型 微调数据 微调模块 AP APr APc APf 框 AP 框 APr
YOLO-World-M COCO 分割头 12.3 9.1 10.9 14.6 22.3 16.2
YOLO-World-L COCO 分割头 16.2 12.4 15.0 19.2 25.3 18.0
YOLO-World-M LVIS-base 分割头 16.7 12.6 14.6 20.8 22.3 16.2
YOLO-World-L LVIS-base 分割头 19.1 14.2 17.2 23.5 25.3 18.0
YOLO-World-M LVIS-base 全部 25.9 13.4 24.9 32.6 32.6 15.8
YOLO-World-L LVIS-base 全部 28.7 15.0 28.3 35.2 36.2 17.4

(来源:论文 Table 8,AP 是 mask AP。)

  • 只训分割头时检测器冻结,零样本能力完全保留;COCO 和 LVIS-base 的 APr / AP 比例几乎一样(L:76.5% 对 74.3%),差距来自 LVIS 的 mask 标注更细更密。
  • 全部微调:L 的 mask AP +9.6,但框的 APr 从 18.0 掉到 17.4,开放词表能力有所退化。
  • 只训分割头那几行的框 AP(M 22.3 / 16.2,L 25.3 / 18.0)与官方模型库里 v1 权重(M 是 O365+GoldG,L 是 +CC3M-Lite 的那个)在 LVIS val 上的零样本 AP 一字不差,可见这几行的框结果就是预训练检测器本身。

5.6 可视化(Sec. 4.6)

作者认为指代能力来自含大量名词短语的预训练数据(GQA、Flickr30k)。注意这些都是挑出来的例子,论文没有在指代检测基准(RefCOCO 等)上报数字。

5.7 附录 C:小模型要多少数据(Table 9)

模型 预训练数据 样本数 AP APr APc APf
YOLO-World-S O365 0.61M 16.3 9.2 14.1 20.1
YOLO-World-S O365 + GoldG 1.38M 24.2 16.4 21.7 27.8
YOLO-World-S O365 + CC3M-245k 0.85M 16.5 10.8 14.8 19.1
YOLO-World-S O365 + CC3M-520k 1.13M 19.2 10.7 17.4 22.4
YOLO-World-S O365 + CC3M-750k 1.36M 18.2 11.2 16.0 21.1

(来源:论文 Table 9,LVIS minival 零样本。)

  • 同样约 1.37M 个样本,人工标注的 GoldG(24.2)比伪标注的 CC3M-750k(18.2)高 6 AP:对小模型来说,标注质量远比数量重要。
  • 伪标注数据加到 750k 反而比 520k 低 1.0 AP(APr 仍在涨):噪声多了,小模型的容量吃不下。
  • 这张表里 S 的 O365 + GoldG 是 24.2,与官方模型库的 24.3 相近,而 Table 2 写的是 26.2,同样是口径问题(9.3 节)。

6. 相关工作的位置

路线 代表 做法 与 YOLO-World 的区别
基类训练 + 蒸馏 OVR-CNN、ViLD、RegionCLIP、DetPro、BARON 在基类上训练,从 CLIP 蒸馏或对齐区域特征,评新类 词表和数据都小,两阶段检测器
简单 ViT 检测器 OWL-ViT、OWLv2 CLIP 的 ViT 直接接检测头,在检测、grounding 数据上微调 骨干是大 ViT,慢
grounding 预训练 GLIP、GLIPv2、Grounding DINO 检测当作短语定位,图文深度融合(每层交叉注意力) 在线词表,图文每次都要一起编码,重
区域-词对齐预训练 DetCLIP、DetCLIPv2 用词典丰富概念,大规模图文数据 精度接近,但慢 20 倍以上
YOLO 上的零样本 ZSD-YOLO 把 YOLO 与语言模型对齐(蒸馏) 没有大规模预训练,按基类 / 新类设定评

YOLO-World 的位置:结构上只在 YOLOv8 上做轻量改动(文本对比头 + 两个融合模块),把性能主要交给大规模区域-文本预训练;部署上用离线词表绕开文本编码器。


7. 论文之后:官方仓库的 v2 和 v2.1

论文对应官方仓库里的"v1"(configs/pretrain_v1/,README 标注"几乎已弃用")。之后的主要改动:

  • v2(2024-02-29) :
    • 去掉 I-Pooling Attention:它对 LVIS 零样本有帮助,但导出 ONNX、TensorRT 后拖慢推理;
    • 对比头里的 L2 归一化换成 BatchNorm:L2 归一化含 reduce 操作,部署慢,BN 可以融进卷积,零样本精度还更高;
    • 支持"重参数化微调":把词表嵌入折进检测头的 1×1 卷积(RepBNContrastiveHead)和 neck 的 1×1 卷积(RepConvMaxSigmoidAttnBlock)后再微调,官方说 COCO 上 46.3 对普通微调的 46.1 AP。
  • v2.1(2025-02) :
    • 补齐词:此前训练时词表不足 80 个就用空字符串补齐,且不加掩码;官方发现这样做 LVIS 能高 2--3 AP,补齐词起了"背景嵌入"的作用,但副作用是推理时通常要额外加一个补齐词才有合理结果。v2.1 在分类损失里给补齐词加了掩码,T-CSPLayer 里仍保留;
    • 伪标注数据重做:用 RAM++ 打标签、YOLO-World-X-v2 打框,重标了 250k 张 CC3M(CC-LiteV2);
    • 图像提示:用 CLIP 图像编码器 + 一个 MLP 适配器把"示例框"编码成嵌入,替换文本嵌入。
  • 官方模型库各版本的 LVIS minival 数字(L,640):v1 32.5 / 33.0(O365+GoldG / +CC3M-Lite)、v2 33.0 / 33.4、v2.1 33.8。这些都比论文 Table 2 的 35.0 / 35.4 低,口径的差别见 9.3 节。

8. 核心代码(个人实现,已对拍)

完整脚本在本库 Detection_Notes/repro/yoloworld/:yoloworld_core.py 是实现,parity_core.py 是对拍。只实现论文新增的计算;卷积 + BN、Linear 这类标准层直接借用官方模块里的参数。

8.1 文本对比头(Eq. 1)

python 复制代码
def contrastive_logits(e, w, logit_scale, bias):
    """e: B×D×H×W(分类分支输出的区域嵌入),w: B×C×D(词表的文本嵌入)→ B×C×H×W"""
    e = F.normalize(e, dim=1)
    w = F.normalize(w, dim=-1)
    return torch.einsum("bdhw,bcd->bchw", e, w) * logit_scale.exp() + bias
  • 每个位置对每个词的分数,就是区域嵌入与词嵌入的余弦相似度乘 α\alpha α(初值 1/0.07≈14.31/0.07 \approx 14.3 1/0.07≈14.3)再加 β\beta β;训练时过 sigmoid,每个词独立做二分类。
  • 换词表不用改网络, ww w 换成新的 C×512C \times 512 C×512 矩阵就行, CC C 可以是 1,也可以是几千。

8.2 T-CSPLayer 的 max-sigmoid 注意力(Eq. 2)

python 复制代码
def max_sigmoid_attn(x, w, blk):
    B, _, H, W = x.shape
    m, d = blk.num_heads, blk.head_channels                         # 每头 d = 32 维
    g = blk.guide_fc(w).view(B, -1, m, d)                            # 文本:Linear → B×C×m×d
    e = blk.embed_conv(x).view(B, m, d, H, W)                        # 图像:1×1 卷积 + BN
    a = torch.einsum("bmdhw,bcmd->bmhwc", e, g).amax(-1)             # 每个位置对 C 个词取最大
    a = (a / d ** 0.5 + blk.bias.view(1, m, 1, 1)).sigmoid()
    y = blk.project_conv(x).view(B, m, -1, H, W) * a.unsqueeze(2)    # 被门控的是 3×3 卷积后的特征
    return y.view(B, -1, H, W)
  • 计算量与词表大小 CC C 成正比:每个位置、每个头都要和 CC C 个词算点积再取最大。 C=1203C = 1203 C=1203 时,P3 层(80×80)的一个头就要算 6,400 × 1,203 个点积。
  • 用的是 max 而不是 softmax:只问"这个位置像不像词表里的某个东西",不管像哪个。所以往词表里加词只会让门控更宽松,不会让某个词的分数变低(9.5 节)。

8.3 I-Pooling Attention(Eq. 3)

python 复制代码
def image_pooling_attn(w, feats, ipa):
    B = feats[0].shape[0]
    toks = torch.cat([F.adaptive_max_pool2d(p(f), 3).flatten(2)        # 每层 1×1 卷积到 256 维,再池化成 3×3
                      for f, p in zip(feats, ipa.projections)], 2).transpose(1, 2)   # B×27×256
    h, d = ipa.num_heads, ipa.head_channels                             # 8 头 × 32 维
    q = ipa.query(w).view(B, -1, h, d).transpose(1, 2)                  # LayerNorm + Linear(512→256)
    k = ipa.key(toks).view(B, -1, h, d).transpose(1, 2)
    v = ipa.value(toks).view(B, -1, h, d).transpose(1, 2)
    o = F.softmax(q @ k.transpose(-1, -2) / d ** 0.5, dim=-1) @ v       # 每个词在 27 个图像 token 上做注意力
    return w + ipa.proj(o.transpose(1, 2).reshape(B, -1, h * d)) * ipa.scale
  • 只有 27 个 key,比在整张特征图(640 输入时三层共 8,400 个位置)上做交叉注意力便宜得多。
  • softmax 在 27 个图像 token 上做,不在词之间做,所以各个词的更新互不影响。

8.4 重参数化:把离线词表折进卷积

python 复制代码
class RepContrastHead(nn.Module):
    """检测头折叠后:L2 归一化 + 1×1 卷积(权重 = α·w/|w|,偏置 = β),forward 不再需要文本"""
    def __init__(self, contrast, w):
        super().__init__()
        wn = F.normalize(w, dim=-1)                                     # C×D
        self.conv = nn.Conv2d(wn.shape[1], wn.shape[0], 1)
        with torch.no_grad():
            self.conv.weight.copy_((wn * contrast.logit_scale.exp())[:, :, None, None])
            self.conv.bias.fill_(float(contrast.bias))

    def forward(self, x, w=None):
        return self.conv(F.normalize(x, dim=1))

class RepMaxSigmoidAttn(nn.Module):
    """自顶向下的 T-CSPLayer 用原始 W:guide_fc(W) 只算一次,按头拆成 m 个 1×1 卷积(各 C 个输出)"""
    def __init__(self, blk, w):
        super().__init__()
        self.m, self.d = blk.num_heads, blk.head_channels
        self.embed_conv, self.project_conv, self.bias = blk.embed_conv, blk.project_conv, blk.bias
        with torch.no_grad():
            g = blk.guide_fc(w)                                         # C×(m·d)
        self.convs = nn.ModuleList()
        for i in range(self.m):
            conv = nn.Conv2d(self.d, g.shape[0], 1, bias=False)
            with torch.no_grad():
                conv.weight.copy_(g[:, i * self.d:(i + 1) * self.d, None, None])
            self.convs.append(conv)

    def forward(self, x, w=None):
        B, _, H, W = x.shape
        e = self.embed_conv(x)
        a = torch.stack([c(t) for c, t in zip(self.convs, e.split(self.d, 1))], 1).amax(2)   # B×m×H×W
        a = (a / self.d ** 0.5 + self.bias.view(1, -1, 1, 1)).sigmoid()
        y = self.project_conv(x).view(B, self.m, -1, H, W) * a.unsqueeze(2)
        return y.view(B, -1, H, W)

reparameterize_v1(model, w) 把检测头三层的对比头换成 RepContrastHead,把自顶向下两个 T-CSPLayer 的注意力换成 RepMaxSigmoidAttn:

  • 折得掉的 :检测头和自顶向下的两个 T-CSPLayer,它们用的是原始 WW W。
  • 折不掉的 :I-Pooling Attention 和自底向上的两个 T-CSPLayer,它们用的 W′W' W′ 随图像而变, WW W 仍要作为常量输入。附录 A.1 的 Eq. 5--6 只是 I-Pooling 的简化写法,没有说它能折成固定权重。
  • 检测头里的 L2 归一化折不掉,要逐位置做 reduce,这是 v2 把它换成 BN 的原因之一(BN 能融进前面的卷积)。

8.5 与官方实现对拍

parity_core.py:在官方 v1 模型上挂 hook,取 4 张 COCO val2017 图(id 139、285、632、724),词表是 LVIS 的 1203 类,严格 FP32(关掉 TF32)。

对拍项 S M L L(+CC3M)
max-sigmoid(4 处)、I-Pooling、对比头(3 层)与官方模块的最大绝对差 0 0 0 0
重参数化前后分类 logits 的最大差 4.5e-4 8.1e-3 2.0e-4 4.5e-3
重参数化前后框回归的最大差 1.3e-4 9.4e-5 2.1e-4 3.7e-4
最终检测(NMS 后每图 300 个)按集合比较,对不上的框 0 0 0 0
  • 前三处新计算逐元素相同,说明 8.1--8.3 的理解与官方实现一致(包括多头、√d 缩放、偏置、门控 3×3 卷积后的特征这些论文没写的细节)。
  • 重参数化前后的差别来自卷积与 einsum 的累加顺序不同(logits 的取值范围约 −40 到 2.5),属于浮点误差。S 有一张图里两个分数几乎相同的框(差 < 4e-6)换了先后顺序,按集合比较完全一致。
  • 能用原始 WW W 把检测头折掉并得到同样的输出,也直接证明了 4.3 节表格最后一行:代码里检测头用的是原始 WW W,不是 I-Pooling 之后的 W′W' W′。

9. 动手验证(个人实验)

全部在 AutoDL 的一张 RTX 4080 SUPER(32GB)上完成:Python 3.10,PyTorch 2.0.1 + CUDA 11.8,mmcv 2.0.1、mmdet 3.0.0、mmengine 0.10.3、mmyolo 0.6.0(官方仓库的子模块),transformers 4.36.2,版本照官方 requirements/basic_requirements.txt。脚本、配置和结果(json)都在本库 Detection_Notes/repro/yoloworld/,入口和重跑方法见其中的 README.md。

权重是论文版(v1)的四个预训练模型,从 HF wondervictor/YOLO-World 下载,文件名末尾的 8 位 sha256 前缀都核对过(18bea4d2、2b7bd1be、0e566235、7a5eea3b);文本编码器 openai/clip-vit-base-patch32。LVIS minival 标注用 GLIP 在 HF 上发布的 lvis_v1_minival_inserted_image_name.json(官方评测用的同一份),COCO val2017 用 AutoDL 公共数据盘上的官方压缩包。没有训练的实验都不涉及随机性;DeepPCB 微调每组用随机种子 0--3 各跑一次(9.7 节)。

9.1 环境与官方代码的几个坑

  1. master 分支 import 不了 :最新提交 1f12bca("add mask",2025-02-26)在 yolo_world/models/detectors/yolo_world.py 里写了 self.text_feats, None = self.backbone.forward_text(texts),Python 直接报 SyntaxError,import yolo_world 都过不去;同一个提交里检测头 loss() 传给 loss_by_feat 的参数也错位了,训练也跑不了。本笔记固定在它前一个提交 b1b09f2(2025-02-06),子模块 mmyolo 跟着这个提交走。
  2. LVIS 评测在最后一步崩 :PyPI 上的 lvis 0.5.3 在 LVISEval.accumulate() 里用了 np.float,numpy 1.24 以后删掉了这个别名。报错发生在所有匹配都算完之后:官方 tools/test.py 在 LVIS minival 上推理了 73 分钟,最后一步崩掉,什么也没留下。改法是把那两行的 np.float 换成 np.float64(setup_env.sh 里用 sed 改)。
  3. 装包 :新版 setuptools 去掉了 pkg_resources,PyTorch 2.0.1 的 torch.utils.cpp_extension 还要 import 它,装 mmyolo 时失败,要固定 setuptools==69.5.1;YOLO-World 的 pyproject.toml 依赖 mmcv-lite,会和带算子的 mmcv 冲突,要 --no-deps;两个包的 setup 都要 import torch,要 --no-build-isolation。
  4. 评测的后处理比模型慢几十倍 :官方 LVIS 评测设置是 score_thr=0.001、nms_pre=30000、多标签。1203 个类时候选框远超 mmcv batched_nms 的 split_thr(默认 1 万),NMS 就按类别逐个循环,单独占用 GPU 时每张图也要 0.35--0.41 秒(9.4 节),是模型前向的 35--44 倍。四个模型并行在一张卡上评 LVIS minival,每个跑了 1 小时左右。

9.2 参数量复算(Table 2)

模型 总参数 其中 CLIP 文本编码器 去掉文本编码器 Table 2 再折进 1203 类词表 同规模 YOLOv8
S 76,811,576 63,428,096 13,383,480 13M (77M) 15,367,371 11,166,544
M 92,493,390 63,428,096 29,065,294 29M (92M) 31,115,425 25,902,624
L 110,982,050 63,428,096 47,553,954 48M (110M) 49,670,325 43,691,504
  • 括号内外都对上了:括号里是含文本编码器的总参数,括号外是去掉文本编码器之后。
  • 相比同规模 YOLOv8,YOLO-World 多了 2.2M(S)、3.2M(M)、3.9M(L)。其中 neck 里与文本直接相关的参数(guide_fc、I-Pooling、注意力偏置)是 0.92M、1.09M、1.18M,其余来自 T-CSPLayer 多出的那一支卷积,以及分类分支最后输出 512 维嵌入(YOLOv8 只输出 80 个通道)。
  • L 的构成:图像骨干 19.81M、neck 21.77M、检测头 5.98M。
  • 把 1203 类的词表折进卷积后多出约 2M 参数,主要是检测头三层各一个 1203×512 的 1×1 卷积。

9.3 同一个模型,35.0 还是 32.5:LVIS 的两种 AP 口径(GPU)

论文 Table 2 的 YOLO-World-L(O365+GoldG)是 35.0 AP,同一配置在 Table 3 里是 32.5,官方模型库给同一个权重标的也是 32.5;S、M 在 Table 2 里是 26.2、31.0,模型库是 24.3、28.6。论文 4.2 节说 Table 2 报的是 Fixed AP(Dave et al. 2021)、每图最多 1000 个预测,而官方配置用的是 mmdet.LVISMetric,后者调用 LVIS API 的默认设置:每张图只保留分数最高的 300 个框。猜测两组数字的差别就在这里。

做法:四个模型都按官方配置推理 LVIS minival(4,809 张图),只把每图最多保留的框数从 300 改成 1000,存下全部检测结果(每个模型约 475 万个框),再用同一份结果按三种口径打分(infer_lvis.py、lvis_ap.py):

  • 标准 AP:每图保留分数最高的 300 个,LVIS API 默认(官方配置就是这样);
  • Fixed AP :照 Dave et al. 的 evaluate_ap_fixed.py,不限每图的个数,每个类别在整个数据集上最多 1 万个;
  • fixed300:每图先截到 300 个,再按 Fixed AP 的规则算,用来分开"每图上限"和"每类上限"两处差别。
模型 标准 AP(每图 300) 官方模型库 fixed300 Fixed AP(每图 1000) 论文 Table 2
S 24.33 / 16.56 / 22.12 / 27.69 24.3 / 16.6 / 22.1 / 27.7 24.32 26.38 / 19.06 / 24.12 / 29.70 26.2 / 19.1 / 23.6 / 29.8
M 28.55 / 19.75 / 26.57 / 31.90 28.6 / 19.7 / 26.6 / 31.9 28.55 30.98 / 23.85 / 29.15 / 33.89 31.0 / 23.8 / 29.2 / 33.9
L 32.44 / 22.35 / 30.39 / 36.08 32.5 / 22.3 / 30.6 / 36.1 32.44 34.98 / 27.13 / 32.83 / 38.29 35.0 / 27.1 / 32.8 / 38.3
L(+CC3M) 32.96 / 23.59 / 32.01 / 35.48 33.0 / 23.6 / 32.0 / 35.5 32.96 35.48 / 27.64 / 34.21 / 38.02 35.4 / 27.6 / 34.1 / 38.0

(四个数依次是 AP / APr / APc / APf。官方模型库的数来自 configs/pretrain_v1/README.md。)

  • 猜测成立 :同一份检测结果,按标准 AP 算就是模型库的数,按 Fixed AP 算就是 Table 2 的数。Fixed AP 与 Table 2 比:L 四项四舍五入后完全相同,M 每项差 0.05 以内,L(+CC3M)差 0.1 左右,S 的 AP、APc 高了 0.2、0.5(可能是论文用的权重或推理细节与公开版略有不同)。标准 AP 与模型库比:S、L(+CC3M)四项相同,M 差 0.05 以内,L 的 APc 低 0.2。为了确认这不是我的评测流程的问题,又用官方 tools/test.py 和官方配置(每图 300 个、mmdet.LVISMetric)把 L 完整跑了一遍:32.4 / 22.3 / 30.4 / 36.1,与我的标准 AP 在官方输出的精度上完全一致,模型库的 30.6 应该来自别的评测环境。
  • 差别全部来自"每图 300 个还是 1000 个":fixed300 与标准 AP 几乎相同,"每类最多 1 万个"这条在这里不起作用。右图是 Fixed AP 随每图上限的变化:L 从 100 个时的 28.1 涨到 1000 个时的 35.0,到 1000 还没饱和。
  • 涨的主要是稀有类:从 300 到 1000,AP 涨 2.0--2.5,APr 涨 2.5--4.8(L:22.35 → 27.13)。1203 个类同时抢每张图 300 个名额,稀有类的正确检测分数偏低,最先被挤掉。这正是 Dave et al. 提出 Fixed AP 的理由:大词表下每图 300 个的上限会系统性地压低稀有类。
  • 影响 :
    • Table 2 与 Table 3、4、5、9 不是同一个口径,同一个模型差了约 2.5 AP,论文没有交代。消融表内部的相对比较不受影响,但不能拿 Table 2 的数和消融表比。
    • 照官方配置复现得到 32.5 而不是 35.0,并不是复现失败。
    • Table 2 里其他方法的数取自各自的论文,作者说是按前人的做法报 Fixed AP,但每图上限是否都是 1000 无从核对。
    • 实际部署不会每张图留 1000 个框;Fixed AP 奖励的是低分的长尾检测,做应用时要看自己实际使用的阈值和每图上限下的结果。

9.4 推理速度:文本编码器、离线词表、重参数化(GPU)

bench_speed.py:batch 1,640×640(一张真实的 COCO 图),只计前向到检测头输出,不含 NMS;FP32 且关掉 TF32(与 V100 的 FP32 一致),每项预热 30 次、取 200 次的中位数,测速时 GPU 上没有别的任务。

S M L
论文(V100):重参数化 / 原始版本 74.1 / 19.9 FPS 58.1 / 18.5 FPS 52.0 / 17.6 FPS
在线:每张图都编码 1203 个类名 59.4 ms(16.8 FPS) 55.7 ms(18.0 FPS) 58.2 ms(17.2 FPS)
其中文本编码器(含分词) 47.4 ms 48.3 ms 48.9 ms
离线词表(1203 类) 7.84 ms(127.6 FPS) 9.63 ms(103.9 FPS) 10.88 ms(91.9 FPS)
再把词表折进卷积 7.52 ms(133.0 FPS) 9.35 ms(107.0 FPS) 10.91 ms(91.7 FPS)
同规模 YOLOv8(80 类) 5.48 ms(182.5 FPS) 6.37 ms(157.0 FPS) 8.24 ms(121.4 FPS)
离线词表,FP16(autocast) 10.71 ms 12.68 ms 14.10 ms
后处理:官方 LVIS 评测设置 346 ms 407 ms 378 ms
后处理:部署设置(score 0.25、NMS 前 1000、每图 100) 1.43 ms 1.28 ms 1.30 ms
  • "原始版本"慢在文本编码器:在线跑法里文本编码器占 80%--87%,三档模型都是 17--18 FPS,与论文括号里的 19.9 / 18.5 / 17.6(V100)几乎一样:瓶颈不在检测器,换更快的 GPU 也没用。
  • 离线词表是收益最大的一步:比在线快 5.3(L)到 7.6 倍(S)。4080 SUPER 上 S / M / L 分别 128 / 104 / 92 FPS,比论文 V100 上的 74 / 58 / 52 快。
  • "折进卷积"本身在 PyTorch 里几乎不提速:词表 ≤1203 时最多快 4%(S),词表上到 4000、10000 反而更慢(L:15.8 对 14.2 ms、25.8 对 21.8 ms),因为每个头单独一个卷积再 stack,kernel 数变多了。重参数化的价值在部署:导出 ONNX、TensorRT 时网络里只剩卷积和逐元素运算,形状固定,不需要文本编码器。
  • 开放词表的代价:同规模下离线词表的 YOLO-World 比 YOLOv8 慢 2.4--3.3 ms,速度是 YOLOv8 的 66%--76%。
  • 词表大小:到 1203 个词,耗时几乎不变(L 10.5 → 10.9 ms,S 7.0 → 7.2 ms):batch 1 时这几个模型受 kernel 启动开销限制,算力没用满;4000 个词 14.2 ms、1 万个 21.8 ms(L)。
  • FP16 在 batch 1 时更慢:autocast 要插入大量类型转换 kernel,YOLOv8 也一样(L:10.2 对 8.2 ms)。小模型在消费级卡上要靠 TensorRT 或 CUDA Graph 才能把 FP16 的好处拿出来。
  • 后处理:官方评测设置下 1203 类的后处理每张图 0.35--0.41 秒,是前向的 35--44 倍;部署常用设置只要 1.3--1.4 ms。论文没有说 FPS 是否含后处理,从数字看应该不含。

9.5 COCO 零样本,以及离线词表怎么定(GPU)

eval_coco_vocab.py:COCO val2017 全部 5,000 张,后处理用官方 YOLOv8 的 COCO 设置(score_thr 0.001、nms_pre 30000、IoU 0.7、每图 300 个),pycocotools 打分。为了让 1000 多个词的跑法不至于每张图 1 秒,所有跑法统一调大了 mmcv NMS 的 split_thr(按类别加坐标偏移、一次做完,结果等价);用默认 NMS 重跑 L(+CC3M)的 80 类词表,AP 同样是 45.13,两种做法没有差别。

先看能否复现 Table 6 的零样本一栏:

模型 实测 AP / AP50 / AP75 论文 Table 6
S 37.28 / 51.90 / 40.54 37.6 / 52.3 / 40.7
M 41.88 / 56.98 / 45.51 42.8 / 58.3 / 46.4
L 45.21 / 60.91 / 49.23 44.4 / 59.8 / 48.3
L(+CC3M) 45.13 / 60.75 / 48.95 45.1 / 60.7 / 48.9

L(+CC3M)完全复现;S、M 低 0.3、0.9,L(O365+GoldG)反而高 0.8,与 L(+CC3M)几乎一样。同一批权重在 LVIS 上与论文吻合(9.3 节),在 COCO 上有 ±1 AP 的出入,原因不明,可能 Table 6 的零样本一栏用的权重或设置与公开版不同。COCO 的打分(pycocotools,每图每类最多 100 个)没有 LVIS 那样的口径问题。

同一个模型(L + CC3M),只改离线词表:

离线词表 COCO AP 变化
80 个类名(官方 coco_class_texts.json) 45.13 --
套 CLIP 常用模板 "a photo of a {}." 42.28 −2.85
末尾加一个补齐词('' 或 ' ':CLIP 分词器会去掉空格,两者是同一个嵌入) 38.64 −6.49
同上,但补齐词只进 neck,检测头只给 80 个类打分 38.64 −6.49
加 1133 个与 COCO 不同名的 LVIS 类名作干扰词,只进 neck 42.06 −3.07
同上,正常后处理(干扰词也参与每图 300 个名额的竞争) 40.82 −4.31

(干扰词:LVIS 1203 类里,同义词与任何一个 COCO 类名都不相同的 1133 个;评测只算 80 个 COCO 类上的检测。)

只检测 person 时的词表 person 的 AP
80 个类名(照常检测,只看 person 一类) 62.21
只有 "person" 59.20
"person" + 补齐词 49.05
  • 词与词并不独立:检测头对每个词单独做 sigmoid,看起来词表里多一个词、少一个词互不影响;但 neck 里的 max-sigmoid 对整个词表取最大,词表一变,所有位置的特征都跟着变。"只进 neck"的两行把这部分单独拿了出来:干扰词的 −4.3 AP 里有 −3.1 来自 neck,剩下 −1.2 才是抢名额;补齐词的 −6.5 则全部来自 neck。
  • 补齐词:v1 的 L(+CC3M)加一个补齐词掉 6.5 AP,80 类里 75 类变差(donut −24.9、sheep −20.4);L(O365+GoldG)从 45.21 掉到 38.51,S 从 37.28 掉到 31.54。官方 V2.1 博客说之前的版本推理时"通常要加一个补齐词",至少对论文版 v1 权重、在 COCO 上,加了明显更差。补齐词在训练中只当负样本、出现在 grounding 数据补齐的位置,推理时加进去相当于把 neck 的门控整体打开(9.7 节 DeepPCB 上,加补齐词后每张图分数高于 0.001 的框从几个到几十个变成两百多个)。
  • 干扰词(大词表):把词表开到 1213 个,COCO 80 类的 AP 掉 4.3,69 类变差(bear −16.8、donut −13.2)。"词表开大一点、什么都检"是有代价的。
  • 只放一个词也不是最好:只检测 person 时,单独一个 "person" 的 AP(59.2)比放着 80 个类名时 person 一类的 AP(62.2)低 3.0。其他类名在 neck 里起了负样本的作用,帮模型把狗、熊这些不是人的东西排除掉。实际用的时候,词表 = 要检测的类别 + 场景里常见、容易混淆的其他物体(这些类别的检测结果丢掉)。
  • 模板 :训练时类名不加任何模板(prompt_format='{}'),推理时套 CLIP 的 "a photo of a {}." 掉 2.9 AP。提示词的写法要和训练时一致。

9.6 I-Pooling Attention 把文本嵌入改了多少

parity_core.py 对拍时顺带统计了 I-Pooling 前后的文本嵌入(4 张 COCO 图,LVIS 1203 类):

S M L L(+CC3M)
W′W' W′ 与 WW W 的余弦相似度:平均 / 最小 0.15 / 0.01 0.13 / −0.00 0.18 / 0.04 0.12 / −0.08
更新量的范数 ÷ WW W 的范数 3.9 4.5 4.7 3.9
词表里两两之间的平均余弦相似度: WW W 0.738 0.738 0.738 0.738
同上: W′W' W′(4 张图) 0.54--0.56 0.52--0.55 0.84--0.91 0.68--0.77
同一个词在两张图上的 W′W' W′ 的余弦相似度 0.50--0.92 0.61--0.96 0.61--0.97 0.54--0.97
  • I-Pooling 不是在原嵌入上做小修正:加上去的量是原嵌入的 4--5 倍, W′W' W′ 与 WW W 几乎正交,主要由图像决定,同一个词换一张图, W′W' W′ 的相似度可以低到 0.5。
  • L 的 1203 个 W′W' W′ 彼此更像了(0.84--0.91,原来 0.738):送进自底向上 T-CSPLayer 的"文本"已经不太区分是哪个词,更像一个按图像生成的门控信号。S、M 则相反,变得更分散。
  • 个人推测:这能解释 Table 4 里 I-Pooling 只贡献 0.3 AP,以及 v2 去掉它之后精度没掉(v2 同时把 L2 归一化换成了 BN,模型库里 v2-L 比 v1-L 还高 0.5 AP)。需要训练层面的消融才能确认,这里只是现象。
  • 检测头用的是原始 WW W(8.5 节),所以 Fig. 3 画的"图像感知嵌入送进检测头"在 v1 代码里并不存在。

9.7 工业缺陷:DeepPCB 上的零样本与微调(GPU)

论文说预训练好的 YOLO-World 能"很容易地迁移到下游任务",Table 6、7 也显示预训练对 COCO、LVIS 的微调有帮助。做工业质检更关心两件事:缺陷能不能零样本检出来;用 YOLO-World 的预训练权重做起点,微调是否比常用的 YOLOv8(COCO 预训练)更好、更省数据。

数据:DeepPCB(github.com/tangsanli5201/DeepPCB,README 写明仅限研究用途)。线扫 CCD 拍的 PCB,二值化后裁成 640×640,每张 3--12 个缺陷(大多是按缺陷样式人工加上去的),6 类:open(断路)、short(短路)、mousebite(鼠咬)、spur(毛刺)、spurious copper(多余铜)、pin-hole(针孔)。官方划分训练 1,000 张(6,873 个框)、测试 500 张(3,140 个框);另从训练集按固定种子抽 100 张(709 个框)作小数据设定。只用待测图,不用模板图。

做法:

  • 零样本 (eval_deeppcb_zeroshot.py):四个预训练模型,三套词表:官方简写(open、short、mousebite、spur、copper、pin-hole),描述性写法(open circuit、short circuit、mouse bite、spur、spurious copper、pin hole),描述性写法 + 补齐词。
  • 微调 (run_deeppcb.sh,两个配置在 configs/):
    • YOLO-World-L(+CC3M)照官方 COCO 微调配置:保留 RepVL-PAN,AdamW 2e-4、wd 0.05,文本编码器冻结,词表用描述性写法;
    • 对照组 YOLOv8-L 用 mmyolo 的 COCO 预训练权重(52.1 AP),分类层换成 6 类、随机初始化;
    • 两边的数据增强(mosaic、mixup、仿射、albu、HSV、翻转)、batch 16、优化器、EMA、轮数都相同:全量 40 轮,10% 子集 200 轮,最后 1/8 的轮数关掉 mosaic;都开 AMP;
    • 测试集上用 COCO 的 AP 评测(DeepPCB 官方脚本是 IoU 0.33 下的 mAP,这里另报 AP50 作参考);每组用随机种子 0、1、2、3 各跑一次。
全量(1000 张,40 轮) 10%(100 张,200 轮)
YOLO-World-L 零样本(四个模型、三套词表里最好的) AP 0.19,AP50 0.39 同左
YOLO-World-L 微调:AP 63.32 ± 3.16(65.8 / 65.7 / 62.7 / 59.1) 53.25 ± 6.69(57.2 / 54.3 / 58.0 / 43.5)
YOLOv8-L 微调:AP 63.77 ± 3.88(68.3 / 64.6 / 63.3 / 58.9) 60.38 ± 4.65(62.5 / 63.7 / 61.8 / 53.5)
YOLO-World-L 微调:AP50 / AP75 96.78 / 75.30 92.47 / 52.88
YOLOv8-L 微调:AP50 / AP75 96.57 / 76.28 93.70 / 69.12

(± 后是 4 个种子的样本标准差,括号里依次是种子 0--3;AP50、AP75 是 4 个种子的平均。)

各类别的 AP(4 个种子的平均):

类别 YOLO-World-L 全量 YOLOv8-L 全量 YOLO-World-L 10% YOLOv8-L 10%
open 58.6 58.5 47.5 53.8
short 56.1 55.9 44.2 49.3
mousebite 62.6 63.1 50.2 58.2
spur 62.1 63.1 49.6 57.4
spurious copper 74.1 75.2 70.1 75.0
pin-hole 66.4 66.9 57.9 68.7
  • 零样本完全不行:四个模型、三套词表,AP 都在 0.2 以下,AP50 不到 0.4。断路、毛刺、铜渣这些二值图上的局部图案不是自然图像里的"物体",CLIP 的文本空间里也没有对应的视觉概念;不加补齐词时,每张图分数高于 0.001 的框只有 3--66 个,加了补齐词变成 200 多个,但几乎都是错的。
  • 全量数据时打平:4 个种子的平均 63.3 对 63.8;按同一个种子配对,YOLO-World 减 YOLOv8 是 −2.5、+1.1、−0.6、+0.2,有正有负;各类别的平均差都在 1.1 AP 以内。开放词表预训练在这里既没有帮上忙,也没有拖后腿。
  • 10% 数据时 YOLOv8 更好 :平均 60.4 对 53.3,4 个种子上 YOLOv8 都领先(3.8--10.0 AP),6 个类别也全部领先,差得最多的是 pin-hole(+10.8)、mousebite(+8.0)、spur(+7.8)。与"预训练让微调更省数据"的直觉相反。个人推测:
    • YOLO-World 多出来的 RepVL-PAN 要适应一个与预训练完全不同的领域(二值化的 PCB 图),小数据下更难;
    • 分类由 "mouse bite"、"spur" 这类词的文本嵌入决定,这些嵌入与缺陷的外观毫无关系,相当于一个没有意义、却又固定住的分类方向,YOLOv8 随机初始化的分类层反而没有这个包袱;
    • 微调配方是 YOLO-World 官方的(AdamW 2e-4),对两边都没调参,结论限于这个配方。
  • 差别都在定位:AP50 两者接近(全量 96.8 对 96.6,10% 92.5 对 93.7),模型之间的差距、种子之间的波动都集中在 AP75(10%:52.9 对 69.1)。缺陷这类小目标要求框很准。
  • 随机种子的影响比模型还大:同一个配方只换种子,全量时 YOLO-World 在 59.1--65.8、YOLOv8 在 58.9--68.3 之间,10% 时 YOLO-World 在 43.5--58.0、YOLOv8 在 53.5--63.7 之间;种子 3 对两个模型都是最差的(种子决定数据顺序和随机增强),说明波动来自训练过程本身。只跑一次就比较两个模型,很容易得出相反的结论:只看种子 0,全量时 YOLOv8 高 2.5 AP;只看种子 1,YOLO-World 高 1.1 AP。本节最初只跑了种子 0,得出过"YOLOv8 全量高 2.5 AP"的错误结论,补到 4 个种子才看清。
  • 训练更慢:同样两组一起占一张卡时(种子 2、3),YOLO-World-L 的训练时间是 YOLOv8-L 的 1.2--1.4 倍(多了文本编码器和 RepVL-PAN)。

结论:工业缺陷检测不要指望 YOLO-World 的零样本;数据充足时它和 YOLOv8 打平,数据很少时反而更差,训练还更慢,不是比 YOLOv8 更好的微调起点。它的用处在别处:工厂里通用物体(人、车、工具、托盘、安全帽......)的零样本检测与预标注。另外,在小数据集上比较两个模型,至少要跑几个随机种子。


10. 讨论与个人思考

10.1 亮点

  1. 改动小、思路干净:分类层换成"物体嵌入与文本嵌入的缩放余弦相似度",neck 里加两个轻量的融合模块,标签分配和损失全部沿用 YOLOv8。开放词表的能力主要来自大规模区域-文本预训练,而不是复杂的结构,YOLOv8 的训练、部署工具链几乎都能复用。
  2. prompt-then-detect 抓住了真正的瓶颈:在线编码 1203 个类名时,文本编码器占推理时间的 80%--87%;词表离线编码后,S / M / L 回到同规模 YOLOv8 速度的 66%--76%(9.4 节)。这一点对工程的意义比结构创新更大。
  3. 小模型也能做视觉-语言预训练:13M 参数的 S 在 LVIS 上有 26.2 Fixed AP,与 232M 参数的 GLIP-T 相当;附录 C 还给出了"小模型重标注质量、伪标注加多了反而掉点"的数据。
  4. 伪标注流程实用:GLIP 打框 + CLIP 复核 + 阈值过滤,全自动,可以直接拿来给自己的数据做预标注。
  5. 开源完整,主要结果能复现:训练、评测、ONNX 导出、重参数化微调、图像提示都有代码和权重;按官方配置实测,L(+CC3M)的 COCO 零样本 45.13(论文 45.1),L 的 LVIS Fixed AP 34.98(论文 35.0)。

10.2 局限与疑问

  1. 评测口径没交代:Table 2 用 Fixed AP(每图 1000 个),消融表和官方模型库用 LVIS API 默认的每图 300 个,同一个模型差约 2.5 AP,论文只字未提(9.3 节)。
  2. 论文与代码多处对不上:Eq. 2 省略了多头、投影、缩放、偏置和门控前的 3×3 卷积;Fig. 3、4 画的第二个 I-Pooling 和"图像感知嵌入进检测头"在 v1 代码里都没有;附录 Eq. 6 写错;正文"稀有类 +10.1 AP"与 Table 5 算出来的 11.1 不符;weight decay 论文写 0.05,按代码推算是 0.2(4.3、5.1、5.3 节)。
  3. 消融不完整:T→I、I→T 只在 O365 设置下拆开(+0.8 / +0.3 AP);I-Pooling 在 v2 里被去掉,实测它几乎把文本嵌入换成了图像信息(9.6 节)。
  4. 离线词表的行为没有讲:训练时用空字符串补齐词表、不加掩码;推理时词与词并不独立(max-sigmoid 对整个词表取最大),加一个补齐词、加一堆干扰词、只留一个词都会明显掉点(9.5 节)。论文对"词表怎么定"没有任何指导。
  5. 离开自然图像就不行:DeepPCB 这种二值化的工业图像上零样本 AP 接近 0(9.7 节)。论文的零样本只在 LVIS 和 COCO 上测(两者是同一批 COCO 图),没有 ODinW 这类跨领域的基准。
  6. FPS 的测法没说清:是否含后处理、预处理,batch 多大;Table 6 又换成 TensorRT,与 Table 2 不可比。
  7. 指代检测只有可视化:Fig. 7 的例子没有 RefCOCO 之类的定量结果。
  8. 复现上的小出入:COCO 零样本 S、M 比 Table 6 低 0.3、0.9,L(O365+GoldG)高 0.8(9.5 节);同一批权重在 LVIS 上却与论文吻合,原因不明。

10.3 后续演进

  • 官方 v2 / v2.1(第 7 节):去掉 I-Pooling,L2 归一化换 BN,重参数化微调,补齐词在损失里加掩码,重做伪标注,图像提示。
  • YOLOE(2025):同样基于 YOLO,文本提示做成可重参数化的轻量适配,另加视觉提示和无提示模式,推理时可以折回普通 YOLO 的结构。
  • Grounding DINO 1.5 Edge(2024):Grounding DINO 一系面向边缘设备的轻量版,路线仍是图文深度融合。
  • Ultralytics 集成了 YOLO-World(yolov8s-world、yolov8s-worldv2 等),用 set_classes 设好离线词表再导出,就是 prompt-then-detect 的用法。

10.4 可借鉴之处

  • 给检测器加开放词表的最小改动:分类层换成与文本嵌入的相似度,或者用类名的文本嵌入初始化分类层。
  • "配置一次、推理很多次"的输入都可以预计算:离线词表、重参数化的思路适用于任何条件输入(提示词、模板、参考图)。
  • 评测要写明口径:大词表下 AP 对"每图保留多少个框"非常敏感(同一份结果,每图 100 个和 1000 个差约 7 AP),对比别人的数字之前先查清 AP 的定义和 maxDets。
  • 伪标注流程:开放词表检测器打框 + CLIP 复核 + 阈值,可以给工业数据做预标注,再人工核对。
  • 对视觉方向:开放词表检测器最适合做"通用物体"的零样本预标注和数据检索(在大量无标注图片里找出含某种物体的图),缺陷这类领域专属的目标还是要靠标注数据(9.7 节)。

11. 落地视角

11.1 选型与速度

  • 词表固定、类别不多:按论文附录 A.2 的做法,去掉 RepVL-PAN、把类名的文本嵌入存进分类层,再在自己的数据上微调,结构就是一个 YOLOv8,速度与 YOLOv8 相同;或者保留 RepVL-PAN,用离线词表。
  • 运行时要随时换词(开放检索、交互式标注):离线词表 + 换词时重新编码一次(1203 个词约 48 ms,几十个词更快),不要每张图都跑文本编码器。
  • 速度参考:4080 SUPER 上离线词表的 S / M / L 分别 128 / 104 / 92 FPS(FP32、batch 1、不含 NMS),是同规模 YOLOv8 的 66%--76%(9.4 节)。
  • 后处理 :评测用的设置(score_thr 0.001、nms_pre 30000)不能拿去部署,1203 类时每张图 0.35--0.41 秒;换成正常的阈值和每图上限只要 1.3 ms 左右。

11.2 离线词表怎么定(9.5 节)

  • 写法与训练一致:裸类名,不套 "a photo of a {}." 这类模板(−2.9 AP)。
  • v1 权重不要随手加补齐词(COCO 上 −6.5 AP)。官方对 v2、v2.1 的建议不同,换版本要重新验证。
  • 词表不要开得过大:多出 1133 个干扰词,COCO 80 类掉 4.3 AP。
  • 也不要只放一个词:把场景里常见、容易混淆的物体也写进词表,当作负类、结果丢掉;只检测 person 时这样做能多 3 AP。
  • 换词表要回归测试:词与词通过 neck 相互影响,加减一个词可能让别的类别变好或变坏十几甚至二十几个点(加补齐词时 donut −24.9、oven +19.0)。

11.3 部署

  • 优先用官方 v2 的权重导出:v2 去掉了随图像变化的 I-Pooling,对比头的 L2 归一化换成了 BN,词表能完全折进卷积,导出 ONNX、TensorRT 都更顺。v1 的 I-Pooling 和自底向上的 T-CSPLayer 折不掉(8.4 节)。
  • 在 PyTorch 里"折进卷积"本身几乎不提速,词表很大时还更慢(9.4 节);它的价值在导出后的静态图。
  • batch 1 时 FP16 用 autocast 反而更慢(9.4 节);FP16、INT8 的收益要靠 TensorRT 之类的推理引擎。
  • 词表到 1203 个对速度几乎没影响,到几千才明显变慢。

11.4 工业质检能不能用(9.7 节)

  • 零样本检缺陷不行:DeepPCB 上四个模型、三套词表的 AP 都在 0.2 以下。缺陷名字当词表,模型根本不认识这些"东西"。
  • 微调也不占优:1000 张时与 YOLOv8-L 打平(4 个种子平均 63.3 对 63.8),100 张时反而低 7 AP,训练还慢 1.2--1.4 倍。缺陷检测直接用 YOLOv8 这类闭集检测器更划算。
  • 小数据上比较模型要多跑几个种子:同一个模型、同一个配方只换随机种子,1000 张时 AP 最多差 9.4 个点(YOLOv8),100 张时最多差 14.5 个点(YOLO-World),只跑一次的对比结论可能完全反过来(9.7 节)。
  • 更合适的用法 :
    • 工厂里通用物体(人、车辆、叉车、托盘、工具、安全帽、手套......)的零样本检测,用来做安全巡检、物料清点的原型;
    • 在大量没标注的图片里按文字找图("有叉车的图"),挑数据;
    • 给闭集模型做预标注:先用 YOLO-World 出框,人工核对后再训练,思路和论文的伪标注流程一样。
  • 词表:照 11.2 节,写场景里实际会出现的物体,同时把容易混淆的物体也写进去当负类。

11.5 许可

  • 官方代码和 HF 上的权重都是 GPL-3.0(pyproject.toml 写的 Apache 2.0 与 LICENSE 文件不一致,以 LICENSE 和模型卡为准)。GPL 要求分发的衍生作品同样开源,闭源商用前要评估清楚。Ultralytics 的实现是 AGPL-3.0,另有商业授权。以上是个人理解,不是法律意见。

12. 面试高频问题

  1. YOLO-World 相对 YOLOv8 改了什么? 分类分支不再输出固定的 80 个通道,而是输出 512 维物体嵌入,与 CLIP 文本嵌入算缩放余弦相似度(Eq. 1);neck 换成 RepVL-PAN(T-CSPLayer 做文本→图像、I-Pooling Attention 做图像→文本);预训练数据从检测扩展到 grounding 和伪标注的图文数据。标签分配(TAL)和损失(sigmoid BCE + CIoU + DFL)都是 YOLOv8 原样(4.2--4.4 节)。
  2. 什么是 prompt-then-detect?为什么快? 用户的词表事先用文本编码器编码一次,推理时只跑图像部分。实测在线编码 1203 个类名时,文本编码器占推理时间的 80%--87%,三档模型都只有 17--18 FPS;离线词表后 S / M / L 是 128 / 104 / 92 FPS(RTX 4080 SUPER,9.4 节)。
  3. 重参数化具体怎么做?哪些能折、哪些折不掉? 检测头: α⋅w/∣w∣\alpha \cdot w / |w| α⋅w/∣w∣ 作为 1×1 卷积的权重、 β\beta β 作为偏置,前面保留对物体嵌入的 L2 归一化;自顶向下的 T-CSPLayer: guide_fc(W)\text{guide\_fc}(W) guide_fc(W) 按头拆成 1×1 卷积。I-Pooling 和用 W′W' W′ 的自底向上 T-CSPLayer 随图像变,折不掉(8.4 节)。在 PyTorch 里折叠本身几乎不提速,价值在导出部署。
  4. max-sigmoid 注意力是什么?为什么用 max? 每个位置与词表里所有词的相似度取最大,过 sigmoid 后当空间门控,乘到 3×3 卷积后的特征上。用 max 只关心"像不像词表里的某个东西",计算量随词表大小线性增长(8.2 节)。
  5. 训练时的词表怎么构造? 每个 mosaic 样本:其中出现的所有正名词,加上随机采的负名词,最多 80 个;不足的用空字符串补齐。官方 v2.1 博客说补齐项不加掩码反而高 2--3 LVIS AP,副作用是推理时通常要加一个补齐词(7 节)。
  6. "区域-文本对比损失"是在词表上做 softmax 吗? 不是。代码里是每个词独立的 sigmoid 二分类交叉熵,目标是 TAL 给的软分数,和 YOLOv8 的分类损失完全一样,只是 logits 换成了与文本嵌入的相似度(4.4 节)。
  7. 为什么冻结文本编码器? Table 5:在只有 365 类的 O365 上微调 CLIP,AP 掉 3.1、APr 掉 5.9,单一的词表会破坏 CLIP 的泛化;BERT 本身不对齐视觉,微调反而有用(+3.7 AP),但远不如冻结的 CLIP。
  8. 图文数据(CC3M)怎么用? n-gram 抽名词 → GLIP-L 打伪框 → CLIP 重打分、按名词 NMS、阈值过滤,得到 246k 张图、821k 个框;图文样本只算分类损失( λI=0 \lambda_I = 0 λI=0)。附录 C:对小模型,伪标注加多了反而掉点,人工标注的 GoldG 更有用(5.7 节)。
  9. 论文 Table 2 的 35.0 和 Table 3、官方模型库的 32.5 为什么不一样? 评测口径不同:Table 2 是 Fixed AP(每图 1000 个、每类最多 1 万个),消融表和模型库是 LVIS API 默认的每图 300 个。同一份检测结果两种算法差约 2.5 AP,差别几乎全在稀有类:1203 个类抢 300 个名额,分数低的稀有类先被挤掉(9.3 节)。
  10. LVIS 的 APr / APc / APf、federated 标注是什么? 按类别在训练集里出现的图片数分:稀有 1--10 张、常见 11--100 张、频繁 100 张以上。LVIS 每张图只确认了部分类别"有"或"没有",没确认过的类别上的检测不算错,这样才能用 1203 个类评测而不要求每张图标全。
  11. YOLO-World 与 GLIP、Grounding DINO 的区别? 后两者把图像和文本深度融合(每层交叉注意力),文本每次都要和图像一起编码,骨干是 Swin;YOLO-World 只在 neck 里做两处轻量融合,词表离线编码,骨干是 YOLOv8。同为 O365 + GoldG 预训练,YOLO-World-L 的 LVIS minival 高约 10 AP,速度快 20 倍以上(5.2 节)。
  12. 部署 YOLO-World 要注意什么? 用离线词表,别每张图跑文本编码器;评测用的后处理设置(score_thr 0.001、nms_pre 30000、1203 类)每张图要 0.35--0.41 秒,部署要换成正常阈值;batch 1 时 FP16(autocast)反而比 FP32 慢,要靠 TensorRT 之类的工具;官方 v2 去掉 I-Pooling、把 L2 归一化换成 BN 都是为了导出部署(7、9.4 节)。
  13. 离线词表里多一个词、少一个词,会影响别的类吗? 会。检测头对每个词单独打分,但 neck 里的 max-sigmoid 对整个词表取最大,词表一变所有位置的特征都变。实测 COCO 上加一个空字符串补齐词掉 6.5 AP,加 1133 个干扰词掉 4.3 AP,只检测 person 时只放一个词比放 80 个类名低 3 AP(9.5 节)。
  14. YOLO-World 能直接用在工业缺陷检测上吗? 零样本不行(DeepPCB 上 AP 接近 0);微调时数据充足与 YOLOv8 打平,数据少时还更差(100 张:53.3 对 60.4,4 个种子平均)。它更适合工厂里通用物体的零样本检测和预标注(9.7、11.4 节)。

13. 关键术语速查

术语 含义
开放词表检测(OVD) 检测类别由文本指定,可以超出训练时的类别
零样本迁移 不在目标数据集上训练,直接评测
区域-文本对 一个框和它对应的文本(类名、名词短语或描述)
在线 / 离线词表 每张图都编码一遍文本 / 事先编码一次反复使用
prompt-then-detect 先把用户的提示编码成离线词表,再做检测
重参数化 把训练时的结构等价变换成推理更快的结构;这里指把文本嵌入折进卷积权重
RepVL-PAN 可重参数化的视觉-语言路径聚合网络,YOLO-World 的 neck
T-CSPLayer 加了 max-sigmoid 文本门控的 C2f
max-sigmoid 注意力 每个位置对词表取最大相似度、过 sigmoid 后当空间门控
I-Pooling Attention 用三层特征池化出的 27 个 token 更新文本嵌入的多头注意力
C2f YOLOv8 的 CSP 模块(CSPLayerWithTwoConv)
TAL task-aligned label assignment:按分类分数与 IoU 的组合挑正样本
DFL distribution focal loss:把框的每条边当离散分布来回归
GoldG GQA + Flickr30k 的 grounding 数据(MDETR 整理,去掉了 COCO 的图)
CC3M† / CC3M-Lite 论文从 Conceptual Captions 3M 里伪标注的 246k 张图
LVIS minival MDETR 从 LVIS v1 val 划出的子集,4,809 张图,全部来自 COCO val2017
APr / APc / APf LVIS 稀有 / 常见 / 频繁类别上的 AP
Fixed AP Dave et al. 2021:不限每图检测数、每类最多 1 万个的 AP
federated 标注 LVIS 每张图只确认部分类别的有无,没确认的类别上的检测不算错
补齐词(padding) 训练时词表不足 80 个补的空字符串,起到"背景嵌入"的作用
mosaic 把 4 张图拼成一张的数据增强

14. 延伸阅读

  • Radford et al. ,Learning Transferable Visual Models From Natural Language Supervision(CLIP),ICML 2021
  • Gu et al. ,Open-vocabulary Object Detection via Vision and Language Knowledge Distillation(ViLD),ICLR 2022
  • Kamath et al. ,MDETR: Modulated Detection for End-to-End Multi-Modal Understanding,ICCV 2021(GoldG 与 LVIS minival 的来源)
  • Li et al. ,Grounded Language-Image Pre-training(GLIP),CVPR 2022
  • Liu et al. ,Grounding DINO: Marrying DINO with Grounded Pre-Training for Open-Set Object Detection,2023
  • Yao et al. ,DetCLIP: Dictionary-Enriched Visual-Concept Paralleled Pre-training for Open-world Detection,NeurIPS 2022
  • Minderer et al. ,Simple Open-Vocabulary Object Detection with Vision Transformers (OWL-ViT),ECCV 2022;Scaling Open-Vocabulary Object Detection(OWLv2),NeurIPS 2023
  • Gupta et al. ,LVIS: A Dataset for Large Vocabulary Instance Segmentation,CVPR 2019
  • Dave et al. ,Evaluating Large-Vocabulary Object Detectors: The Devil is in the Details,2021(Fixed AP)
  • Feng et al. ,TOOD: Task-aligned One-stage Object Detection,ICCV 2021(TAL)
  • Ding et al. ,RepVGG: Making VGG-style ConvNets Great Again,CVPR 2021(重参数化)
  • Wang et al. ,YOLOE: Real-Time Seeing Anything,2025(同样走"可重参数化的文本提示 + YOLO"路线,另加视觉提示和无提示模式)
  • Tang et al. ,Online PCB Defect Detector On A New PCB Defect Dataset,2019(DeepPCB 数据集,9.7 节)

关注Hollis的视觉大模型实战:视觉与多模态大模型,读到能复现、跑到能落地。

每篇论文从公式讲到代码,能复现的我先跑一遍;每天还有一份只看一手来源的 AI 早报。

想看哪篇论文、对复现结果有疑问,欢迎在评论区留言。

文中论文图片出自原论文,出处见图注。

相关推荐
alonglong1 小时前
RAG 增量索引实测:把 434.7 秒的全量重建压到 1.35 秒,以及"字节级一致"为什么只属于复用路径
人工智能
康实训1 小时前
高校中医康复实训室建设规划要点
人工智能·实训室·实训室建设
larance1 小时前
机器学习的数据分片
人工智能·机器学习
Gu_WenYun1 小时前
端侧AI规模化落地,算力景气延续,科技基金怎么选?
人工智能·科技·金融
u1301301 小时前
GitHub 热榜项目:日榜(2026-10-12)
人工智能·github
chien0111 小时前
Agent 需要什么样的运行时?——读阿里云 Agent Sandbox 发布报道
人工智能·语言模型
码流子1 小时前
事件告警延迟拆解:从摄像头到手机通知,延迟卡在哪六个环节
数据库·人工智能·物联网
QYR_111 小时前
全球半导体离子注入机用零部件市场分析:2032年规模有望突破8亿美元,精密制造与高纯材料驱动行业增长
大数据·人工智能