共享单车目标检测:YOLO格式数据集构建与训练实践指南
2026/9/15 0:13:52 网站建设 项目流程

简介:面向需要训练YOLO系列目标检测模型的开发者和研究人员,这是一份个人制作、格式规范的共享单车标注数据集。压缩包内共275个文件,包含136张jpg实景图片以及一一对应的136个txt标签文件,标签采用YOLO项目通用的归一化坐标格式,可直接被训练脚本读取;另附2个cache缓存文件和1个yaml配置文件,便于快速启动训练流程。压缩包整体约90.06MB,已有190人学习下载,作者强调标注准确、格式规范,可满足常见YOLO项目的直接使用需求。对于正在开展共享单车违停识别、城市骑行路径分析、交通流量统计或相关毕业设计项目的读者而言,这套数据可直接用于模型训练与效果验证,免去手动采集图像、清洗噪声样本和逐张标注的繁琐过程。尤其适合已有一定YOLO使用基础、希望快速获得有效训练样本以推进实验的中高级开发者。

1. 共享单车检测数据集构建:为什么YOLO格式可以直接喂训练

共享单车这类目标检测任务,和常规车辆检测有个很明显的差异:单车目标小、密集、相互遮挡,且大量出现在路边停放场景中。如果标注框偏移三五个像素,训练出来的模型在IOU阈值稍高一点的情况下,漏检和误检就同时上来了。很多人自采数据做成COCO或VOC格式,再写转换脚本转YOLO,中间一旦坐标归一化出错,整个训练白跑。

这个共享单车标注数据集直接以YOLO项目格式给出,包含train/val的cache文件、整理好的图像以及对应标签目录,不需要再做格式转换。摘要里强调“格式规范、标注准确”,实际使用中主要体现在两点:类别ID从0开始连续编号,标注框坐标归一化到0~1区间且未出现越界框。对想快速把YOLOv5/v8跑起来、验证检测流程,或者准备扩充自有数据集做预训练的人,这个包可以直接作为数据侧起点。下面从标签格式、目录结构、统计校验、训练配置和排错五个层面拆开讲。

2. 标签文件与train.cache:YOLO数据格式的规范与校验

2.1 目录结构与txt标签约定

YOLO系列项目的数据目录一般长这样,这套共享单车数据集的目录也遵循同样的约定:

dataset/ ├── images/ │ ├── train/ │ │ ├── IMG_7607@0.5x.jpg │ │ └── ... │ └── val/ │ └── ... ├── labels/ │ ├── train/ │ │ ├── IMG_7607@0.5x.txt │ │ └── ... │ └── val/ │ └── ... ├── train.cache └── val.cache

图像文件和标签文件保持同名,只是后缀不同。每个txt文件里每一行对应一个目标,格式为:

class_id x_center y_center width height

比如IMG_7607@0.5x.txt的一行内容可能是:

0 0.4832 0.5714 0.1246 0.2083

其中第一列是类别ID,共享单车若只检测一类就是0;后面四列是归一化坐标,分别表示中心点x、中心点y、框宽、框高,取值都在0到1之间。注意YOLO使用归一化坐标而不是像素坐标,因此同一张图无论原始分辨率多大,标签文件内容都一样,这也方便在训练时做resize。

# 快速查看标签文件内容 cat dataset/labels/train/IMG_7607@0.5x.txt
2.2 train.cache / val.cache 是什么

训练YOLO时会在第一次加载数据集后生成train.cacheval.cache文件。它们是序列化后的缓存,用于保存图像路径、图像尺寸、标签文件是否存在、目标数量等验证结果,避免每次启动训练都重新扫描一遍磁盘上的数据集。

# YOLOv5中cache文件的生成逻辑(简化说明) img_info = { "path": str(img_path), "shape": (img_h, img_w), "labels": labels_list, } # 之后用pickle写入 .cache 文件

缓存内容的核心是让数据加载器快速定位到每个batch的样本路径,同时跳过损坏图像和残缺标签。初次加载时如果数据集较大,扫描需要一点时间;有了cache后再次启动训练,加载速度会明显提升。

