☰
YOLO-World开放词汇检测:PyTorch推理、微调与ONNX导出
2026/10/25 13:11:54 网站建设 项目流程

简介:面向计算机视觉开发者、目标检测学习者与需要开放词汇检测方案的工程人员,这份 YOLO-World 配套资料提供 PyTorch 实现、预训练权重及预训练/微调代码,可用于复现实验、课程项目、算法二次开发与快速验证。压缩包共 161 个文件,约 2.35MB,主体为 110 个 Python 源码,并配有 Markdown 文档、文本说明、JSON 配置、示例图片、Shell 脚本、Notebook、Dockerfile 及少量 C++ 文件,覆盖代码阅读、环境搭建与推理演示等用途。已有 883 人学习下载,适合希望理解 YOLO-World 开放词汇检测与视觉定位流程的读者参考。资料围绕 prompt-then-detect 范式组织,预训练权重可直接用于开放词汇推理,训练与微调代码便于替换数据集及类别文本,读者可据此了解模型结构、数据配置、训练与微调入口,并通过文档和示例脚本完成权重加载、检测验证与结果排查,目录结构较为清晰,能减少从零搭建环境的成本。

1. 从一个“换类别不用重训”的检测需求说起:YOLO-World 源码和文档能落地到什么程度

产线临时加一种物料,传统 YOLO 要重新采集、标注、训练,周期一拖就错过排产;YOLO-World 源码和文档吸引人的点,正是把类别先写成文本 prompt,在不重训的前提下跑出第一版检测结果,再决定是否补数据微调。它基于 PyTorch 生态,核心是视觉特征与文本嵌入的开放词汇检测,适合需要快速验证新类别、做竞品分析、给标注团队定边界的从业者,也适合想拆开源码理解文本编码器和检测头如何对接的开发者。资料给的是源码和文档,不是现成业务系统;能不能用,取决于你是否愿意先跑通基线、记录参数、再用自己的验证集卡住误检和漏检。

2. 把 PyTorch 环境跑通:从依赖检查到第一张图推理

2.1 先确认 CUDA、PyTorch 和 torchvision 的匹配关系

拿到 YOLO-World 源码后,最忌讳的做法是直接pip install -r requirements.txt然后跑 demo。开放词汇检测比普通 YOLO 多一个文本编码器,依赖链里同时牵扯 PyTorch、torchvision、CUDA 运行时和分词器组件,任何一处版本错位都可能在加载权重时炸出形状不匹配。我一般先建一个干净虚拟环境,再确认机器上的 CUDA 驱动能支撑当前 PyTorch 轮子,最后才装项目依赖。下面这段检查脚本不依赖项目代码,先把底座摸清楚。

# check_env.py import torch import torchvision print("torch:", torch.__version__) print("torchvision:", torchvision.__version__) print("cuda available:", torch.cuda.is_available()) print("cuda version:", torch.version.cuda) print("gpu count:", torch.cuda.device_count()) if torch.cuda.is_available(): print("gpu name:", torch.cuda.get_device_name(0)) # 做一次小矩阵乘法,确认 CUDA 不只是在“可见”层面可用 x = torch.randn(256, 256, device="cuda") y = torch.randn(256, 256, device="cuda") z = x @ y print("cuda matmul ok:", z.shape)

这段脚本的作用不是炫技,而是把“驱动可见 CUDA”和“PyTorch 真能跑算子”分开验证。torch.cuda.is_available()为真但矩阵乘法报错的情况并不少见,常见原因是容器里的 CUDA 运行时和宿主机驱动不匹配,或者装了 CPU 版 PyTorch。torch.version.cuda显示的是 PyTorch 编译时使用的 CUDA 版本,不是驱动版本;两者不需要完全相同,但大版本跨度太大就容易翻车。确认底座后,再按资料里的依赖说明安装,不要自己随手升级torch,否则文本编码器依赖的算子可能对不上。

如果机器没有 GPU,也能跑通推理,只是device要改成cpu,imgsz先降到 640 以内,别拿大图硬扛。CPU 推理适合验证类别名和预处理链路,不适合做批量评估。另一个常见坑是torchvision和torch分开安装导致版本错配,表现是导入torchvision.ops时报符号未定义;解决方式是按 PyTorch 官方轮子组合重装,而不是单独升级某一个包。

2.2 权重与目录:文本编码器不能漏

