尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
YOLO-World开放词表检测:原理、微调与部署避坑指南
简介面向开放词汇目标检测与视觉定位的YOLO-World资料包适合PyTorch开发者、视觉方向学生及需复现或二次开发检测器的算法工程师。内容提供PyTorch实现、预训练权重及预训练/微调代码围绕prompt-then-detect范式组织可用于自定义词表推理、检测与grounding实验。压缩包共161个文件以110个Python源码为核心配合20个Markdown文档、10个文本说明以及JSON类别文本、样例图像、Jupyter推理示例和Docker构建配置等整体约2.35MB便于按模块查阅源码与文档。已有883人学习下载说明其在开放词汇检测学习中具有参考价值。读者可了解模型加载、推理入口、数据处理与容器化运行方式并开展迁移实验、词表适配和训练流程梳理许可证与依赖说明也有助于合规使用和环境搭建目录结构清晰便于定位工程配置与实验模块。1. 类别表写死的那一刻我就想换个思路做产线物料盘点那阵子最烦的不是模型精度是类别表。今天客户要认五种纸箱明天加两种托盘改完 yaml 重训一轮两周就过去了。后来翻到yolo-world 的资料包pytorch 源码加文档核心就一句话把检测头里的分类权重从固定类别向量换成文本嵌入类别由你现场输入的自然语言决定。它是基于成熟检测框架二次构建的开放词表检测器支持零样本迁移、自定义词表也能重参数化后当普通检测器跑。适合手上堆着一大把零散类别需求、不想每个场景都重训的开发者也适合想搞明白视觉-语言对齐怎么落到检测头里的同学。下面按我拆包的顺序从跑通、架构、训练到改造一层层往下走。2. 环境跑通pytorch 依赖、权重落位与第一次推理拿到资料包先别急着pip install -r先搞清楚里面有两条技术路线依赖完全不是一回事。一条是官方仓库那条基于 mm 系生态mmengine / mmcv / mmdet / mmyolo配置驱动、训练友好、支持分布式另一条是上游检测框架把开放词表能力集成进去的版本一个类就能调推理和导出省事。两条路都能跑但装错环境会出现能 import 但不能训练这种半死不活的状态排查起来很耗人。我的建议是只想快速验证效果走上游集成路线要做微调、改结构、复现论文指标走官方仓库路线。下面按官方仓库为主、集成版为辅来讲因为大部分二次开发最终都会落到配置文件上。2.1 依赖装不对后面全是白费最容易翻车的是 mmcv。它不是纯 Python 包带 C/CUDA 扩展必须和 torch 版本、CUDA 版本三方对齐直接从 PyPI 装大概率拿到一个不匹配的 wheel报undefined symbol或者编译到一半挂掉。血泪经验是先定 torch再用 mim 装 mm 系顺序反了就要推倒重来。# 1. 建环境Python 版本对齐仓库 README别用太新的 conda create -n yolo-world python3.10 -y conda activate yolo-world # 2. 先装 torch按本机驱动选 CUDA 版本这一步决定了后面 mmcv 能不能编译过 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 3. 用 mim 装 mm 系mim 会自动挑和当前 torch 匹配的版本 pip install -U openmim mim install mmengine mmcv2.0.0 mmdet3.0.0 mmyolo0.6.0 # 4. 最后装项目自身的其余依赖 pip install -r requirements.txt这几行的顺序是有讲究的torch决定了mmcv的编译目标mim会读当前环境里的 torch 版本去索引对应 wheel所以必须在装完 torch 之后执行。--index-url指向的是官方 wheel 源换成 CPU 版就把cu118去掉。requirements.txt放最后是因为里面可能锁了某些和 mm 系冲突的包比如旧版 numpy冲突时能一眼看出来是谁覆盖了谁。装完先做一次体检别等到跑模型才发现环境是坏的import torch import mmcv, mmengine, mmdet import numpy as np print(torch:, torch.__version__, cuda:, torch.cuda.is_available()) print(mmcv:, mmcv.__version__, mmengine:, mmengine.__version__) print(mmdet:, mmdet.__version__, numpy:, np.__version__) # 真正跑一次卷积能跑通才说明 CUDA 扩展没问题光看 is_available 会骗人 x torch.randn(2, 3, 64, 64).cuda() print((x * 2).mean().item())这里的重点是最后那两行。torch.cuda.is_available()返回 True 但实际算子不可用的情况我遇到过不止一次通常是被别的包覆盖了 CUDA 运行时。跑一个真实的卷积算子能把这类问题提前暴露。numpy 也顺手打出来因为新版 numpy 对旧代码里np.int、np.float这类别名的移除会导致一些数据增强库直接崩看到 2.x 就要有心理准备。2.2 权重和配置文件怎么放资料包里通常有四大块东西搞混了就会出现配置指向的文件不存在这种低级错误。我习惯在仓库根目录建一个weights/把外部文件统一丢进去配置里的路径也跟着改别散落在各个子目录。文件类型典型位置作用常见坑预训练权重.pthweights/模型参数含文本分支和检测头文件名和配置里load_from不一致模型配置.pyconfigs/下按模型规模分目录定义 backbone、neck、head 结构改结构忘了同步改这里词表文件.json/.txtdata/或configs/同级训练用的类别名集合映射成文本嵌入换数据集后没换词表类别全错位示例图片 / demo 脚本demo/快速验证图片路径相对路径cd 错目录就找不到词表文件是最容易被忽略的一个。它不是简单的类别名列表训练阶段往往是一个 JSON里面按 train/val 分成两组词汇模型启动时会把每个词过一遍文本编码器缓存成嵌入向量。你换了自己的数据集却还用原词表模型输出的索引和你的类别名就对不上检测框位置看着还行标签全是乱的。2.3 三种推理入口按场景选跑通第一张图有三条路从简单到复杂分别是命令行 demo、Python API、自己写推理循环。先跑 demo 确认权重没问题再用 API 接业务代码。# 官方仓库的 demo 形式参数顺序按仓库 README 调整 python demo/demo.py \ configs/pretrain/你的模型配置.py \ weights/你的权重.pth \ demo/sample.jpg \ person,dog,carton \ --topk 100 \ --threshold 0.25 \ --device cuda:0--topk是保留的候选文本-区域匹配对数量开放词表下不建议设太小词表大了容易漏--threshold是相似度阈值和普通检测的置信度阈值不是一个量纲通常要更低一些0.2 到 0.3 起步比较常见。词表用逗号分隔中文词也能跑但实测英文提示词召回更稳这是文本编码器的训练分布决定的。集成版更省事一个类搞定适合往业务代码里塞from ultralytics import YOLOWorld # 加载带开放词表能力的权重 model YOLOWorld(yolov8s-worldv2.pt) # 现场指定词表这一步会把文本嵌入写进检测头重参数化 model.set_classes([carton, pallet, forklift, safety vest]) results model.predict( sourcedemo/sample.jpg, conf0.25, # 置信度阈值 iou0.5, # NMS 的 IoU 阈值 imgsz640, # 输入分辨率和训练时对齐效果最好 verboseFalse, ) for box in results[0].boxes: cls_id int(box.cls) print(model.names[cls_id], float(box.conf), box.xyxy.tolist())set_classes是整段代码的关键它做的事就是把你的词表编码成文本嵌入替换掉检测头里原来的分类权重模型从此变成一个只认这几个类的普通检测器速度也回到正常水平。names会同步更新成你传进去的词所以后面取标签直接用model.names[cls_id]就行。conf和刚才的--threshold是同一个东西只是换了个名字。提示set_classes是原地修改模型状态的同一个 model 对象换词表会覆盖上一次的设置。业务里要来回切词表每次切完都要重新确认model.names别拿旧索引去查新词表。跑通这一步大概能覆盖六成使用场景给个词表图里找对应物体。但如果你发现某些词死活检测不出来别急着怀疑权重先去看第 5 章的排查清单八成是词表表达和训练分布对不上。3. 架构拆解一个 batch 在模型里怎么走理解结构比背 API 有用得多尤其当你需要判断我的类别检测不出来到底是哪一环坏了的时候。整个模型可以粗暴切成三块图像分支、文本分支、以及把两者缝在一起的融合层。图像分支就是标准的检测器骨架文本分支是一个冻结的文本编码器融合层才是这个项目真正新增的东西。3.1 整体链路从像素到相似度矩阵图像侧走的是经典的单阶段检测结构CSP 结构的 Darknet backbone 逐级下采样抽出 C3/C4/C5 三个尺度的特征图再进一个 PAN 结构的 neck 做自顶向下加自底向上的双向融合最后三个解耦头分别输出每个位置的框回归和类别预测。文本侧简单得多词表里的每个类别名先套一个提示词模板常见做法是a photo of a {class}这种拼成一个句子列表丢进文本编码器得到形状[N, D]的嵌入矩阵N 是词表大小D 是文本嵌入维度通常 512做完 L2 归一化后缓存起来训练时整个 epoch 都不变属于算一次用到底的角色。关键差异在检测头。普通检测器的分类分支是一个Conv输出num_classes维向量每个维度硬绑一个类别这里的分类分支输出的是视觉嵌入然后和文本嵌入矩阵做矩阵乘法得到一个[位置数, N]的相似度矩阵再走 sigmoid 得到每个位置的类别得分。类别不再是权重里的固定一列而是运行时可替换的一组向量这就是开放词表的物理实现。用一个简短的伪代码把这条链路串起来# 仅示意前向数据流具体模块名以仓库实现为准 def forward(self, images, txt_feats): # images: [B, 3, H, W] # txt_feats: [N, D]N 为词表类别数D 为文本嵌入维度 feats self.backbone(images) # 多尺度视觉特征 # 关键一步文本反过来调制视觉特征让特征知道当前要找什么 feats self.neck(feats, txt_feats) cls_scores, bbox_preds [], [] for feat in feats: # 视觉特征投到文本空间再和文本嵌入做点积 visual_embed self.text_proj(feat) # [B, D, H, W] # einsum 得到每个空间位置与每个类别的相似度 score torch.einsum(bchw,nd-bnhw, visual_embed, txt_feats) cls_scores.append(score.sigmoid()) bbox_preds.append(self.reg_head(feat)) return cls_scores, bbox_predseinsum那一行是整个模型的灵魂它把分类从查表变成了相似度计算。txt_feats换掉输出语义就跟着换不需要动任何一个卷积权重。这也解释了一个常见困惑为什么同一张图换词表后框的位置会微微变化因为 neck 里的文本调制也参与了特征生成不只是最后那一下点积。3.2 RepVL-PAN文本怎么反过来调制视觉名字里的 RepVL 是可重参数化的视觉-语言的意思PAN 就是那个特征金字塔。它在标准 PAN 的基础上插了两类模块一类管文本指导视觉一类管视觉补充文本。先看文本指导视觉的那一层本质是一个通道门控import torch import torch.nn as nn class TextGuidedLayer(nn.Module): 用文本嵌入生成逐通道的门控权重调制视觉特征 def __init__(self, channels, text_dim, reduction16): super().__init__() # 文本维度 - 视觉通道数中间降维减少参数量 self.text_proj nn.Sequential( nn.Linear(text_dim, channels // reduction, biasFalse), nn.ReLU(inplaceTrue), nn.Linear(channels // reduction, channels, biasFalse), ) self.norm nn.BatchNorm2d(channels) self.act nn.SiLU(inplaceTrue) def forward(self, x, txt_feats): # x: [B, C, H, W]当前层视觉特征 # txt_feats: [B, N, D]N 为词表大小D 为文本嵌入维度 txt txt_feats.mean(dim1) # 沿类别维求均值 - [B, D] w torch.sigmoid(self.text_proj(txt)) # 门控权重 - [B, C] w w.unsqueeze(-1).unsqueeze(-1) # [B, C, 1, 1] return self.act(self.norm(x * w)) # 通道级调制三个参数要盯住channels必须等于该层视觉特征通道数写错了直接 shape 报错text_dim必须等于文本编码器输出维度两者不一致时中间要加投影层reduction控制中间瓶颈宽度默认 16 是个参数量和表达力的折中词表特别大时可以调小一点保留更多信息。用sigmoid而不是softmax是有原因的。softmax会让通道之间互相竞争总和恒为 1等于强行压缩特征能量sigmoid是独立的 0 到 1 门控允许某些通道被放大、某些被抑制不会破坏特征的尺度。这种细节在改结构时很容易被忽略换成softmax之后精度掉一两个点还找不到原因属于典型的玄学故障。另一个模块解决相反方向的问题文本嵌入是脱离图像的同一个词在任何图里都一样缺乏上下文。做法是把视觉特征池化成固定数量的 token和文本嵌入拼在一起做注意力class ImagePoolingAttention(nn.Module): 视觉上下文回写文本把图像池化成 3x3 token与文本拼起来做自注意力 def __init__(self, embed_dim, num_heads8, pool_size3): super().__init__() # 用固定池化尺寸保证不同输入分辨率下 token 数不变 self.pool nn.AdaptiveAvgPool2d(pool_size) self.num_tokens pool_size ** 2 self.mha nn.MultiheadAttention(embed_dim, num_heads, batch_firstTrue) def forward(self, txt_feats, visual_feats): # visual_feats: [B, C, H, W]从 PAN 的某一层取 # txt_feats: [B, N, C]注意这里通道必须已经对齐到 embed_dim v self.pool(visual_feats).flatten(2).transpose(1, 2) # [B, 9, C] kv torch.cat([txt_feats, v], dim1) # [B, N9, C] out, _ self.mha(kv, kv, kv) # 自注意力 return out[:, : txt_feats.shape[1]] # 只取回文本部分pool_size3意味着固定 9 个视觉 token这是为了在导出和重参数化时形状可预期。self.mha的embed_dim必须和文本维度一致视觉特征通道数不是这个值时前面要加一层 1x1 卷积做投影这是新手最容易漏的一步。返回时只切回文本部分视觉 token 用完就丢因为它们的作用只是给文本注入当前图像的上下文。注意这两个模块是串联在 PAN 的每一层上的改动其中一个的通道数要同步检查相邻层的输入输出否则会在 neck 中间炸掉。3.3 重参数化为什么推理还能跑回 YOLO 的速度训练时模型带着文本分支要跑文本编码器、要做跨模态注意力比普通检测器慢一截。但推理时根本不需要这些词表是固定的文本嵌入算一次就够融合层的门控权重也是固定的。所谓重参数化就是把这部分预计算的结果直接烘焙进检测头的权重里之后整个文本分支可以整个丢掉。流程大致是三步先把词表编码成嵌入矩阵再让它过一遍融合层算出对应的门控参数最后把这些参数固化到 neck 和 head 的权重里。做完之后模型结构上和普通检测器没差别速度也对齐了。# 集成版里这一步被封装成了一个调用本质就是重参数化 model.set_classes([carton, pallet, forklift]) # 验证一下names 变了模型结构里也不再有文本分支的参与 print(model.names) # {0: carton, 1: pallet, 2: forklift} print(model.model[-1].nc) # 检测头类别数已同步这也解释了一个现象为什么改词表之后必须重新set_classes不能直接改names字典。改names只是改标签显示检测头里还是上一组嵌入输出语义完全对不上。我见过有人为了省事直接改字典结果检测框全在标签全错排查了半天以为是权重加载错了。4. 训练链路数据组织、损失函数与微调配置推理跑通了接下来是自己训练。这块的门槛比推理高不少主要卡在数据格式和显存上。开放词表训练和普通检测训练最大的区别是标注不只要有框还要有和框对应的文本描述而且词表是动态的。4.1 数据组织框标注加词表文件检测框部分还是老样子YOLO 格式的 txt每行class_id cx cy w h坐标归一化到 0 到 1# annotations/000001.txt # 每行: class_id center_x center_y width height均为归一化值 0 0.4821 0.5310 0.2130 0.3870 2 0.7315 0.6120 0.1540 0.2210 1 0.2043 0.4780 0.0980 0.3120真正需要额外准备的是词表。训练时模型的类别数不是固定的而是跟着词表走所以要先给一份类别名清单再给一份索引到名字的映射{ train: [carton, pallet, forklift, safety vest, oil drum], val: [carton, pallet, forklift] }train是训练时参与文本编码的词val是验证时用的子集。两个列表可以不一样这正好对应开放词表的评估逻辑训练见过的词和评估用的词不必完全相同跨词表泛化能力就是这么测出来的。移植到自己数据时class_id必须和train列表的下标严格对应错一位就全乱。提示类别名尽量用英文、名词、单数别写 红色的纸箱子 这种描述性短语。文本编码器是在图像-文本对上训出来的它对名词短语的响应最好长描述反而会稀释语义。4.2 损失函数与配置项配置是 mm 系那种字典嵌套风格改的时候像在改 Python 代码比 yaml 灵活但也更容易写错。下面只保留和开放词表相关的关键字段# 路径按仓库实际配置文件调整这里只截取结构性字段 model dict( typeYOLOWorldDetector, backbonedict( typeYOLOv8CSPDarknet, deepen_factor0.33, # 控制深度s/m/l 靠这个和 widen 区分 widen_factor0.50, # 控制宽度显存不够就往下调 ), neckdict( typeYOLOWorldPAFPN, text_channels512, # 必须等于文本编码器输出维度 embed_channels[256, 256], # 必须和 backbone 各层输出通道对齐 guide_channels512, # 文本指导分支的中间维度 ), bbox_headdict( typeYOLOWorldHead, num_classeslen(CLASSES), # 跟着词表走不要写死 reg_max16, # DFL 的离散区间数一般不改 loss_clsdict(typeBCELoss), # 分类走二值交叉熵 loss_bboxdict(typeIoULoss, loss_typeciou), # 框回归 loss_dfldict(typeDFLoss), # 分布式焦点损失 ), train_cfgdict( assignerdict( typeTaskAlignedAssigner, topk10, # 每个 GT 选多少个预测点做正样本 alpha0.5, # 分类分与 IoU 的平衡系数 beta6.0, # IoU 的幂次越大越偏向高 IoU ), ), )num_classes这行是最常改的但很多人改错方向它应该等于词表大小不是你的业务类别数。词表里塞了 500 个词这里就写 500哪怕你的数据只标了 3 类。alpha和beta是任务对齐分配器的核心alpha大一点更看重分类质量beta大一点更看重框的贴合度一般不动除非你的数据小目标特别多。损失侧还有一个只在训练时存在的项区域-文本对比损失。它要求图像里每个区域的特征和它对应的文本描述相似、和其他文本不相似是开放词表能力的来源。这一项通常不需要手动配权重跟着仓库默认走但如果你的数据里有些类别标注很稀疏可以考虑单独调低这一项的权重避免它把分类分支带偏。训练命令按卡数选# 单卡 python tools/train.py configs/你的配置.py --amp --work-dir work_dirs/exp1 # 多卡第二个参数是卡数 bash tools/dist_train.sh configs/你的配置.py 8 --amp --work-dir work_dirs/exp1--amp混合精度基本是必开的省显存还能快一点但要注意有些自定义损失在 fp16 下会溢出出现 loss 变 NaN 就先关掉它验证一下。--work-dir一定要显式指定不然日志和权重混在默认目录里跑几轮就分不清哪个是哪个了。4.3 在自己的数据上微调完全从零训开放词表检测器不现实数据量根本不够。常规做法是加载预训练权重做微调再配合冻结策略控制遗忘。# 加载预训练权重只训检测头和 neck 的融合层 python tools/train.py configs/你的配置.py \ --cfg-options load_fromweights/预训练权重.pth \ --amp \ --work-dir work_dirs/finetuneload_from和配置文件里的load_from是同一个字段写在命令行里更方便切换。微调时有几个经验值学习率比从头训小一个数量级backbone 前两个 stage 可以冻结EMA 一定要开开放词表的分类分支波动比较大EMA 对最终精度影响明显。数据量少于几百张时建议把 backbone 整个冻住只训 neck 和 head否则很容易过拟合到几个样本上。训练日志里重点看两个指标loss_cls和验证集上的 mAP。loss_cls震荡但不发散是正常的开放词表的相似度计算本身就有噪声如果它连续几个 epoch 单调上涨先检查词表和标注的索引是否对齐这是最常见的原因。5. 避坑与排查跑 YOLO-World 最容易翻车的五件事下面这五条全是我自己踩过的按踩到的频率排序。每条都按看到什么现象、真实原因是什么、怎么解决来写方便你对着症状直接查。5.1 词表里的词检测不出来换个说法就有了现象设了car图里明明有车一个框都没有改成automobile或者a photo of a car框立刻出来了。原因开放词表的召回强烈依赖文本嵌入和训练词表的分布匹配。预训练用的词汇表里某些概念是用特定词表达的你换一个近义词嵌入向量就偏了相似度掉到阈值以下。这不是模型坏了是文本侧的语义漂移。解决给每个业务类别准备 2 到 4 个同义表达一起塞进词表让模型多路召回同时把conf阈值先降到 0.15 左右看有没有候选确认是阈值问题还是真的没有响应。实在不行就上提示词模板a photo of a xxx这种对多数类别都有小幅提升。5.2 import 就报 undefined symbol现象import mmcv或者跑训练脚本时直接抛ImportError: undefined symbol: ...或者No module named mmcv._ext。原因mmcv 的 C 扩展和当前 torch/CUDA 版本不匹配。多半是先用 pip 装了 torch之后又装了 CPU 版的 mmcv或者反过来二进制接口对不上。解决别硬修直接重建环境。顺序固定成torch → mim install mm 系 → 项目依赖全程不要手动pip install mmcv。已经污染的环境卸载重装往往比排查快。5.3 训练第二个 batch 就 OOM现象batch_size2都能爆显存或者训到一半显存缓慢上涨最后挂掉。原因开放词表训练除了常规的检测计算图还要缓存文本嵌入、维护跨模态注意力的中间变量显存占用比同规模的普通检测器高一截。另外多尺度训练时最大尺度那张图是显存峰值配置里写了multi_scale就容易踩到。解决先开--amp再把base_lr按 batch 线性缩放batch 减半学习率也减半不要只改 batch还不行就关掉多尺度训练固定imgsz最后的手段是开梯度检查点用时间换显存。5.4 微调之后只认新类别原词表全丢现象拿自己的数据微调完新类别检测挺好但原来能检出的通用类别全部消失模型像是变傻了。原因分类分支被新词表整体覆盖加上学习率过大、backbone 没冻结模型把之前的视觉-语言对齐关系冲掉了。这是典型的灾难性遗忘。解决词表用并集把原词表和新类别合在一起训backbone 前两个 stage 冻结学习率降一个数量级打开 EMA。如果数据量很少只训 neck 和 headbackbone 完全不动精度反而更好。5.5 导出 ONNX 之后输出对不上现象模型导出成功但推理结果的框和 PyTorch 侧差很多或者输出张量维度不对类别数也不是你设的那些。原因直接导出一个还带文本分支的模型ONNX 图里会多出文本输入形状不固定很多推理引擎处理不了或者忘了先做重参数化导出的还是原始词表。解决导出前必须先set_classes完成重参数化确认model.names和model.model[-1].nc都变了再导出。导出后用固定 shape 的随机输入跑一遍和 PyTorch 侧的输出逐个比对差在 1e-3 以内才算过关。6. 二次开发把开放词表接进业务链路真正落地的时候模型只是链路里的一环剩下的是词表管理、阈值策略、批量推理和导出。这部分没有标准答案只有几个我自己验证过好用的做法。6.1 词表动态切换与后处理业务里常见需求是同一个进程服务多个场景每个场景一套词表。频繁调set_classes会有一次文本编码开销可以按词表做缓存用哈希做 keyfrom ultralytics import YOLOWorld import hashlib class WordlistDetector: def __init__(self, weight_path): self.model YOLOWorld(weight_path) self._current_key None def _key(self, words): # 词表顺序会影响类别索引所以用排序后的拼接做 key return hashlib.md5(,.join(sorted(words)).encode()).hexdigest() def detect(self, image, words, conf0.25): key self._key(words) if key ! self._current_key: self.model.set_classes(words) # 只在词表变化时重参数化 self._current_key key # agnostic_nms 关掉避免不同类别互相压制 return self.model.predict(image, confconf, iou0.5, agnostic_nmsFalse)agnostic_nmsFalse这一项值得单独说。开放词表下同一个物体可能被多个近义词同时命中carton和box都框住同一个箱子如果开类别无关的 NMS会丢掉其中一个看起来像是漏检关掉之后保留多个标签在业务层再按优先级去重更可控。6.2 导出与一致性验证部署侧一般走 ONNX 或者 TensorRT导出脚本很短但验证不能省import numpy as np import onnxruntime as ort import torch # 导出前必须完成重参数化否则图里还带文本分支 model.set_classes([carton, pallet, forklift]) model.export(formatonnx, opset12, simplifyTrue, imgsz640) # 用固定输入比对 PyTorch 与 ONNX 输出 sess ort.InferenceSession(yolov8s-worldv2.onnx) x np.random.rand(1, 3, 640, 640).astype(np.float32) onnx_out sess.run(None, {sess.get_inputs()[0].name: x}) with torch.no_grad(): torch_out model.model(torch.from_numpy(x)) diff max( float(np.abs(o.detach().numpy() - n).max()) for o, n in zip(torch_out, onnx_out) ) print(max diff:, diff) # 超过 1e-3 就别急着上线opset选 12 是兼容性比较好的一个档位太新的算子某些推理引擎还不支持。比对的时候注意输出顺序PyTorch 侧和 ONNX 侧的张量排列可能不同一个[B, C, N]、一个[B, N, C]先打印 shape 对齐再做差不然会误判成导出失败。6.3 一个我反复验证的习惯从那以后我每次改完词表或者换数据集都强制走一遍固定流程先打印model.names和检测头的nc再拿一张必定包含目标类别的图跑一次确认至少有一个框最后才跑到批处理上。原因很简单开放词表这条链路上有三处地方都能让类别悄悄错位——词表顺序、set_classes的调用时机、重参数化后的权重固化——任何一处错了模型都不会报错只会安静地给你一堆框配上错的标签。这种静默失败比崩溃难查十倍加三步确认花不了两分钟。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