需要注意cache与路径绑定。如果你下载数据集后把目录移动到其他位置,或者把Windows路径改成Linux路径,旧cache就可能失效。YOLOv5/v8在校验时发现缓存路径不匹配会重新生成,不必手动删除,但如果遇到缓存相关报错,直接删除*.cache再跑一次是最稳妥的。

2.3 用Python脚本校验标签规范

拿到数据集后的第一件事,不是直接开训,而是先把标签整体扫描一遍,确认格式没坏。常见做法是写一个轻量校验脚本:

import os from pathlib import Path label_dir = Path("dataset/labels/train") errors = [] for txt_path in label_dir.glob("*.txt"): with open(txt_path, "r", encoding="utf-8") as f: lines = f.readlines() for idx, line in enumerate(lines): parts = line.strip().split() if len(parts) != 5: errors.append(f"{txt_path.name} line {idx+1}: 列数不对") continue cls_id, cx, cy, w, h = parts try: cx = float(cx) cy = float(cy) w = float(w) h = float(h) except ValueError: errors.append(f"{txt_path.name} line {idx+1}: 坐标非数字") continue # 检查归一化坐标是否在合理区间 if not (0.0 <= cx <= 1.0 and 0.0 <= cy <= 1.0): errors.append(f"{txt_path.name} line {idx+1}: 中心点越界") # 宽高为负属于无效框 if w <= 0 or h <= 0 or w > 1 or h > 1: errors.append(f"{txt_path.name} line {idx+1}: 宽高异常") if errors: print(f"发现 {len(errors)} 个问题") for e in errors[:20]: print(e) else: print("格式校验通过")

脚本逻辑很简单:先检查每行字段数是否为5,再把坐标转成浮点数,最后判断中心点在不在0到1区间、宽高是否为正且不超过1。cls_id这里没做上限检查,如果数据集里有多个类别,应该改成与data.yaml中的类别数量对比,超过nc-1的ID说明类标文件与标签文件不一致。

2.4 标注工具导出后的坐标兼容性

这类数据集通常从CVAT或LabelImg标注后导出。CVAT导出YOLO格式时,会自动完成归一化转换,坐标原点是图像左上角。若自己用脚本从COCO转YOLO,注意COCO的bbox[x, y, width, height],其中x, y是左上角坐标,需要换算成中心点:

x_center = x + w / 2 y_center = y + h / 2

换算后再除以图像宽度和高度,才是YOLO格式的归一化值。常见的坑是忘记除以尺寸直接把像素坐标当归一化值用,训练时所有框全部偏到图外。

3. 用统计手段审查数据集:类别分布、目标尺度与标注偏差

3.1 图像尺寸与@0.5x缩放的影响

数据集中图片命名带有@0.5x字样,说明这些图像被统一缩放到了原图的50%。这样做的好处是压缩文件体积,降低标注时的加载开销。但对于检测任务,缩放会改变目标在图像中的像素占比。原本20x40像素的共享单车框,缩放后变成10x20像素,接近小目标的边界(小目标一般指像素面积小于32x32)。如果训练时imgsz设成640,这些小目标会被进一步压缩,特征提取难度加大。

因此训练这类数据时,imgsz不要设成320,建议至少640,如果有条件用1280做一次对比实验。

# 统计图像尺寸分布 python -c " from PIL import Image from pathlib import Path for split in ['train', 'val']: img_dir = Path(f'dataset/images/{split}') sizes = [Image.open(p).size for p in img_dir.glob('*.jpg')] widths = [s[0] for s in sizes] heights = [s[1] for s in sizes] print(f'{split}: {len(sizes)}张,宽范围 {min(widths)}-{max(widths)},高范围 {min(heights)}-{max(heights)}') "

如果发现图像尺寸参差不齐,训练时模型会做letterbox填充,将不同长宽比的图统一缩放。填充区域没有像素信息,不会错标,但会浪费部分计算量。对共享单车这类横竖比例差异不大的场景,问题不大。

