简介:面向目标检测与车辆检测算法训练的数据集配套说明文档,适合需要构建交通监控场景车辆检测模型的开发者与算法学习者。数据集包含1000张真实场景道路车辆图片,覆盖城市道路、高速道路、农村道路及遮挡情境,标注类别涵盖Auto、Bus、Car、LCV、Motorcycle、Multi-Axle、Tractor、Truck共8类;所有样本经labelimg标注,同时提供VOC(xml)、COCO(json)、YOLO(txt)三种主流格式标签,可直接用于YOLO系列等算法训练。配套提供YOLO11一键训练脚本,支持GPU、CPU、Mac(M芯片)三平台运行,并附有训练结果日志供参考,能显著降低环境搭建与调参门槛。资源包为单份PDF文档,大小约7.19MB,内含数据集完整介绍与百度网盘获取方式;已有1333位用户学习下载,适合从事车辆识别、智能交通项目实践的个人或团队作为数据补充与训练基础。
1. 这套车辆检测数据集与三格式标签,到底解决了什么问题
一个目标检测项目的真实场景:你手上有一套车辆检测数据集,1000 张图,带着 VOC、COCO、YOLO 三种格式的标签,外加一个号称能在 GPU / CPU / Mac 三平台一键训练 YOLO11 的脚本。听起来像是开箱即用,但拿到手你会发现,真正卡住你的不是训练按钮,而是标签对不对得上、脚本在三个平台上能不能跑通、1000 张图训出来的模型到底能不能用于实际车辆检测。下面我按标签格式、环境配置、训练参数、避坑记录四个顺序把它拆开,讲清楚这套东西怎么落地。
这套方案适合两类人:一类是 0 基础纯小白,需要有人把 YOLO11(ultralytics)环境配置和训练命令一步步喂到嘴边;另一类是已经跑过几次目标检测、但总在格式转换和小数据集调参上翻车的熟手。1000 张图达不到工业级数据量,但作为垂直场景验证、原型演示、算法选型对比,完全够用。前提是你别急着点训练,先把三种标签格式和脚本边界看清楚。
2. 三种标签格式的内在差异与互相转换:先别急着训练
拿到多格式标签,新手的第一反应往往是“统一转成 YOLO,反正训练只认一种”。这个思路本身没问题,但直接转换会踩进类别索引错位、坐标换算错位、验证集和训练集划分不一致这几个坑里。YOLO 训练只需要 TXT,但 VOC 的 XML 和 COCO 的 JSON 里藏着图片尺寸、类别名、目标 ID 这些关键信息,转换时不把它们对齐,后面训练出来的模型就是废的。
2.1 VOC / COCO / YOLO 三种格式的底层组织方式
三种格式不是简单换了文件后缀,它们的标注坐标基准、类别表达方式、文件组织粒度完全不同。我把差异拆成一张表,训练前建议先对照着看一遍你的数据:
| 对比项 | VOC | COCO | YOLO |
|---|---|---|---|
| 标注文件形态 | 每张图一个 XML | 整个数据集一个 JSON | 每张图一个 TXT |
| 坐标基准 | 像素绝对坐标,xmin/ymin/xmax/ymax | 像素绝对坐标,x/y/width/height | 归一化坐标,x_center/y_center/width/height |
| 类别表达 | 字符串类名,如 car、bus | 整数 category_id | 整数索引,从 0 开始 |
| 图片尺寸来源 | XML 里有 size 字段 | JSON 的 images 里有宽高 | TXT 里没有,需从图片读取 |
| 典型目录 | JPEGImages + Annotations | 一个 annotations JSON 文件 | images + labels 平铺 |
这里有一个最常见的翻车点:VOC 的类别是“名字”,YOLO 的类别是“序号”。比如 VOC 里 object 的 name 是 car,转换时如果 car 对应 YOLO 的 0 号索引,那 classes 的顺序就得固定成car在最前面。你要是按字典序或者按读取顺序去生成这个映射,训练脚本里names写得跟转换时不一致,模型训练时看到的类别和推理时输出的类别就对不上了。
COCO 格式则是另一个极端。它把所有标注塞进一个 JSON,用 category_id 关联类别,用 image_id 关联图片。好处是 pycocotools 可以直接算 mAP,坏处是 JSON 一旦上几十 MB,手工打开根本没法排查。实际转换时很多人的做法是直接把 COCO 的 category_id 当成 YOLO 的索引号,这基本必错——COCO 的 category_id 是数据集自定义的,常见写法是 id 从 1 开始,而 YOLO 的 class_id 必须从 0 开始,且要连续。
2.2 VOC 到 YOLO 转换脚本的最小实现
把 VOC 转成 YOLO,核心就三件事:读 XML、拿图片尺寸、把 xmin/ymin/xmax/ymax 换成归一化的中心点加宽高。下面这个脚本是去掉异常处理的最小可用版本,适合先跑通再加固:
import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, img_w, img_h): tree = ET.parse(xml_path) root = tree.getroot() boxes = [] for obj in root.iter("object"): name = obj.find("name").text.strip() bndbox = obj.find("bndbox") xmin = float(bndbox.find("xmin").text) ymin = float(bndbox.find("ymin").text) xmax = float(bndbox.find("xmax").text) ymax = float(bndbox.find("ymax").text) x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h box_w = (xmax - xmin) / img_w box_h = (ymax - ymin) / img_h boxes.append((name, x_center, y_center, box_w, box_h)) return boxes # 类别映射:顺序决定了 YOLO 索引,必须和训练 YAML 的 names 完全一致 class_index = {"car": 0} img_w, img_h = 1920, 1080 boxes = voc_to_yolo("Annotations/xxx.xml", img_w, img_h) with open("labels/xxx.txt", "w") as f: for name, xc, yc, bw, bh in boxes: idx = class_index[name] f.write(f"{idx} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}\n")逻辑说明:这段代码把 XML 里绝对值坐标转成相对值。x_center 是 bbox 左右边界的平均值再除以图宽,box_w 是左右边界差除以图宽。YOLO 格式不接受像素值,所有数字必须在 0 到 1 之间。参数说明:class_index是整个脚本的地基,它的 key 顺序必须和训练时data.yaml里的names字段完全一致;img_w和img_h别从 XML 的 size 节点读,最好用cv2.imread或PIL.Image.open直接读原图,因为有些数据集标注尺寸和真实图片尺寸不一致,读错会导致所有框整体偏移。
2.3 COCO 到 YOLO 转换与类别索引错位检查
COCO 转 YOLO 比 VOC 多一道工序:先建立起 category_id 到 YOLO class_id 的映射,再按映射关系写 TXT。常见做法是遍历 JSON 里的categories列表,按它在数组中出现的顺序生成映射,不要直接用 COCO 自带的 id 字段:
import json import os def coco_to_yolo(json_path, output_dir): with open(json_path, "r") as f: coco = json.load(f) # 按 categories 数组的原始顺序建映射,保证类名可读 cat_id_to_name = {cat["id"]: cat["name"] for cat in coco["categories"]} names = [cat_id_to_name[cid] for cid in sorted(cat_id_to_name.keys())] name_to_idx = {name: idx for idx, name in enumerate(names)} img_id_to_info = {img["id"]: img for img in coco["images"]} anns_by_img = {} for ann in coco["annotations"]: anns_by_img.setdefault(ann["image_id"], []).append(ann) os.makedirs(output_dir, exist_ok=True) for img_id, anns in anns_by_img.items(): img = img_id_to_info[img_id] img_w, img_h = img["width"], img["height"] txt_path = os.path.join(output_dir, img["file_name"].replace(".jpg", ".txt")) with open(txt_path, "w") as f: for ann in anns: x, y, w, h = ann["bbox"] # COCO 的 bbox 是左上角 xy,YOLO 要的是中心点 xy xc, yc = (x + w / 2) / img_w, (y + h / 2) / img_h bw, bh = w / img_w, h / img_h idx = name_to_idx[cat_id_to_name[ann["category_id"]]] f.write(f"{idx} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}\n")逻辑说明:COCO 的 bbox 是左上角坐标加宽高,转 YOLO 时中心点要自己算;类别映射不能拿 category_id 直接当索引,必须通过类名重新编号,否则容易出现“训练时一类、推理时另一类”的错位。常见做法是先把所有类名按固定顺序写进names.txt,再反向生成索引表,这样脚本无论跑几次结果都一致。
转完格式,哪怕前面逻辑都写对了,也建议做三件事再进训练:第一,随机挑 5 张图,把标注框画在原图上人工看一眼,这一步能暴露坐标偏移和宽高反了的问题;第二,统计每个类别的目标数量,确认没有类别被漏掉;第三,检查 TXT 里所有归一化坐标是否都在 0 和 1 之间,溢出说明图片尺寸取错了。这三步做一遍也就十分钟,但能省掉后面整个训练周期的返工时间。
3. 在 GPU/CPU/Mac 三平台跑通 YOLO11:环境配置与一键训练脚本
标签格式稳了,下一个门槛是环境。YOLO11 这一代延续了 ultralytics 的调用方式,训练命令本身不复杂,复杂的是三套平台各自的环境差异。GPU 机器要装 CUDA 版 PyTorch,CPU 机器装普通版就行,Mac 要确认 MPS 后端可用,这三个坑不提前踩平,脚本跑起来就是各种 torch 报错。
3.1 YOLO11(ultralytics)环境配置的三条路径
以 0 基础纯小白的视角,我习惯把环境安装拆成三步:装 PyTorch、装 ultralytics、验证可用性。PyTorch 的安装命令因平台而异,我按常见做法整理成表:
| 平台 | 安装命令(常见做法) | 验证命令 |
|---|---|---|
| Linux/Windows 且显卡为 NVIDIA | pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 | python -c "import torch;print(torch.cuda.is_available())"输出 True |
| 无 GPU 的 CPU 机器 | pip install torch torchvision | python -c "import torch;print(torch.cuda.is_available())"输出 False 即可 |
| Mac(Apple Silicon 或 Intel) | pip install torch torchvision | python -c "import torch;print(torch.backends.mps.is_available())"输出 True |
然后统一执行pip install -U ultralytics。装完建议再跑一行完整验证,确认 YOLO11 能正常加载预训练权重,这一步会首次下载权重文件,耗时取决于网络:
python -c "from ultralytics import YOLO; model = YOLO('yolo11n.pt'); print(model.names)"逻辑说明:这行命令做两件事,一是验证 ultralytics 库安装成功,二是验证 yolo11n.pt 权重能被正确加载,能打印出类别名说明整个链路是通的。参数说明:yolo11n是这一代模型里参数最少的版本,适合先跑通流程;如果机器显存充足,后续可以换成yolo11s.pt或yolo11m.pt,效果会更好但训练更慢。
Mac 上最常踩的坑是 MPS 后端显示可用,但跑训练时频繁报某个算子不支持。我的做法是训练前先用device=mps跑 1 个 epoch,如果报算子错误,直接把设备换成device=cpu,虽然慢点但至少不会中途崩溃。另一个常见做法是升级到最新版 ultralytics,新版本对 MPS 的算子覆盖一直在补。
3.2 数据集 YAML 的组织方式与目录结构
YOLO11 训练不认识文件夹里有什么,它只认一个 data.yaml。这个 YAML 里写三样东西:图片路径、标注路径、类别信息。常见目录结构如下,图片和标签同名不同后缀,标签里每一行代表一个目标:
path: /home/user/vehicle_dataset train: images/train val: images/val nc: 1 names: 0: vehiclevehicle_dataset/ ├── images/ │ ├── train/ # 800 张 │ └── val/ # 200 张 ├── labels/ │ ├── train/ # 与 train 图片一一对应的 txt │ └── val/ └── data.yaml逻辑说明:path是数据集根目录,train和val是相对path的子目录,nc是类别数,names的索引顺序必须和标签文件里的数字一一对应。参数说明:如果数据集只有车辆一类,names写0: vehicle就行;如果包含 car、bus、truck 多类,按类别顺序全部列出,nc改成对应数量。
这里有两个容易忽略的细节。一是train和val划分要在图片和标签上同时生效,图片在images/train、标签就必须在labels/train,不能一边 train 一边 val。二是路径里不要带中文或空格,YOLO 训练脚本读取路径时遇到特殊字符很容易出诡异报错,这个对 Windows 用户尤其常见。
3.3 一键训练脚本:从裸命令到可在三平台复用
裸训练命令长这样,先把它跑通:
yolo detect train \ model=yolo11n.pt \ data=data.yaml \ epochs=100 \ batch=16 \ imgsz=640 \ device=0参数说明:model是预训练权重路径,data是上一步的 YAML,epochs是训练轮数,batch是每批图片数,imgsz是输入分辨率,device=0表示用第一张 NVIDIA 显卡,Mac 上改成mps,纯 CPU 改成cpu。这套参数在 1000 张图上一般二十分钟到一小时能跑完一轮,具体看显卡型号。
裸命令能跑通后,再把三平台差异封装进脚本。我习惯的做法是写一个 bash 脚本,自动判断系统类型并选择 device,同时把训练日志落到文件里,方便事后排查:
#!/usr/bin/env bash set -e # 自动选择训练设备:Mac 用 MPS,带 NVIDIA 显卡用 0,否则用 CPU if [[ "$(uname)" == "Darwin" ]]; then DEVICE="mps" elif python -c "import torch; print(torch.cuda.is_available())" | grep -q True; then DEVICE="0" else DEVICE="cpu" fi echo "[INFO] 当前训练设备: $DEVICE" yolo detect train \ model=yolo11n.pt \ data=data.yaml \ epochs=100 \ batch=16 \ imgsz=640 \ device=$DEVICE \ project=./runs \ name=vehicle_yolo11 \ > train.log 2>&1 echo "[INFO] 训练完成,最佳权重在 runs/vehicle_yolo11/weights/best.pt"逻辑说明:脚本先用 uname 判断是不是 Mac,再用 torch.cuda.is_available 判断有没有可用显卡,最后把训练输出重定向到 train.log。这段脚本的妙处在于同一份代码在三种平台上都能跑,不用每换一台机器就改一次 device。参数说明:project和name控制训练结果的保存位置,best.pt是验证集上表现最好的权重,后续做推理验证就用它。
脚本写好后chmod +x train.sh再./train.sh执行。如果 train.log 里出现显存不足错误,把 batch 从 16 降到 8;如果训练特别慢,确认 device 是否真的选对了。跑通这一条,三平台一键训练的骨架就算立住了。
4. 1000 张车辆图的训练参数调法:先调稳再调准
环境通了、脚本能跑,接下来才是真正体现功力的部分:参数怎么调。YOLO11 的默认参数是给 COCO 这种几十万张的大数据集设计的,直接套在 1000 张车辆图上,你大概率会看到 loss 曲线剧烈震荡、验证集 mAP 上不去、训练到一半就早停。不是模型不行,是参数没跟着数据量走。
4.1 从数据集规模反推参数:先看这几个关键项
我在 1000 张小数据集上训练,第一步不是改学习率,而是定模型规模、batch、imgsz、训练轮数这四个基础参数。它们之间有连带关系,改一个往往要动另一个。给一套可直接抄的初始配置:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| model | yolo11n.pt 或 yolo11s.pt | 参数少,1000 张图不容易过拟合 |
| epochs | 150 | 配合早停,实际跑多少以 patience 判断 |
| batch | 16(GPU)/ 8(MPS)/ 4(CPU) | 显存不够优先降 batch,别降 imgsz |
| imgsz | 640 | 车辆目标较大,640 足够,960 会显著变慢 |
| patience | 30 | 连续 30 轮 mAP 不涨就停 |
| optimizer | auto | 让 ultralytics 自己选,手动改容易翻车 |
参数说明:yolo11n是指标下限最低但速度最快的选择,yolo11s精度略高、训练时间翻倍。1000 张图这个规模,我一般直接上yolo11s.pt,因为车辆是相对规整的目标,模型容量大一点能学到更多细节,同时又不会像yolo11m那样明显过拟合。batch的设定要考虑显存,显卡报错时先减半,不要硬凑 16。
imgsz=640是最稳的起点。车辆检测不像小目标检测那样必须用 960 或 1280 去放大输入,640 在精度和速度之间最平衡。等你把 loss 曲线跑稳了,再尝试把 imgsz 提到 800,看 mAP 是否真的上涨,如果没涨就换回来,这一步属于精调阶段。
4.2 预训练权重与数据增强:小数据集最容易在这里翻车
小数据集训练,最忌讳的是从头开始训练。YOLO11 的预训练权重已经在 COCO 上见识过大量车辆图片,你拿它做初始化,模型起步就带了一批通用的特征提取能力。如果完全从随机权重开始,1000 张图大概率只能学到场景分布,遇到新角度直接漏检。所以我的原则是:永远从预训练权重起步,只在个别类别差异极大时才考虑从头训。
数据增强是另一个两极分化的参数组。YOLO11 默认开启 mosaic、翻转、HSV 扰动等增强,对大数据集是好事,对 1000 张这种规模反而容易增强过度,让模型一直看到变形严重的样本。我通常会这样调:
# data.yaml 同级目录下的增强配置,或直接在命令行传参 hsv_h: 0.015 hsv_s: 0.5 hsv_v: 0.4 degrees: 0.0 translate: 0.1 scale: 0.5 fliplr: 0.5 flipud: 0.0 mosaic: 0.8 mixup: 0.15逻辑说明:hsv_h/s/v控制颜色扰动,车辆出现在不同光照、不同颜色的场景里,适度的 HSV 扰动相当于免费扩充了光照多样性;fliplr=0.5是左右翻转,车辆基本对称,放心开;flipud=0.0是上下翻转,绝不能开,车顶朝下会产生大量错误标注;mosaic=0.8把四张图拼成一张训练,等于变相扩充了小目标的样本量;mixup=0.15做图像混合,数值别超过 0.2。参数说明:如果你发现训练初期 loss 下不去,先把degrees和translate调小,几何扰动对小数据集最伤。
这些增强参数在 YOLO11 里可以直接写进训练命令,也可以放到 YAML 里。我习惯写在 YAML 里,因为脚本只维护一份配置,换数据集时不用改命令。但增强参数不是越大越好,翻车的典型表现是 loss 前 20 轮不降反升,那就是增强过猛,模型连真实目标长什么样都看不清了。
4.3 训练中断与恢复:别让一次断电毁掉全部进度
小数据集训练通常要一两个小时,遇到服务器重启、显存占用被别的进程抢走、或者笔记本合盖导致训练中止,心态很容易崩。YOLO11 自带断点续训能力,训练过程中每个 epoch 都会保存last.pt,中断后从它继续就行:
yolo detect train resume=True逻辑说明:训练中断后再执行这条命令,ultralytics 会自动从上次训练目录里的last.pt恢复,同时读回当时的训练状态和超参数。参数说明:如果你移动过训练目录,或者换了机器,可以手动指定权重路径model=/path/to/last.pt,但要配合resume=True使用,否则会被当成新权重从头训。
恢复训练有一个隐藏规则:别改 imgsz 和 batch。学习率计划是按总步数算的,你改了 batch 等于改了每个 epoch 的步数,学习率曲线就对不上了;改了 imgsz 会让后面的验证指标和前面完全不可比。我遇到过几次恢复后 mAP 反而变低,最后发现都是因为恢复时顺手改了参数,改回原值再恢复就正常了。养成习惯:把训练命令原样复制一份存档,恢复训练时只改resume=True,其他一律不动。
5. 避坑清单:标签错位、平台差异与验证集翻车现场
训练参数调完,真正的考验才刚刚开始。这章我把三平台训练 1000 张车辆数据时最容易碰到的五个问题,按现象、原因、解决的顺序完整写出来。每条看起来都不起眼,但足够让一个整天的心血白费。
5.1 现象:loss 正常下降,但验证集 mAP 一直是 0
这是训练中最迷惑人的状态:训练日志里 box_loss 和 cls_loss 都在降,训练集预测图看着也有框,但验证集 mAP50、mAP50-95 全部为 0。原因几乎都出在标签和验证集的匹配上。最常见的是转换格式时 classes.txt 的顺序和 data.yaml 里 names 的顺序不一致,模型训练时学的类别索引和验证时算的索引对不上;另一个常见原因是验证集图片对应的标签 txt 根本没生成,模型在验证集上一张目标都找不到。
解决步骤:第一步,进 labels/val 目录看是不是每张验证图片都有同名 txt;第二步,统计所有 txt 里的类别序号,确认只有 0 或 1,出现 1 说明映射溢出;第三步,写几行代码把验证集标签画在图上,看框的位置是否贴合车辆。这三步走完,九成问题能找到根源。别盯着 loss 曲线发呆,loss 下降只能说明训练集上拟合得不错,验证集 mAP 靠的是标签格式完全正确。
5.2 现象:Mac 上训练比 CPU 还慢,或者中途直接崩掉
在 Mac 上跑 YOLO11,device=mps看起来是一条捷径,实际用起来却是玄学。我见过 Mac 上 MPS 训练比 CPU 慢三倍的情况,也见过训练到第 40 轮突然报某个算子不支持直接终止的。原因有两个:一是 MPS 后端对部分算子的实现还是走的 CPU fallback,数据在 GPU 和 CPU 之间反复拷贝,速度自然上不去;二是 batch 设置过大,统一内存被撑爆,系统开始疯狂交换内存。
解决方法分优先级:先把 batch 从 16 降到 8,imgsz 从 640 降到 640 不动,模型换成 yolo11n;如果还崩,把workers设为 0,Mac 上 DataLoader 多进程时常引发 spawn 崩溃;最后直接退回device=cpu,慢但至少能出结果。我的血泪经验是:Mac 上做小规模验证可以,真要训练大模型,找一台 NVIDIA 显卡的机器会省下大量时间。
5.3 现象:训练跑一半报 CUDA out of memory
显存不足在 GPU 上训练时太常见了,尤其是在你想提高精度把 imgsz 从 640 改到 960 之后。显存占用和 imgsz 近似平方关系,640 时 batch 16 没问题,960 时 batch 8 都可能爆。另一个隐蔽原因是后台还有别的进程占着显存,比如之前训练崩了但进程没杀干净。
解决步骤:先执行nvidia-smi看显存被谁占用,如果有残留 Python 进程就 kill 掉;然后看当前命令的 batch 和 imgsz,batch 减半是最直接的解法;最后一步,把 mosaic 增强关掉也能省显存,因为它需要同时缓存四张图的特征。显存问题本质上是资源调配问题,YOLO11 本身没有魔法,只能靠降 batch 或降 imgsz 换空间。
5.4 现象:数据集加了新图重新训练,mAP 不升反降
1000 张图想进一步提升精度,最自然的想法是扩充数据集。但很多人加完图发现 mAP 反而掉了,这不是模型变笨了,而是增量训练的方式不对。原因有两类:一是新图片的标注风格和旧图不一致,比如旧图框得紧、新图框得松,模型在同样的目标上看到完全不同的边界,训练目标自相矛盾;二是重新训练时又用了预训练权重从头跑,学习率从头开始衰减,旧数据学到的东西被逐渐覆盖。
解决做法:第一种情况,扩充数据后先做标注质量抽检,确认新旧的框风格一致;第二种情况,用model=runs/xxx/weights/last.pt作为初始权重继续训练,这样模型是在已有能力的基础上微调,而不是重新学。另外,新图片的分布不要突变,全是白天场景的数据集突然加入大量夜间图,mAP 短期内下降是正常的,要给模型足够多的 epoch 去适应新分布。
5.5 现象:验证集表现不错,一到实地拍摄就漏检
这是所有小数据集训练者最痛的一关。1000 张图里可能 80% 是白天、晴天、市区场景,模型在这些场景里 mAP 很高,但换到雨天、夜晚、逆光、高速运动场景就直接漏检。原因是数据分布覆盖不够,数据增强只能做颜色和几何扰动,补不了“雨天挡风玻璃”“夜间路灯反光”这种真实域差异。
解决思路:第一步,把模型跑到一段实地拍摄的视频上,按帧抽样找漏检最集中的场景,针对性补采 200 到 300 张图;第二步,暂时补不了数据时,用现有模型对目标场景做伪标签,人工筛选后加入训练,这是一种半监督的迭代方式;第三步,在最终落地时,把检测结果接到多模态信息上去做二次过滤,比如结合车辆轨迹连续性和多视角信息,降低单帧漏检的影响。车辆检测这个方向,数据覆盖度决定模型上限,参数只能决定在已有分布上发挥多少。
6. 验证模型效果与继续涨点:从 1000 张图往实用走
模型训练完,真正决定它能不能用的不是训练日志里的 mAP,而是你亲手画出来的框。我养成的习惯是:先随机抽 30 张验证集图片,用 best.pt 跑一遍预测并保存可视化结果,肉眼确认每个目标的位置、置信度、类别都对,再回头谈指标。框的位置偏了半个车身,mAP 再高也是废的。
from ultralytics import YOLO model = YOLO("runs/vehicle_yolo11/weights/best.pt") results = model.predict( source="test_images/", conf=0.4, save=True, project="results", name="visual_check", )逻辑说明:conf=0.4是置信度阈值,低于这个值的检测框会被过滤掉。参数说明:如果发现很多真实车辆被过滤掉了,把 conf 降到 0.25 再看;如果发现大量误检框,把 conf 提到 0.6。每个项目的最佳阈值不一样,这个值就是用来给你试的。我一般会在 0.25、0.4、0.6 三档各跑一遍,选出误检和漏检平衡最好的那一档。
可视化验证通过后,想继续涨点有三个方向,按性价比排序:第一,补充新场景数据,把漏检最集中的场景单独挖出来补采,这是数据驱动的正道;第二,做难例挖掘,用当前模型跑完所有训练图,把 loss 最高的那些图挑出来重点分析,看是标注问题还是模型问题;第三,微调阶段把 imgsz 从 640 提到 800,加少量 epoch 再看 mAP 是否真的上涨。我以前也图省事,跳过可视化直接看 mAP,结果被“mAP 挺高但实拍帧帧漏检”狠狠打过脸,现在哪怕时间再紧,也会先画框再谈指标,这个顺序能少走很多弯路。希望帮到你。
本文还有配套的精品资源,点击获取