Multica:用 AI 搭建你的数字员工团队,TaoToken 统一 Key 接入实践

Multica:用 AI 搭建你的数字员工团队,TaoToken 统一 Key 接入实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/25 13:41:15
微信小程序点餐外卖源码:SKU、购物车合并与订单状态机

微信小程序点餐外卖源码:SKU、购物车合并与订单状态机

简介:这份微信小程序源码包面向餐饮商家、小程序初学者与需要完成课程设计或毕业设计的开发者,提供一套可直接部署改造的餐饮点餐外卖解决方案,涉及菜单浏览、在线下单、叫号排队、微信支付、配送状态跟踪、用户账号及订单管理等业务场景&…

📅 2026/10/25 13:41:15
Python AI五子棋实战:Minimax与Alpha-Beta剪枝实现解析

Python AI五子棋实战:Minimax与Alpha-Beta剪枝实现解析

简介:这份资源面向Python初学者与AI算法爱好者,提供一套可直接运行的五子棋AI实现方案,重点演示极大极小值搜索与Alpha-Beta剪枝在博弈决策中的落地方式。包内共12个文件,以py源码、xml配置、pyc缓存及iml工程文件为主&#xff0c…

📅 2026/10/25 13:36:15
MORE NEWS

更多资讯

📰

制造集团数字化转型规划:151页PPT拆解与落地避坑指南

