
简介本资源面向无人机航拍目标检测的学习者与开发者提供基于Visdrone数据集的YOLOv5训练成果帮助解决小目标密集场景下模型训练与验证的实际问题。压缩包共126个文件约680.11MB涵盖yaml配置、py源码、pt权重、jpg与png图像、mp4测试视频、xml标注及sh、yml等脚本文件结构完整便于直接复现与二次开发。资源内含YOLOv5s-visdrone.pt与yolov5m-visdrone.pt两个训练权重并附训练曲线、相关场景测试视频以及yolov5-5.0完整代码可直观对比不同规模模型在航拍视角下的检测表现。目前已有4358人学习下载适合具备一定深度学习基础、希望快速验证Visdrone检测方案或进行迁移学习的研究者与工程人员参考使用。1. Visdrone数据集YOLOv5训练权重无人机视角下的小目标检测到底难在哪拿到yolov5-5.0-visdrone.zip这个权重包的人十有八九是冲着 Visdrone 数据集去的。Visdrone 是无人机航拍视角的目标检测数据集标注了行人、车辆、自行车等十类目标特点是目标尺度极小、分布密集、背景复杂。用 COCO 预训练权重直接推理 Visdrone 图片你会发现行人只有十几个像素模型几乎全漏。这就是为什么需要专门在 Visdrone 上微调的 YOLOv5 权重——它不是通用模型而是针对航拍小目标场景重新收敛过的。这个权重包适合三类人一是做无人机巡检、交通监控的工程师需要一个能直接跑通 Visdrone 类目标的基线二是想学习小目标检测微调策略的研究者拿现成权重省去从头训练的时间三是需要在边缘设备上部署航拍检测的开发者YOLOv5-5.0 的工程化程度足够支撑后续量化导出。但要注意权重不是万能钥匙输入分辨率、类别映射、置信度阈值这三件事没对齐照样翻车。2. Visdrone数据集与YOLOv5-5.0的匹配逻辑为什么不是随便一个权重都能用2.1 Visdrone的标注格式与YOLOv5的适配关系Visdrone 原始标注是 CSV 格式每行包含bbox_left, bbox_top, bbox_width, bbox_height, score, object_category, truncation, occlusion。YOLOv5 需要的是每张图对应一个.txt文件每行class_id x_center y_center width height且坐标必须归一化到 0~1。这个转换不是简单除法有几个边界情况必须处理。常见做法是写一个转换脚本把 Visdrone 的 CSV 按图片名分组逐行转换。下面是我一般会用的转换逻辑import os import csv from PIL import Image # Visdrone类别映射原始类别ID从1开始YOLOv5从0开始 # 原始类别1pedestrian, 2people, 3bicycle, 4car, 5van, 6truck, 7tricycle, 8awning-tricycle, 9bus, 10motor CATEGORY_MAP {1:0, 2:1, 3:2, 4:3, 5:4, 6:5, 7:6, 8:7, 9:8, 10:9} def visdrone2yolo(csv_path, img_dir, label_dir): os.makedirs(label_dir, exist_okTrue) # 按图片名聚合标注 img_anns {} with open(csv_path, r) as f: reader csv.reader(f) for row in reader: if len(row) 8: continue img_name row[0] # 跳过score为0的忽略区域 if int(row[4]) 0: continue cat int(row[5]) if cat not in CATEGORY_MAP: continue bbox [float(row[1]), float(row[2]), float(row[3]), float(row[4])] img_anns.setdefault(img_name, []).append((CATEGORY_MAP[cat], bbox)) for img_name, anns in img_anns.items(): img_path os.path.join(img_dir, img_name) if not os.path.exists(img_path): continue w, h Image.open(img_path).size label_path os.path.join(label_dir, img_name.replace(.jpg, .txt)) with open(label_path, w) as f: for cls_id, (bx, by, bw, bh) in anns: # 归一化并转为中心点格式 x_center (bx bw / 2) / w y_center (by bh / 2) / h nw bw / w nh bh / h # 裁剪到0~1防止越界 x_center max(0, min(1, x_center)) y_center max(0, min(1, y_center)) nw max(0, min(1, nw)) nh max(0, min(1, nh)) f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {nw:.6f} {nh:.6f}\n)这段代码的关键点有三个第一score0的行是 Visdrone 定义的忽略区域必须跳过否则会引入噪声第二坐标裁剪到 0~1 是防止某些标注框超出图像边界导致训练时 loss 爆炸第三类别映射必须和权重文件的names顺序一致否则推理时类别全错。2.2 YOLOv5-5.0的模型结构与小目标检测的冲突点YOLOv5-5.0 的默认结构是 CSPDarknet53 主干 PANet 颈部 三个检测头分别对应 80×80、40×40、20×20 的特征图输入 640×640 时。Visdrone 里大量目标在 10~30 像素之间20×20 的检测头感受野太大小目标特征在深层特征图上几乎消失。这就是为什么直接用 COCO 权重推理 Visdrone 会漏检——不是权重不好是尺度不匹配。yolov5-5.0-visdrone.zip里的权重之所以有用是因为它在 Visdrone 上微调过检测头的权重已经适应了小目标分布。但如果你要自己从头训练有几个参数必须改--img-size建议设到 1024 或 1280让更多小目标在特征图上有足够像素--anchors要用 Visdrone 的 K-means 聚类结果重新生成默认的 COCO anchor 尺寸偏大--hyp里的mosaic和mixup增强对小目标有帮助但mosaic的degrees旋转角度不宜过大否则小目标旋转后更模糊。2.3 权重文件的结构与加载方式YOLOv5-5.0 的权重文件是 PyTorch 的.pt格式内部是一个字典包含model模型结构、ema指数移动平均权重、optimizer优化器状态推理时不需要、best_fitness、epoch等字段。加载时用torch.load()即可但要注意版本兼容性——YOLOv5-5.0 的权重在 6.0 以上版本加载可能会报KeyError因为模型结构有变动。import torch # 加载Visdrone微调权重 ckpt torch.load(yolov5-5.0-visdrone.pt, map_locationcpu) # 查看权重包含的类别 print(ckpt[model].names) # 应该是Visdrone的10类 # 查看训练时的输入尺寸 print(ckpt[model].yaml.get(imgsz, 未记录)) # 推理时只需要model和ema model ckpt[ema if ckpt.get(ema) else model].float() model.eval()如果加载时报RuntimeError: Unexpected key(s) in state_dict说明权重和当前代码的模型定义不一致。解决办法是找到权重对应的yolov5l.yaml或yolov5s.yaml用相同的配置文件构建模型后再加载。Visdrone 权重通常基于yolov5l或yolov5m因为小目标检测需要更大的模型容量。3. 用yolov5-5.0-visdrone权重跑通推理从环境配置到结果可视化3.1 环境依赖与版本锁定YOLOv5-5.0 对 PyTorch 和 CUDA 版本有要求。我一般会锁定以下组合Python 3.8、PyTorch 1.8.0、torchvision 0.9.0、CUDA 11.1。这个组合在 5.0 版本上最稳定不会出现torch.meshgrid的警告或amp检查失败的问题。# 创建虚拟环境 conda create -n yolov5-visdrone python3.8 -y conda activate yolov5-visdrone # 安装PyTorch根据你的CUDA版本调整 pip install torch1.8.0cu111 torchvision0.9.0cu111 -f https://download.pytorch.org/whl/torch_stable.html # 安装YOLOv5-5.0依赖 pip install -r requirements.txt # requirements.txt里包含numpy, opencv-python, Pillow, PyYAML, requests, scipy, tqdm, matplotlib, pandas, seaborn注意YOLOv5-5.0 的requirements.txt里opencv-python版本不要装太高4.5.x 即可4.8 以上在某些系统上会和torchvision冲突导致ImportError。3.2 推理命令与参数含义假设你已经把权重文件放在weights/yolov5-5.0-visdrone.pt测试图片在inference/images/下推理命令如下python detect.py \ --weights weights/yolov5-5.0-visdrone.pt \ --source inference/images/ \ --img-size 1024 \ --conf-thres 0.25 \ --iou-thres 0.45 \ --device 0 \ --save-txt \ --project runs/detect \ --name visdrone_test参数逐个说明--img-size 1024是推理分辨率Visdrone 小目标必须用大分辨率640 会漏掉一半行人--conf-thres 0.25是置信度阈值Visdrone 场景下建议比 COCO 的 0.5 低因为小目标置信度普遍偏低--iou-thres 0.45是 NMS 的 IoU 阈值密集场景下可以降到 0.4 减少漏检--save-txt会保存每张图的检测结果到 txt方便后续评估--device 0指定 GPU没有 GPU 就写cpu但速度会慢很多。推理完成后结果保存在runs/detect/visdrone_test/下图片带框txt 文件每行格式是class_id x_center y_center width height confidence坐标是归一化的。3.3 结果可视化与类别映射检查推理跑通后第一件事是检查类别映射对不对。Visdrone 的 10 类在权重里的顺序是pedestrian, people, bicycle, car, van, truck, tricycle, awning-tricycle, bus, motor。如果你发现检测框位置对但类别标签全是乱的说明权重训练时的类别顺序和你的data.yaml不一致。import cv2 import numpy as np # 读取检测结果并绘制 img cv2.imread(inference/images/test.jpg) h, w img.shape[:2] names [pedestrian, people, bicycle, car, van, truck, tricycle, awning-tricycle, bus, motor] colors np.random.randint(0, 255, (len(names), 3)).tolist() with open(runs/detect/visdrone_test/test.txt, r) as f: for line in f: parts line.strip().split() cls_id int(parts[0]) xc, yc, bw, bh, conf map(float, parts[1:]) # 反归一化 x1 int((xc - bw/2) * w) y1 int((yc - bh/2) * h) x2 int((xc bw/2) * w) y2 int((yc bh/2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), colors[cls_id], 2) cv2.putText(img, f{names[cls_id]} {conf:.2f}, (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, colors[cls_id], 1) cv2.imwrite(visdrone_result.jpg, img)这段代码的作用是把归一化坐标还原成像素坐标然后画框。如果发现框的位置偏移很大检查--img-size是否和推理时一致YOLOv5 在推理时会做 letterbox 填充坐标还原时要考虑填充偏移。不过detect.py保存的 txt 已经是还原后的归一化坐标直接用即可。4. 避坑与排查Visdrone训练权重落地时最容易翻车的5个地方4.1 现象推理结果全是背景一个目标都没有原因置信度阈值设太高或者权重加载时用了model而不是ema。Visdrone 小目标的置信度普遍在 0.1~0.4 之间用 COCO 的 0.5 阈值会过滤掉所有小目标。另外YOLOv5-5.0 的ema权重比model权重更稳定如果代码里默认加载model效果会差一截。解决把--conf-thres降到 0.1 先看有没有框确认有检测后再逐步调高到 0.25 左右。加载权重时显式指定ckpt[ema]如果ema不存在再用model。4.2 现象训练时loss正常下降但验证集mAP一直是0原因验证集的标注路径或类别映射错了。YOLOv5 在验证时会读取data.yaml里的val路径如果路径下没有对应的.txt标注或者标注里的类别 ID 超出了nc的范围mAP 计算会直接返回 0。解决检查data.yaml的val路径是否指向正确的图片目录对应的labels目录是否存在且文件名匹配。用python -c import os; print(len(os.listdir(val/labels)))确认标注文件数量。另外Visdrone 的验证集有部分图片没有标注这些图片的 txt 文件应该是空的不能缺失。4.3 现象GPU显存溢出batch-size调到1还是OOM原因--img-size设太大。Visdrone 常用 1024 或 1280但如果你用的是yolov5l或yolov5x1024 分辨率下 batch-size4 就可能爆显存。另外--rect参数在 YOLOv5-5.0 里对显存优化有限不如直接降分辨率。解决先用--img-size 640跑通确认流程没问题后再逐步提高到 1024。如果必须用 1024把模型换成yolov5s或yolov5m或者用--batch-size 2配合梯度累积。梯度累积在 YOLOv5-5.0 里没有原生支持需要手动改训练循环。4.4 现象检测框重叠严重同一个目标出现多个框原因NMS 的 IoU 阈值设太高或者--agnostic-nms没开。Visdrone 密集场景下不同类别的框可能重叠默认的类别内 NMS 无法抑制跨类别重叠。解决把--iou-thres从 0.45 降到 0.35并加上--agnostic-nms让 NMS 在所有类别间统一执行。代价是可能抑制掉一些真实的重叠目标需要根据场景权衡。4.5 现象权重加载报KeyError: model.24.anchor_grid原因YOLOv5-5.0 和 6.0 的模型结构在检测头部分有差异5.0 的anchor_grid是注册为 buffer 的6.0 改成了普通属性。用 6.0 的代码加载 5.0 的权重就会报这个错。解决要么把代码切到 YOLOv5-5.0 的 tag要么手动修改模型定义把anchor_grid注册为 buffer。最省事的办法是直接用 5.0 版本的仓库不要混用版本。5. 从权重到部署Visdrone-YOLOv5在边缘设备上的量化与验证技巧拿到yolov5-5.0-visdrone.zip只是第一步真正落地往往要跑到 RK3568、树莓派这类边缘设备上。YOLOv5-5.0 的权重是 FP32 的直接部署推理速度很慢量化到 INT8 是常见做法。但 Visdrone 小目标对量化误差极其敏感量化后 mAP 掉 10 个点以上是常有的事。我一般会先用 ONNX 导出再用 RKNN 或 TensorRT 做量化。导出 ONNX 时注意--img-size要和推理时一致--batch-size 1并且加上--dynamic让 batch 维度动态。导出命令python export.py \ --weights weights/yolov5-5.0-visdrone.pt \ --img-size 1024 1024 \ --batch-size 1 \ --dynamic \ --simplify \ --opset 11--simplify会用 onnx-simplifier 去掉冗余节点--opset 11是 RKNN 工具链兼容性最好的版本。导出后得到一个.onnx文件用onnxruntime验证一下输出和 PyTorch 是否一致import onnxruntime as ort import numpy as np sess ort.InferenceSession(yolov5-5.0-visdrone.onnx) # 构造输入 dummy np.random.randn(1, 3, 1024, 1024).astype(np.float32) outputs sess.run(None, {sess.get_inputs()[0].name: dummy}) # 输出应该是三个尺度的特征图 for i, out in enumerate(outputs): print(f输出{i}形状: {out.shape})量化时校准集的选择很关键。不要用随机图片要从 Visdrone 训练集里抽 200~500 张有代表性的图片覆盖白天、夜晚、密集、稀疏各种场景。校准集越接近实际部署场景量化后的精度损失越小。RK3568 上我一般用rknn-toolkit2做量化配置里quantized_dtype选asymmetric_quantized-8quantized_algorithm选normal不要用mmse后者在小目标上容易过拟合校准集。量化后一定要做精度对比用同一批测试图片分别跑 PyTorch 权重和量化后的 RKNN 模型计算 mAP 差异。如果掉点超过 5 个检查校准集是否覆盖了所有类别或者尝试混合量化——把检测头的前几层保持 FP16只量化主干网络。这个技巧在 Visdrone 上通常能挽回 2~3 个点的 mAP。最后说一个我踩过的坑RK3568 的 NPU 对 1024×1024 输入的支持有限实际部署时往往要降到 640×640这时候小目标检测效果会明显下降。我的习惯是先在 640 上跑一版基线记录 mAP再逐步尝试 768、896找到精度和帧率的最佳平衡点。不要一上来就追求 1024边缘设备的算力瓶颈比想象中更早出现。希望帮到你。本文还有配套的精品资源点击获取