YOLO-World 的权重通常不止一个视觉检测权重,还涉及文本编码器权重或已经融合好的文本嵌入。资料里的文档一般会写清楚权重放置位置,但很多人只把检测权重放进目录,跑起来发现类别设置无效,或者报找不到 CLIP 相关文件。我一般先不猜文件名,而是从入口脚本和配置文件里反查它实际读取哪些路径,再用一个路径检查脚本把缺失项一次性列出来。

# 在项目根目录先看文档和配置里出现的权重路径关键词 grep -RIn --exclude-dir=.git -E "weight|ckpt|checkpoint|clip|text_encoder" . | head -80

这条命令只用来定位线索,不是让你无脑改路径。重点看入口脚本里default=或配置里model.weights、text_encoder这类字段,确认它是相对路径还是绝对路径。相对路径通常以项目根目录或配置文件所在目录为基准,不同代码风格不一样;跑之前先pwd确认当前目录,再决定要不要改配置。权重缺失的报错有时很绕,比如先报KeyError再报形状不匹配,本质都是文本侧没加载完整。

还有一个细节:如果资料里提供的是已经重参数化的权重,类别在导出时就被固化了,此时再改set_classes可能不生效。重参数化适合部署固定类别,不适合继续做开放词汇实验。验证方法是拿两个完全不同的类别列表各跑一次同一张图,如果输出类别名和框完全不变,基本可以判断你加载的是固化权重,或者文本嵌入被缓存后没有刷新。

2.3 跑通最小推理:类别列表、置信度和 NMS

最小推理不要一上来接摄像头,也不要用业务大图。选一张光线正常、目标清晰的测试图,先用三到五个英文类别跑通,确认输出框、类别名和分数都正常,再逐步换自己的类别。下面这段脚本按常见 Ultralytics 风格入口写;如果资料里的推理入口是配置式脚本,模型加载那两行换成文档里的入口,set_classes和预测参数的含义一致。

# minimal_infer.py from ultralytics import YOLOWorld # 权重路径按资料文档替换,不要写死不存在的文件 weights = "path/to/yolo_world_weights.pt" model = YOLOWorld(weights) # 类别先用英文短词,避免一上来就叠加分词和同义词问题 classes = ["person", "safety helmet", "forklift"] model.set_classes(classes) results = model.predict( source="path/to/test.jpg", imgsz=640, conf=0.25, iou=0.5, device=0, max_det=100, save=True, ) for r in results: # 打印类别名和分数,别只看保存出来的图 for box in r.boxes: cls_id = int(box.cls.item()) print(classes[cls_id], round(float(box.conf.item()), 3), box.xyxy.tolist())

set_classes要放在predict之前,且每次换类别后重新调用;有些封装会缓存文本嵌入,换类别不重新设置就会出现“明明改了列表,结果还是旧类别”的假象。imgsz控制推理分辨率,小目标多时可以提高,但显存和耗时也会上升;conf是置信度阈值,开放词汇检测里这个值不要照搬封闭词汇模型,类别名越抽象,分数分布越玄学,建议先用 0.15 到 0.35 之间做几组对比。iou是 NMS 阈值,密集目标场景可以适当降低,但太低会吞掉相邻框。device=0表示第一张 GPU,CPU 环境改成cpu。max_det限制每张图最多保留多少框,评估时不要设得太小,否则漏检会被误判成模型不行。

参数常见取值作用调整建议
imgsz640 / 800推理输入尺寸小目标多先试 800,显存不够再降
conf0.15~0.35置信度过滤开放类别先低后高,记录误检变化
iou0.45~0.6NMS 重叠阈值密集目标降低,稀疏目标保持 0.5
device0/cpu推理设备GPU 不可用时先 CPU 验证链路
max_det100~300单图最大检测数评估场景不要压得太低

2.4 基线记录:别凭一张图判断能用

跑出第一张图后,最容易犯的错是“看着还行”就直接接业务数据。开放词汇检测的稳定性跟类别措辞、图像域、阈值强相关,单图好看不代表批量可用。我一般会建一个很小的基线表,至少覆盖十张图、三组类别、两组conf,把检出数、误检数、漏检数和耗时记下来。这个表不追求漂亮,只用来判断下一步该调 prompt、调阈值,还是补数据微调。

图片编号类别组conf检出数明显误检明显漏检备注
img_001基础三类别0.25610远处小目标分数偏低
img_001基础三类别0.15830误检增加,适合召回优先
img_002加入同义词0.25502复合词拆分后漏检