3.2 标注可视化验证

光看坐标数字不能判断标注准不准,最直观的方式是把标注框画回图像上:

import cv2 img_path = "dataset/images/train/IMG_7607@0.5x.jpg" label_path = "dataset/labels/train/IMG_7607@0.5x.txt" img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path, "r", encoding="utf-8") as f: for line in f: cls_id, cx, cy, bw, bh = map(float, line.strip().split()) x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(int(cls_id)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imshow("check", img) cv2.waitKey(0)

代码里将归一化坐标反算成像素坐标,再绘制矩形。注意cx - bw / 2可能因为浮点精度出现负数,绘制时cv2.rectangle会自动截断,但如果越界超过图像尺寸,有的版本会报错。建议加一句x1 = max(0, x1)之类的保护。

逐张看图能发现标注的常见问题:框比单车轮廓大很多、只框了车身没框车轮、把行人误标成共享单车等。这类问题用脚本不好查,只能人工抽检,至少每类目标看20个框,心里才有底。

3.3 目标尺度分布与宽高比统计

共享单车是长条形目标,宽高比通常在1:2到1:3之间。如果统计结果出现大量接近1:1的框,说明标注可能把车筐或座椅单独框了出来,或者把斜停的单车框成了正方形。写个小脚本统计:

import numpy as np from pathlib import Path ratios = [] areas = [] labels_dir = Path("dataset/labels/train") for txt_path in labels_dir.glob("*.txt"): with open(txt_path, "r", encoding="utf-8") as f: for line in f: _, _, _, w, h = map(float, line.strip().split()) ratios.append(w / h) areas.append(w * h) ratios = np.array(ratios) areas = np.array(areas) print(f"宽高比 中位数: {np.median(ratios):.3f}, 均值: {ratios.mean():.3f}") print(f"面积占比 中位数: {np.median(areas):.4f}, 均值: {areas.mean():.4f}") print(f"小目标(<0.01)占比: {(areas < 0.01).mean() * 100:.1f}%")

这个统计的意义在判断数据集的难度。面积占比越小,目标越小,训练越难收敛。如果小目标占比过高,训练时不建议开太强的Mosaic增强,因为Mosaic会把多个小目标拼在一起再缩放,进一步减小目标的尺寸。我在标注数据集中如果检测到小目标占比较高,一般会把mosaic关掉或者降到0.5,不然前几十个epoch的loss下降会很慢。

4. 接进YOLOv8训练:data.yaml配置、显存预估与训练命令

4.1 data.yaml 配置

这套数据集是YOLO项目格式,最省事的做法是直接写一个data.yaml,指向数据目录:

# dataset/data.yaml path: ./dataset # 数据集根目录,相对于运行训练命令的位置 train: images/train val: images/val nc: 1 # 类别数量,只有一个共享单车类 names: 0: shared_bike

nc是类别总数,names是类别名列表,索引必须从0开始。如果原数据集是从CVAT导出的类别比较多,这里只要改成实际类别数量和对应的名称即可。这里有一个容易踩的坑:如果标签文件中的类别ID超过nc - 1,训练时不会报错,但会直接跳过这些标注,导致实际参与训练的标签比文件里少。

4.2 训练命令与参数说明

使用YOLOv8训练:

yolo train data=dataset/data.yaml model=yolov8s.pt epochs=100 imgsz=640 batch=16 device=0

参数说明:

  • model=yolov8s.pt表示用yolov8s的预训练权重作为起点。共享单车检测相对简单,s模型比n模型精度高一些,比m模型占用显存少,作为起点比较合适。如果硬件允许,试试yolov8m.pt,会再高1~2个点mAP。
  • epochs=100是这个规模数据集的合理范围。数据量小的话,50轮左右就可能过拟合,100轮方便观察loss曲线在哪个位置开始回升。
  • imgsz=640是输入尺寸,前面说了数据里有0.5x缩放图,640比320更稳妥。
  • batch=16是批大小,取决显存。如果不确定,可以先用batch=-1让YOLO自动探测可用显存给出一个建议值。
  • device=0指定第一张GPU卡。用CPU训练的话,epochs建议减半,先跑通流程。

如果用的是YOLOv5:

python train.py --data dataset/data.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100

旧版的--img参数对应新版的imgsz,其余没有太大区别。YOLOv5和v8的标签格式完全兼容,这个数据集两个项目都能直接用。

4.3 显存预算与batch调优

不同batch大小直接影响显存占用,经验值如下:

模型imgsz=640, batch=16 显存占用备注
yolov8n~4GB适合低显存显卡
yolov8s~8GB推荐起点
yolov8m~12GB精度更高但训练慢

如果显存不够但还想用大batch,有两个方向:一是降低imgsz到480,先验证标签没问题,再回640正式训练;二是用梯度累积:

yolo train ... batch=8 device=0

配合optimizer='SGD',小batch多跑几步也能逼近大batch效果。共享单车检测场景中没有特别需要大batch的理由,除非你同时在训练几个类别且希望更快收敛。

4.4 训练结果怎么看

训练结束后,runs/detect/train/目录下会生成results.csv。我一般先看三组指标:

指标含义正常范围(这个场景)
metrics/precision(B)预测框中真正是单车的比例0.85以上
metrics/recall(B)真实单车中被检出的比例0.8以上
metrics/mAP50(B)在IOU阈值0.5下的平均精度0.9以上可认为标注质量好

如果precision高但recall低,说明模型预测偏保守,表现为漏检较多。这时可以调低conf阈值:

yolo predict model=runs/detect/train/weights/best.pt source=test.jpg conf=0.25

如果mAP50高但mAP50-95明显低,说明标注框和真实边界贴合得不够好——框偏大或偏小,导致IOU在0.75时掉分明显。这种问题靠调参解决不了,只能回标注阶段修框。

5. 训练前后的排错技巧:cache失效、越界框与数据增强的取舍

训练过程中最常遇到的几个问题,按影响排序,第一是cache失效或损坏,第二是标签越界导致的loss异常,第三是数据增强在小数据集上适得其反。

cache文件在数据集目录被移动、镜像文件被修改或访问权限变化后可能失效,报错信息一般是train.cache not found或者corrupted cache。最直接的解法是强制重新生成:

rm -f dataset/train.cache dataset/val.cache yolo train data=dataset/data.yaml model=yolov8s.pt epochs=100 imgsz=640 batch=16 device=0

删除后重新训练,YOLO会在数据加载阶段重新扫描图像和标签,重新生成cache,整个过程不会有数据损失。

标签越界的情况,在训练日志中的表现是首次验证时mAP极低甚至为0。原因是某个txt文件中存在width=1.2这样的异常值,归一化后的框超出了图像范围,模型预测时在特征图上无法对应到有效区域。前面2.3节的校验脚本已经覆盖了这种情况,还有一种边界case是w/h极小,比如0.0001,这类框在缩放后只有一个像素,几乎不可能训练出有效特征,也建议清理。清理时直接删除对应行即可,不用重标。

数据增强方面,共享单车数据集如果只有几百张图,建议关闭强增强:

yolo train ... mosaic=0.5 hsv_h=0.01 hsv_s=0.5 hsv_v=0.4

Mosaic把所有训练图拼接后缩放,小目标的尺寸会被进一步压缩;而在停车场景中,一辆车周围通常是密集排列的车群,拼接后反而加剧了遮挡程度。hsv增强保留一定色彩扰动即可,因为不同城市的共享单车颜色差异很大,但同一批采样中的颜色通常是均匀的。如果标注数据本身涵盖多种颜色,hsv增强可以再弱一点,避免模型过度依赖颜色特征。

最后提醒一个容易被忽略的点:如果你把数据集用于YOLOv8实例分割任务,仅靠这份目标检测标注是不够的,因为分割需要多边形轮廓而不是矩形框。建议先跑通检测流程,再做标注升级。

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

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

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

立即咨询