简介:这份151页PPT是德勤为某大型制造集团编制的产业数字化转型规划方案,面向制造企业战略规划、数字化管理与咨询从业者,帮助解决集团层面数智化转型的顶层设计与落地路径问题。压缩包内仅含1个pptx文件,约19.98MB,内…

📰

TinyImageNetTorch:微调预训练模型的轻量级压力测试集

简介:本资源是一套基于PyTorch实现TinyImageNet数据集微调预训练模型的完整代码工程,面向深度学习初学者与教学实践者,解决小规模图像分类任务中模型快速适配与高效训练的实际问题。资源共34个文件,包含8个核心Python源码&#xf…

📰

DeepSeek双链路实战:硅基流动API与LM Studio本地部署

简介:《DeepSeek 非官网使用方法》配套PDF面向具备一定技术背景的AI开发者、自然语言处理学习者及需频繁处理文本解析任务的专业人士,聚焦官网之外的API调用与本地部署两条路径,帮助读者按响应效率、联网能力、成本和控制权限完成选型。文档共…

📰

C++从零实现CNN与全连接网络:手写梯度、内存与MNIST训练

简介:本资源是一套面向深度学习初学者与C开发者的实践型教学项目,聚焦神经网络底层原理与工程实现,帮助读者摆脱框架依赖,真正理解卷积神经网络(CNN)与全连接网络(FCN)的前向传播、反…

📰

基于深度学习的恶意加密流量检测毕设源码:DoH与CTU-13特征工程及模型复现

简介:本资源面向计算机、网络安全相关专业的本科生与研究生,提供一套基于深度学习的恶意加密流量检测系统完整实现方案,可用于毕业设计、课程大作业或期末项目。压缩包共217个文件,约25.61MB,包含4个Python核心脚本、6…

📰

基于FFmpeg的轻量级音视频播放器实现与同步原理

简介:这是一份基于FFmpeg 5.1开发的C音视频播放器实战项目,面向多媒体开发初学者与C进阶学习者,旨在帮助读者系统掌握FFmpeg核心API在真实播放器场景中的集成与应用。资源包含294个文件,主体为231个头文件(h&#xff0…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