记录时把“类别组”写清楚,不要只写“改过 prompt”。后面排查问题时,你会需要知道当时到底传了哪些字符串、有没有加模板、有没有换权重。基线跑通的标准不是检出所有目标,而是同一组输入重复跑两次结果一致、换类别后输出确实变化、GPU 和 CPU 的类别名映射一致。这三条过了,再进入源码结构和自定义数据。

3. 源码目录怎么读:文本编码、视觉融合和检测头三条线

3.1 从入口脚本倒推配置:先找 build model 和 text encoder

YOLO-World 源码看起来目录多,真正要抓的入口只有几条线:推理脚本、训练脚本、模型构建配置、数据配置。不要从最底层算子开始读,那样很容易陷进黑匣子。我一般先在入口脚本里搜build、model、text、set_classes这几个关键词,确认模型对象从哪里来、文本编码器在哪里初始化、类别列表最终传给了谁。这样读一遍,比对着目录树猜半小时有效。

# trace_entry.py from pathlib import Path # 把入口脚本路径换成资料里的实际文件 entry = Path("path/to/inference_or_train_entry.py") text = entry.read_text(encoding="utf-8", errors="ignore") for i, line in enumerate(text.splitlines(), 1): low = line.lower() if any(k in low for k in ["build", "text_encoder", "set_classes", "clip", "model("]): print(f"{i:04d}: {line.strip()}")

这段脚本只做静态定位,不执行项目代码。输出里重点看三类行:模型构建处、文本编码器初始化处、类别设置处。如果set_classes只是把字符串存进列表,真正编码发生在predict内部,那缓存问题就要去预测封装里找;如果入口脚本自己调用了 tokenizer 和文本编码器,那类别模板和最大 token 长度就会影响结果。clip关键词可能出现在配置名里,也可能只是注释,别看到就改,先确认它是不是实际加载路径。

读配置时还要注意一个分叉:有些实现把文本嵌入预先算好存成文件,推理时直接加载;有些实现每次set_classes都重新编码。前者启动快,但改类别后必须清缓存或重新生成嵌入;后者灵活,但批量推理时别在循环里反复set_classes,否则文本编码器会成为瓶颈。我一般把类别设置放在循环外,图片循环内只做predict,这样耗时更可控。

3.2 文本 prompt 进入模型后发生了什么

YOLO-World 的核心链路可以粗分成三段:图像经过视觉 backbone 和 neck 得到多尺度特征;类别名经过 tokenizer 和文本编码器得到文本嵌入;视觉特征与文本嵌入在融合模块里交互,检测头输出框和类别分数。开放词汇能力来自文本侧提供的语义锚点,所以类别名不是随便写的标签,它直接参与分类决策。把类别写成person和写成a photo of a person,在某些实现里分数分布会不一样,原因就是文本编码器看到的上下文变了。

这也解释了为什么同一个模型,换一组同义词,误检和漏检会跳变。类别名太短可能语义太宽,比如helmet会把安全帽、骑行头盔、摩托车头盔都拉进来;类别名太长又可能偏离训练分布,导致分数整体偏低。我一般先用短词跑基线,再针对误检类别加限定词,比如把helmet改成safety helmet,把car改成sedan car。每次只改一个类别,保留记录,否则出了问题不知道是哪次改动造成的。

如果资料里的配置支持 prompt 模板,不要把模板写死在推理脚本里。下面这种小函数适合放在配置层,模板和类别分开维护,后面做类别扰动实验也方便。

# prompt_config.py def build_prompts(classes, template="a photo of a {}"): # 模板只作用于需要上下文的类别,短词类别可以传 template=None if template is None: return list(classes) return [template.format(c) for c in classes] base_classes = ["person", "safety helmet", "forklift"] prompts_with_template = build_prompts(base_classes, template="a photo of a {}") prompts_plain = build_prompts(base_classes, template=None) print("plain:", prompts_plain) print("template:", prompts_with_template)

这段代码不直接调用模型,目的是把 prompt 生成逻辑独立出来。template参数决定是否给类别名加语境;classes保持原始英文短词,方便和标注文件里的类别名对应。实际传给set_classes的应该是最终字符串列表,而不是原始类别名和模板混在一起。模板不是越多越好,开放词汇检测里最常见的翻车是“训练时没见过这种模板,推理时分数整体塌了”,所以模板要和资料文档里的示例保持一致,改一次记一次。

