VisDrone 无人机小目标检测数据集在 YOLO26 中的完整训练实践:自动下载、YOLO 格式转换与配置解析
本文以 Ultralytics 官方文档 VisDrone 数据集页 为主体,系统讲解如何使用 data="VisDrone.yaml" 一键训练 YOLO26 检测模型。读完你可以掌握:VisDrone-DET 数据集的构成与划分(8,629 张航拍图像、10 个类别)、VisDrone.yaml 的完整字段与自动下载/标注转换脚本的逐行解析、底层自动下载机制在源码中的真实调用链,以及针对航拍小目标场景的训练调优建议(高分辨率、SAHI 切片推理)。
一、数据集概览:为什么 VisDrone 是小目标检测的标准基准
VisDrone 是由中国天津大学机器学习与数据挖掘实验室(MLDM)的 AISKYEYE 团队构建并维护的大规模无人机影像基准。完整基准包含在中国 14 个城市用机载相机采集的 288 段视频(共 261,908 帧)和 10,209 张静态图像,覆盖城市与乡村环境、稀疏与拥挤场景、多种天气与光照条件。全部帧累计带有 超过 260 万个手工标注边界框,并附带场景可见性、物体类别、遮挡程度等额外属性。
Ultralytics 仓库中的 VisDrone.yaml 配置只使用其中用于目标检测的 VisDrone2019-DET 静态图像子集,该子集提供 8,629 张航拍图像,全部划分为固定的 train / val / test-dev 三部分:
| 划分 | 图像数 | 用途 |
|---|---|---|
| Train | 6,471 | 用于训练检测器 |
| Validation | 548 | 开发阶段的验证 |
| Test-dev | 1,610 | 训练完成后做最终评测 |
此外还存在第四个划分 test-challenge(1,580 张),它被 VisDrone 竞赛扣留、不随下载脚本分发——这也是完整的 DET 集合总数为 10,209 张图像的原因。
1.1 关键特征
- 小而密的物体:航拍视角使目标又小又密集——仅 548 张验证图像就包含 38,759 个标注框,平均约 70 个物体/图。
- 场景多样性:来自 14 个中国城市,覆盖城市/乡村、白天/夜晚、不同天气。
- 标注丰富:全基准超过 260 万个框,且带遮挡(occlusion)与可见性(visibility)属性。
- 固定划分:train / val / test-dev(6,471 / 548 / 1,610)划分固定,便于一致性评测。
1.2 十个目标类别
数据集标注 10 个类别,与 VisDrone.yaml 中的 names 完全一致:
| 索引 | 类别 | 说明 |
|---|---|---|
| 0 | pedestrian | 站立或行走的行人 |
| 1 | people | 其他姿态的人 |
| 2 | bicycle | 自行车 |
| 3 | car | 小汽车 |
| 4 | van | 厢式车 |
| 5 | truck | 卡车 |
| 6 | tricycle | 三轮车 |
| 7 | awning-tricycle | 带篷三轮车 |
| 8 | bus | 公共汽车 |
| 9 | motor | 摩托车 |
注意 VisDrone 刻意区分 pedestrian(站立或行走的人)与 people(任何其他姿态的人),这两类的正确区分也是训练时需要关注的易混淆点。
二、Ultralytics 的 VisDrone.yaml 配置全解
Ultralytics 在 ultralytics/cfg/datasets/VisDrone.yaml 中维护该数据集的完整配置,包含三部分:路径定义、类别名、以及一段自动下载并转换为 YOLO 格式的 Python 脚本。
2.1 数据集目录结构与主配置
文件头部注释说明了下载后的目录约定:
# parent
# ├── ultralytics
# └── datasets
# └── VisDrone ← downloads here (~2 GB)
核心路径配置(相对于 path 的相对路径)为:
path: VisDrone # dataset root dir
train: images/train # train images (relative to 'path') 6471 images
val: images/val # val images (relative to 'path') 548 images
test: images/test # test-dev images (optional) 1610 images
train / val / test 支持三种形式:目录(path/to/imgs)、图像清单文件(path/to/imgs.txt)、目录列表,此处均为目录。注释中的 6471 images、548 images、1610 images 与上表的划分规模一一对应。
2.2 自动下载与 YOLO 转换脚本
download: 字段内嵌了一段可直接执行的 Python 脚本,是理解“首次训练自动下载”的关键。其核心函数 visdrone2yolo 负责格式转换:
def visdrone2yolo(dir, split, source_name=None):
"""Convert VisDrone annotations to YOLO format with images/{split} and labels/{split} structure."""
from PIL import Image
source_dir = dir / (source_name or f"VisDrone2019-DET-{split}")
images_dir = dir / "images" / split
labels_dir = dir / "labels" / split
labels_dir.mkdir(parents=True, exist_ok=True)
# Move images to new structure
if (source_images_dir := source_dir / "images").exists():
images_dir.mkdir(parents=True, exist_ok=True)
for img in source_images_dir.glob("*.jpg"):
img.rename(images_dir / img.name)
for f in TQDM((source_dir / "annotations").glob("*.txt"), desc=f"Converting {split}"):
img_size = Image.open(images_dir / f.with_suffix(".jpg").name).size
dw, dh = 1.0 / img_size[0], 1.0 / img_size[1]
lines = []
with open(f, encoding="utf-8") as file:
for row in [x.split(",") for x in file.read().strip().splitlines()]:
if row[4] != "0": # Skip ignored regions
x, y, w, h = map(int, row[:4])
cls = int(row[5]) - 1
# Convert to YOLO format
x_center, y_center = (x + w / 2) * dw, (y + h / 2) * dh
w_norm, h_norm = w * dw, h * dh
lines.append(f"{cls} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}\n")
(labels_dir / f.name).write_text("".join(lines), encoding="utf-8")
结合 VisDrone.yaml 的源码,转换逻辑有三个要点:
- 跳过被忽略的区域:VisDrone 原始标注每行是
x1,y1,w,h,ignored,cls,occlusion,truncation的 CSV 格式,脚本以row[4] != "0"判断,凡ignored字段非 0 的框一律丢弃(这同时排除了未被使用的 "others" 类别)。 - 类别索引下移一位:VisDrone 原始类别编号从 1 开始,脚本用
cls = int(row[5]) - 1映射到 YOLO 从 0 开始的 10 个类别。 - YOLO 归一化:先由 PIL 读取真实图像尺寸得到
dw, dh = 1/W, 1/H,再计算中心点与归一化宽高((x + w/2) * dw等),输出标准五元组cls xc yc w h(保留 6 位小数),文件写入labels/{split}/,与images/{split}/同名对应。
下载主流程则按“train → val → test-dev”三个压缩包顺序处理,刻意注释掉了 test-challenge 包:
# Download (ignores test-challenge split)
dir = Path(yaml["path"]) # dataset root dir
urls = [
f"{ASSETS_URL}/VisDrone2019-DET-train.zip",
f"{ASSETS_URL}/VisDrone2019-DET-val.zip",
f"{ASSETS_URL}/VisDrone2019-DET-test-dev.zip",
# f"{ASSETS_URL}/VisDrone2019-DET-test-challenge.zip",
]
download(urls, dir=dir, threads=4)
# Convert
splits = {"VisDrone2019-DET-train": "train", "VisDrone2019-DET-val": "val", "VisDrone2019-DET-test-dev": "test"}
for folder, split in splits.items():
visdrone2yolo(dir, split, folder) # convert VisDrone annotations to YOLO labels
shutil.rmtree(dir / folder) # cleanup original directory
可以看到:下载完成后脚本对每个划分先转换标注,再用 shutil.rmtree 删除原始 VisDrone2019-DET-* 目录,最终只保留干净的 images/ + labels/ 双目录结构。
三、源码级机制:自动下载是如何被触发的
“首次训练自动下载”并非魔法,其调用链在 ultralytics/data/utils.py 的 check_det_dataset() 中实现。关键流程如下:
- 定位 YAML:传入
data="VisDrone.yaml"后,check_file会先在包内ultralytics/cfg/datasets/目录中找到该文件;甚至允许直接传裸名(如data="VisDrone"),源码会自动尝试补全为.yaml/.yml(utils.py L567-L569)。 - 校验必填字段:函数强制要求 YAML 中存在
train和val键,且names或nc至少提供一个(L590-L617)——VisDrone.yaml 的 10 类names即在此通过校验,nc被自动推导为 10。 - 路径解析:
path: VisDrone是相对路径,源码会将其解析到全局数据集目录DATASETS_DIR之下(L623-L625)。DATASETS_DIR取自用户设置项SETTINGS["datasets_dir"],定义在 ultralytics/utils/init.py,默认位于 ultralytics 仓库同级目录的datasets/下。 - 执行 download 脚本:当
val指向的图像目录尚不存在且autodownload开启时,源码按download字段的值分派执行策略——以http开头且以.zip结尾的直接下载、以bash开头的走 shell 脚本,否则按 Python 脚本用exec(s, {"yaml": data})执行(L654-L660)。这解释了为什么 VisDrone.yaml 的脚本体内可以直接使用变量yaml(如Path(yaml["path"]))——它是被注入的执行上下文。 - 镜像源与并发:三个压缩包均从
ASSETS_URL拉取,该常量定义为 GitHub release 资产地址,见 ultralytics/utils/init.py L66;download(urls, dir=dir, threads=4)以 4 线程并发下载,脚本执行完毕后源码会打印形如Dataset download success ✅ (xx.xs)的日志(L661-L663)。
因此整条链路可以概括为:model.train(data="VisDrone.yaml") → check_det_dataset 发现 datasets/VisDrone/images/val 不存在 → exec 内嵌下载脚本 → 下载约 2 GB 的三个 zip → visdrone2yolo 转成 YOLO 标签 → 清理原始目录 → 训练继续。
四、训练实操:一键训练 YOLO26 检测模型
4.1 资源与空间预算
- 首次训练会自动下载 3 个压缩包,共约 2 GB;
- 解压并转换过程中大约需要 4 GB 空闲磁盘空间。
4.2 训练代码
以 YOLO26n 为例,在 VisDrone 上训练 100 个 epoch、图像尺寸 640:
Python 方式(数据集在首次运行时自动下载并转换):
from ultralytics import YOLO
# Load a model
model = YOLO("yolo26n.pt") # load a pretrained model (recommended for training)
# Train the model - dataset will auto-download on first run
results = model.train(data="VisDrone.yaml", epochs=100, imgsz=640)
CLI 方式:
# Start training from a pretrained *.pt model
# Dataset will auto-download and convert on first run
yolo detect train data=VisDrone.yaml model=yolo26n.pt epochs=100 imgsz=640
完整的训练参数(batch、patience、amp、增强选项等)请参考官方训练文档。
4.3 小目标精度调优建议
VisDrone 的困难在于物体相对画面极小(往往只有几十个像素),且常以密集、重度遮挡的群组出现,这使得在地面视角照片上调参的检测器直接迁移时会显著掉点。针对该数据集有两个被官方文档推荐的改进方向:
- 提高训练/推理分辨率:例如将
imgsz提到1280并适当减小 batch size,小目标就能在特征图上占据更多像素,从而被更完整地检测; - SAHI 切片推理:SAHI 瓦片化推理将大图切成多个窗口分别推理再合并结果,让每个推理窗口中小目标占比更高,适合大尺寸航拍图的推理阶段。更多通用建议见模型训练技巧。
五、典型应用场景与相关数据集
VisDrone 的密集场景与微小目标使其成为航拍视角小目标检测的标准基准,常见应用包括:
- 无人机交通监控与车辆计数
- 人群分析与公共安全监控
- 基础设施与施工现场巡检
- 杂乱场景中检测微小目标的计算机视觉研究
如果还有其他遥感/航拍基准需要对比,可以参考面向卫星影像的 xView 数据集(小目标同样突出)以及采用有向框标注的 DOTA-v2 数据集。
六、常见问题(FAQ)
Q1:VisDrone 能用于什么? 在无人机影像上训练和评测检测器——目标小、密集、俯视拍摄。其航拍视角、拥挤场景与多变条件的组合,使它成为 UAV 交通监控、人群分析和微小目标研究的常用测试床。
Q2:图像与类别数量? Ultralytics 配置包含 8,629 张图像(6,471 训练 / 548 验证 / 1,610 test-dev),全部共享同样 10 个类别:pedestrian、people、bicycle、car、van、truck、tricycle、awning-tricycle、bus、motor。
Q3:如何下载?
用 data="VisDrone.yaml" 首次训练时自动下载,无需手动操作。脚本从 Ultralytics 的 release 资产地址抓取约 2 GB 的三个压缩包,并把标注转换为 YOLO 格式;竞赛扣留的 test-challenge 划分不包含在内。
Q4:VisDrone-DET 与完整 VisDrone 基准的区别?
完整基准覆盖 5 项任务——图像检测、视频检测、单目标跟踪、多目标跟踪和人群计数,共 288 段视频与 10,209 张静态图像。Ultralytics 的 VisDrone.yaml 只覆盖图像检测任务(VisDrone2019-DET),即 6,471 / 548 / 1,610 三部分。
Q5:为什么检测器在 VisDrone 上表现差,怎么提升?
对象在画面中往往只有几十个像素且密集遮挡。如前所述,提高 imgsz(如 1280)配合更小的 batch,以及推理阶段使用 SAHI 切片,是两条有效的路径。
七、引用与致谢
若在研究中使用 VisDrone 数据集,请引用以下论文:
@ARTICLE{9573394,
author={Zhu, Pengfei and Wen, Longyin and Du, Dawei and Bian, Xiao and Fan, Heng and Hu, Qinghua and Ling, Haibin},
journal={IEEE Transactions on Pattern Analysis and Machine Intelligence},
title={Detection and Tracking Meet Drones Challenge},
year={2022},
volume={44},
number={11},
pages={7380-7399},
doi={10.1109/TPAMI.2021.3119563}}
感谢中国天津大学机器学习与数据挖掘实验室的 AISKYEYE 团队创建并持续维护 VisDrone 数据集。
小结
- 一份 YAML 搞定数据接入:ultralytics/cfg/datasets/VisDrone.yaml 把路径、10 类
names和内嵌下载/转换脚本合为一体,data="VisDrone.yaml"即可启动训练。 - 转换逻辑值得细读:跳过
ignored区域、类别编号减一、按真实图像尺寸归一化,三步完成 VisDrone 原始 CSV 到 YOLO 五元组的转换。 - 机制可溯源:自动下载由 check_det_dataset 在验证集目录缺失时
exec触发,下载源为ASSETS_URL(utils/__init__.py),数据集落地于DATASETS_DIR(utils/__init__.py L1527)。 - 针对小目标调优:提高
imgsz与 SAHI 切片推理是文档给出的两条提升航拍小目标召回率的主线。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00