3.3 自定义类别列表的写法:英文、同义词和复合词

自定义类别列表时,先遵守三个原则:用英文、用具体名词、一个类别只表达一个概念。中文类别名不是绝对不能跑,但文本编码器对中文的语义覆盖通常不如英文稳定,尤其遇到专业术语和缩写,分词结果可能完全偏离。常见做法是维护一张中文到英文的映射表,推理时传英文,展示时再映射回中文,这样既不破坏文本侧,也不影响业务可读性。

复合词要特别小心。worker_with_helmet这种下划线拼接不一定比worker wearing a helmet好,前者可能被 tokenizer 拆成奇怪片段,后者更接近自然语言。我的习惯是先把复合需求拆成两个单类别:person和safety helmet,分别检测后在业务层做空间关联,而不是硬压成一个类别。这样模型侧更稳定,后处理逻辑也更清楚。

# class_mapping.py cn_to_en = { "人员": "person", "安全帽": "safety helmet", "叉车": "forklift", "反光背心": "high visibility vest", } en_classes = list(cn_to_en.values()) # 传给模型的是英文列表,展示时用反查表 en_to_cn = {v: k for k, v in cn_to_en.items()} def show_name(en_name): return en_to_cn.get(en_name, en_name) print(en_classes) print(show_name("forklift"))

这段映射代码解决的是“模型侧稳定、业务侧可读”的分离问题。cn_to_en放在配置里维护,不要散落在多个脚本;en_classes的顺序要和后续结果解析一致,因为很多模型输出的是类别索引,索引错位比类别名写错更难查。show_name只做展示,不参与推理。如果资料里的模型支持中文文本编码,也要先用小批量图验证中文类别和英文类别的检出差异,别假设它一定等价。

3.4 重参数化导出:快,但动态类别会收窄

重参数化的价值是把文本嵌入固化进模型,推理时不再跑文本编码器,速度更稳,部署链路更简单。代价是类别被固定,导出后不能再像开放词汇模型那样随便set_classes。这一步适合“类别已经验证完、准备上固定场景”的阶段,不适合还在做类别探索的阶段。导出前先确认三件事:当前类别列表就是最终列表、预处理和后处理参数已经固定、导出的输入输出形状和推理引擎对得上。

# export_model.py from ultralytics import YOLOWorld model = YOLOWorld("path/to/yolo_world_weights.pt") model.set_classes(["person", "safety helmet", "forklift"]) # 导出格式按部署端选择,opset 和动态轴参数要跟推理引擎匹配 model.export(format="onnx", opset=12, simplify=True)

format决定导出目标,opset影响算子兼容性,simplify会尝试简化计算图但可能改变节点名。导出后不要只看文件生成成功,要拿同一张图对比导出前后的框数量和分数排序;如果导出后类别名全变成class_0,说明类别映射没有随模型一起保存,需要在部署端自己维护顺序。重参数化模型适合固定类别产线,如果业务经常加类别,保留开放词汇权重和导出权重两套,别把探索路径一刀切掉。

4. 用自己的数据验证:YOLO 格式转换、微调配置和评估口径

4.1 数据准备:YOLO 格式目录与 data.yaml

开放词汇模型可以先 zero-shot 跑一遍,但要上业务,最终还是要用自己的数据验证。数据格式优先跟资料里的训练脚本对齐;如果文档没有特别说明,常见做法是 YOLO 格式:images/train、images/val、labels/train、labels/val,标签文件里每行是class_id x_center y_center width height,坐标归一化到 0 到 1。类别 ID 从 0 开始连续编号,data.yaml里的names顺序必须和标签文件里的 ID 一致。这个顺序错位是最隐蔽的坑之一,训练 loss 看着正常,评估时类别全对不上。

# data.yaml path: /data/my_detection_dataset train: images/train val: images/val names: 0: person 1: safety helmet 2: forklift

path是数据集根目录,train和val是相对路径;如果你的训练入口不支持相对路径,就改成绝对路径。names的键必须是整数,值用英文短词,和推理时的类别列表保持一致。标签文件里不要出现空行以外的多余字符,Windows 换行和 BOM 都可能让解析器读错第一行。转换脚本写完先抽查十张图的可视化,确认框的位置和类别 ID 都对,再开始训练。

4.2 微调时冻结哪些层:文本编码器、backbone、检测头

微调策略取决于数据量。数据量很小的时候,我一般冻结文本编码器和大部分 backbone,只让融合层和检测头适应新域;数据量足够且类别差异大时,再逐步解冻。冻结太少容易过拟合,冻结太多又学不动新类别。资料里的训练配置通常会暴露freeze参数,常见做法是冻结前若干层,具体层数要看模型结构,不要照搬别人的数字。文本编码器是否冻结也要看目标:如果只是适应图像域,文本侧可以冻;如果要让类别名更贴合业务语义,才考虑解冻文本侧,但学习率要压低。

# Ultralytics 风格入口的示意,模型和路径按资料替换 yolo detect train \ model=path/to/yolo_world_weights.pt \ data=/data/my_detection_dataset/data.yaml \ imgsz=640 \ epochs=50 \ batch=8 \ freeze=10 \ lr0=0.001 \ device=0

freeze=10表示冻结前 10 层,不是所有实现都按层号计数,有的按模块名匹配,跑之前看日志里实际冻结了哪些参数。lr0是初始学习率,微调通常比从头训练小一个量级;batch受显存限制,先小后大,别为了追求大 batch 把imgsz偷偷降了却不记录。epochs不要一上来拉满,先跑短周期看验证集是否过拟合。训练日志里重点看分类 loss 和回归 loss 是否同步下降,如果分类 loss 降但验证 mAP 不升,可能是类别名和标签语义不匹配,或者数据里同一类有多种叫法。

4.3 训练命令与日志看什么

训练启动后不要只盯总 loss。开放词汇微调里,文本侧和视觉侧的适应速度不一样,总 loss 下降可能只是背景更容易分了。我一般同时看验证集的mAP50、mAP50-95、每类 precision 和 recall,再看混淆矩阵里有没有固定类别互相吞。如果某一类 recall 一直上不去,先检查标注框是否漏标,再检查类别名是否太泛。比如vest可能把普通马甲也算进去,改成high visibility vest后误检下降但召回也可能降,这时候要回到数据里看真实分布,而不是只调阈值。

# 验证入口示意,按资料里的评估脚本替换 yolo detect val \ model=runs/detect/train/weights/best.pt \ data=/data/my_detection_dataset/data.yaml \ imgsz=640 \ conf=0.001 \ iou=0.6 \ device=0

评估时conf设低一点,让 mAP 计算拿到完整 PR 曲线;iou设成和部署接近的值,但不要为了好看把评估阈值和部署阈值混为一谈。best.pt是按验证集指标选出来的,不代表业务场景最优,最终还要拿独立测试集跑一遍。日志里如果出现某类instances为 0,说明验证集没有该类样本,mAP 里这一类的值没有参考意义,别拿它下结论。

4.4 评估不要只看 demo 图:mAP、误检、漏检

demo 图只能证明链路通,不能证明模型可用。我一般把评估拆成三层:整体 mAP 看趋势,每类 P/R 看短板,业务抽样看误检和漏检的具体形态。整体 mAP 高但某一类 recall 低,说明这类需要补数据或改 prompt;整体 mAP 一般但误检集中在背景纹理,说明负样本不够。开放词汇模型的误检往往不是“框歪了”,而是“语义近邻被拉进来了”,比如把helmet检成hat,这时候改类别名比加数据更快见效。

指标看什么常见异常处理方向
mAP50宽松匹配下的整体检出高但业务误检多看每类 precision
mAP50-95框质量低但分类对检查标注框和回归 loss
每类 recall漏检某类持续低补样本或改类别措辞
每类 precision误检背景纹理被误检加负样本或收紧类别名

评估结果要按类别组记录,不要只存一个总分。后面做 prompt 对比时,同一套验证集、同一个conf口径才有可比性。数据量少的时候,训练集和验证集要按场景分,不要随机切图导致同一场景的相似图同时出现在两边,那样指标会虚高。

5. 避坑与排查:开放词汇检测最容易翻车的五件事

5.1 类别名写错导致“什么都检测不到”

现象是模型跑完不报错,但输出框极少,甚至为零,换一张图也一样。原因通常不是模型坏了,而是类别字符串和文本编码器预期不匹配:用了中文但文本侧英文为主、用了下划线拼接的复合词、类别名过长被截断,或者类别名和资料示例的格式差异太大。解决时先把类别退回到三到五个英文短词,用资料文档里的示例类别跑同一张图;如果示例能出框、你的类别不出框,问题就在 prompt。再把类别逐个替换,一次只换一个,找到触发问题的那个词。最后检查 tokenizer 的最大长度和是否截断,长短语不要硬塞。

5.2 缓存文本嵌入后改类别不生效

现象是set_classes明明改了列表,输出类别名还是旧的那几个,或者分数完全不变。原因是推理封装把文本嵌入缓存在模型对象或全局变量里,换类别没有触发重新编码;也可能是你加载的是重参数化权重,类别已经固化。解决时先确认权重类型,如果是开放词汇权重,就在每次换类别后新建模型对象或调用文档里的刷新接口;如果封装没有刷新接口,就把类别设置放在进程启动时,不要在一个进程里反复换。验证方法是拿两个语义差异很大的类别各跑一次,输出完全一致就说明缓存或固化权重在作怪。

5.3 导出 ONNX 后动态类别失效

现象是 PyTorch 下能正常set_classes,导出 ONNX 后只能输出固定类别,或者类别索引全变成数字。原因是重参数化导出把文本嵌入固化成了分类头权重,动态文本输入被裁掉;有些导出配置还会把类别名映射留在 Python 侧,不写进模型。解决时先明确部署需求:要动态类别就保留开放词汇模型和文本编码器,不要走固化导出;要固定类别就在导出前把类别列表定死,并在部署端按同样顺序维护映射表。导出后拿同一张图对比框数量和分数排序,别只看文件能不能加载。

5.4 数据标签 ID 与类别顺序错位

现象是训练 loss 正常,评估时某一类指标异常低,混淆矩阵里两类互相吞。原因是data.yaml的names顺序和标签文件里的class_id不一致,或者转换脚本按字母序重排了类别,而标签没有同步。解决时先抽十张图做可视化,把框上的类别名和原图对照;再用脚本统计每个 ID 的样本数,和names逐项核对。转换脚本里不要用集合去重后直接排序,集合顺序不稳定,必须显式维护class_to_id映射。评估前再跑一次标签合法性检查,确认没有越界 ID 和归一化坐标超出 0 到 1。

5.5 显存和 batch size 的假象

现象是训练一开始正常,跑几十步后显存暴涨或直接 OOM;或者把batch调大后 loss 看起来更稳,但验证指标下降。原因是开放词汇模型里文本编码器和融合模块的中间激活占用比普通检测器高,batch变大后每步样本数增加,等效学习率也变了,却没有同步调lr0。解决时先固定imgsz和模型配置,只调batch,记录显存峰值和每轮耗时;batch翻倍时学习率不要机械翻倍,先小步试。OOM 不一定是模型太大,也可能是评估阶段没关梯度或缓存了过多中间结果,训练和验证分开跑能快速定位。

6. 进阶验证:用“类别扰动实验”判断模型边界

类别能检出不等于类别稳定。我习惯在固定图片集上做一轮类别扰动:同一批图,分别用原始类别、同义词、上下位词、加模板短语跑一遍,记录每组的检出数、误检数和分数分布。这个实验不追求指标最高,而是看模型对措辞变化有多敏感。敏感度过高,说明业务侧必须锁死 prompt;敏感度低,才适合把类别配置交给现场人员维护。

# prompt_perturbation.py groups = { "base": ["person", "safety helmet", "forklift"], "synonym": ["worker", "hard hat", "forklift truck"], "hypernym": ["person", "helmet", "vehicle"], "template": ["a photo of a person", "a photo of a safety helmet", "a photo of a forklift"], } for name, classes in groups.items(): model.set_classes(classes) # 每次换组都重设,避免缓存干扰 results = model.predict("path/to/fixed_test_dir", imgsz=640, conf=0.25, iou=0.5, device=0) # 这里只记录数量和平均分,详细框信息落 CSV 方便复查 count = sum(len(r.boxes) for r in results) avg_conf = sum(float(b.conf.item()) for r in results for b in r.boxes) / max(count, 1) print(name, count, round(avg_conf, 3))

这段脚本的关键是固定图片目录、固定conf和iou,只变类别组。set_classes放在每组循环开头,防止缓存;count和avg_conf只是粗指标,真正排查还要把每张图的框落表。跑完你会看到某个同义词组检出数暴涨但平均分下降,那通常是语义变宽导致的误检;模板组分数整体偏低,说明模板偏离了资料里的示例分布。把这几组结果和业务抽样对照,就能判断该锁 prompt、补数据,还是换权重。从那以后我每次换类别配置都强制走一遍扰动实验,不再凭单张 demo 图下结论。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询