资讯动态

YOLOv5小分辨率交通指示牌数据集:从标注到训练避坑指南

发布时间:2026/10/22 2:55:46 来源:尧图企业网站定制
简介智能小车赛道自动驾驶场景下的交通指示牌目标检测数据集面向目标检测入门者及自动驾驶视觉识别学习者采用YOLOV5标准目录结构解压后无需处理即可直接训练和验证。图像为200×120分辨率的RGB图片涵盖左转、右转、红灯、绿灯、人行道等8个常见赛道路标类别。训练集包含901张图片及对应901个txt标注验证集包含225张图片及225个txt标注另附类别字典txt方便标签对照。压缩包共2000个文件以1127个txt标注及类别文件、872个jpg图像为主体另含1个可直接运行的py可视化脚本随机传入一张图片即可绘制边界框并保存到当前目录方便快速检查标注效果。资源包大小约10.31MB轻量易用目前已有151人学习下载。1. 直接拿来训200x120小分辨率下8类别交通指示牌数据集做智能小车赛道识别的人大概率都经历过这么一段采集了上千张图用标注工具一张张框完导出的格式五花八门再写脚本转成YOLO格式中间哪步坐标除错了边界框直接飞出画面。这份目标检测数据集用的是YOLOv5目录格式训练集901张、验证集225张全部带txt标签图像分辨率固定在200x120的RGB图内容是赛道上常见的交通指示牌共8个类别含左转、右转、红灯、绿灯、人行道。11MB的体积解压出来直接挂在YOLOv5的datasets目录下就能开训省掉了标注、清洗、格式转换这几步最耗时也最容易出错的环节。适合正在做智能小车毕设、准备参加赛道竞速或者需要快速验证检测方案的从业者。2. 先看清数据再动手目录结构、标签格式与类别字典怎么对上2.1 YOLOv5标准目录到底长什么样用过YOLOv5的人都知道它默认的目录组织是images和labels两个兄弟目录图片和同名txt一一对应。这份数据集按同样的套路排好了拿到后建议先整体看一遍结构确认没解压错层级。我习惯用tree命令快速扫一遍tree datasets -L 3正常情况你会看到类似下面的结构训练集在train下验证集在val下所有图片都在images里、所有标签都在labels里datasets ├── images │ ├── train │ │ ├── 0.jpg │ │ ├── 1.jpg │ │ ├── ... │ │ └── 1079.jpg │ └── val │ ├── 64.jpg │ ├── 75.jpg │ └── ... └── labels ├── train │ ├── 0.txt │ ├── 1.txt │ └── ... └── val └── ...需要确认的关键点有三处第一images和labels下的子目录名要完全一致train对train、val对val有一处拼写不一致训练时就会报找不到标签文件第二图片和txt的主文件名必须一一对应比如0.jpg对应0.txt这是YOLO系列找标签的唯一凭据第三数量要对得上训练集901对901、验证集225对225。第一遍检查最好加一条统计命令看有没有图没有标签、或者标签多于图片ls datasets/images/train | wc -l ls datasets/labels/train | wc -l两个数字不相等说明资源本身有缺失或解压异常。这类检查花不了两分钟但能避免后面训练时“明明有图却一直跳过”的尴尬场面。2.2 labels里的txt不是随便写的归一化坐标与类别索引YOLOv5的标签文件是纯文本每一行对应一个标注框格式固定为五个数字类别编号、归一化中心点x、归一化中心点y、归一化宽、归一化高。类别编号从0开始计数。打开其中一个txt你看到的应该是类似这样的内容2 0.4850 0.5110 0.1300 0.2100 0 0.8320 0.4700 0.1100 0.1800 5 0.2100 0.6400 0.1500 0.2000第一列是类别索引后面四个数是归一化后的坐标。所谓归一化是拿真实像素坐标除以图像宽高中心点x除以200、中心点y除以120、框宽除以200、框高除以120。因为图片尺寸只有200x120每个坐标都落在0到1之间。动手训练前我建议写一段小脚本把这五个列的数值范围算一遍确认没有越界import os label_dir datasets/labels/train for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname), r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(f异常行数: {fname} - {line}) continue cls, x, y, w, h map(float, parts) if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): print(f越界: {fname} - {line})这段脚本遍历所有训练标签把列数不对、坐标越界的行直接打印出来。类别编号在这里不需要验证大小范围因为下一步要和类别字典对齐。这段代码的作用是把文本数据的质量底线守住宁可训练前多跑几秒也不要训练到一半发现标签里混着脏数据。2.3 类别字典、data.yaml与标签索引三方对齐数据包里附带了一个类别字典txt文件里面按行写了8个类别的名称。这份字典的文本顺序就是标签txt里“第一列数字”的对照表。也就是说字典第1行对应编号0、第2行对应编号1依次类推。这里有一个非常容易踩的坑data.yaml里names列表的顺序必须和这个字典文件的顺序完全一致否则会出现“训练时模型学的是红灯推理时输出却是绿灯”的错乱。整理一份正确的data.yaml核心内容如下path: datasets # 数据集根目录相对于YOLOv5运行目录 train: images/train # 训练图片路径 val: images/val # 验证图片路径 nc: 8 # 类别总数 names: [左转, 右转, 红灯, 绿灯, 人行道] # 其余3个类别以实际classes.txt为准注意YOLOv5新版要求path和train、val是分开写的train和val是相对于path的相对路径。有老版本习惯把train写成完整绝对路径换到新版本后这种写法会被警告但不影响运行。关键在于names我上面只列了5个剩下3个要以你手里classes.txt的原文顺序原样补进去一个都不能换位置。验证对齐是否正确可以再走一遍统计脚本把每类目标的样本量列出来import os from collections import Counter counter Counter() label_dir datasets/labels/train for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname), r) as f: for line in f: cls int(line.strip().split()[0]) counter[cls] 1 for cls in sorted(counter.keys()): print(f类别 {cls}: {counter[cls]} 个标注框)运行后看每个编号的样本量再对照names逐一确认。样本量差别很大的类别比如红灯几百个、某一类只有几十个后面训练时要考虑是否做类别加权否则少数类很容易学不动。这一步是后面所有训练的前置条件值得认真走一遍。3. 可视化验证一行命令把边界框画回原图3.1 这套可视化脚本做了什么拿到数据集光看txt文件里的数字是看不出问题的最直接的手段是把框画回原图上肉眼检查。资源包里附带的可视化py文件干的就是这件事随机从数据集里取一张图片读取对应的txt标签用OpenCV把矩形框画上去同时把类别名称写到框上方最后保存到当前目录。脚本无需改参数、可直接运行这对不熟悉OpenCV绘制API的人来说确实方便。它的核心逻辑大致是下面这段我做了一份等价实现供参考import cv2 import os import random img_dir datasets/images/train label_dir datasets/labels/train fname random.choice(os.listdir(img_dir)) img_path os.path.join(img_dir, fname) label_path os.path.join(label_dir, fname.replace(.jpg, .txt)) img cv2.imread(img_path) height, width img.shape[:2] with open(label_path, r) as f: for line in f: parts line.strip().split() cls, xc, yc, w, h map(float, parts) x1 int((xc - w / 2) * width) y1 int((yc - h / 2) * height) x2 int((xc w / 2) * width) y2 int((yc h / 2) * height) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(int(cls)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) save_name visualize_ fname cv2.imwrite(save_name, img) print(f已保存: {save_name})代码逻辑不复杂随机选图读取同名txt把归一化坐标乘以实际宽高还原成像素坐标cv2.rectangle画框cv2.putText写类别编号。有个细节值得注意中心点坐标和宽高的换算要用xc - w/2和xc w/2减错一半位置框就会偏移。类别这里我选择直接显示编号如果想显示中文类别名需要配合中文字体文件OpenCV自带的putText不支持中文会显示成乱码这是初学时容易纠结的问题。3.2 自己扩展一版指定图片、过滤类别、批量输出单个随机图片只能看到一张效果想系统检查整个验证集我一般会扩一版脚本支持传图片路径、按类别过滤、批量输出到指定目录。下面这版脚本可以作为模板import cv2 import os import sys def draw_label(img_path, label_path, out_dir, filter_classNone): img cv2.imread(img_path) if img is None: print(f无法读取图片: {img_path}) return height, width img.shape[:2] with open(label_path, r) as f: for line in f: parts line.strip().split() cls, xc, yc, w, h map(float, parts) if filter_class is not None and int(cls) ! filter_class: continue x1 int((xc - w / 2) * width) y1 int((yc - h / 2) * height) x2 int((xc w / 2) * width) y2 int((yc h / 2) * height) color (0, 255, 0) if int(cls) 0 else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, str(int(cls)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1) out_name os.path.basename(img_path).replace(.jpg, _check.jpg) os.makedirs(out_dir, exist_okTrue) cv2.imwrite(os.path.join(out_dir, out_name), img) if __name__ __main__: img_dir sys.argv[1] if len(sys.argv) 1 else datasets/images/val label_dir sys.argv[2] if len(sys.argv) 2 else datasets/labels/val out_dir sys.argv[3] if len(sys.argv) 3 else check_output for fname in os.listdir(img_dir): if not fname.endswith(.jpg): continue img_path os.path.join(img_dir, fname) label_path os.path.join(label_dir, fname.replace(.jpg, .txt)) draw_label(img_path, label_path, out_dir) print(批量可视化完成)跑法是python draw_all.py datasets/images/val datasets/labels/val check_output。三个位置参数分别指定图片目录、标签目录和输出目录。批量跑完所有验证集样本后打开check_output目录一屏扫过去哪些框贴得歪、哪些类别标错、哪些图压根没框一目了然。3.3 用可视化结果反查标签质量可视化不只是看一眼热闹它是训练前唯一一次用肉眼审查全部数据的机会。集中检查三个点第一框和物体边缘是否贴合如果框明显大于或小于指示牌本身说明标注精度有问题第二类别是否匹配红灯边上标成绿灯这类错标训练时会直接教坏模型第三图片本身是否有模糊、过曝、旋转异常的情况这类问题不影响标签格式但会影响模型收敛。我习惯在批量可视化之后再做一次统计把每个文件里的标注框数量列出来重点看框数为0的图片import os label_dir datasets/labels/val for fname in sorted(os.listdir(label_dir)): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname), r) as f: count len([line for line in f if line.strip()]) if count 0: print(f空标签: {fname})空标签文件在YOLOv5训练时会被跳过如果这类样本太多模型会倾向把对应图片当成背景。数量少还好超过几十张就得考虑是否要把这些图片从训练集里剔掉。这一步把可视化脚本的应用场景从“看一张”扩展到了“审全量”属于开箱那一下最值得花的功夫。4. 训练配置把901张训练图在YOLOv5里跑通4.1 训练入口选对YOLOv5版本和预训练权重数据整理完毕后进入训练环节。YOLOv5官方源码仓库是最常用的训练入口train.py是主脚本。这里建议选一个稳定分支新版本对老数据集的兼容性通常没问题但个别版本改了默认增强策略训练结果会有差异。我一般会固定在一个已知稳定的版本上做实验不频繁追新原因后面避坑章节会讲。预训练权重是第一个要决策的点。常见做法是使用COCO预训练权重作为起点因为模型的前几层已经学会了基础特征在小数据集上收敛更快。但如果你处于离线环境或者下载超时预训练权重无法自动获取。这时有两个选择手动把权重文件放到weights/目录后重试或者直接放弃预训练、从零训练。对于11MB这种规模的小数据集从零训练完全可行901张图配合足够的epoch效果不比用预训练差太多只是收敛会慢一些。4.2 data.yaml与训练超参小分辨率场景怎么设训练前先把data.yaml准备好路径设置直接关系到能不能找到数据path: /你的绝对路径/datasets train: images/train val: images/val nc: 8 names: [左转, 右转, 红灯, 绿灯, 人行道, 类别六, 类别七, 类别八]这里的names列表必须与classes.txt顺序完全一致。因为这份数据集本身是YOLOv5目录格式只要path、train、val三处写对训练时就能自动匹配到对应标签。针对200x120小分辨率小目标的场景训练参数有四个值得专门调整。第一个是imgsz训练尺寸建议设在320而不是默认的640。因为原始图片只有200x120直接缩放到640会严重拉伸变形而且小目标被放大后细节失真模型学到的是扭曲特征。320在保持宽高比的前提下已经足够。第二个是batch根据显卡显存来6GB显存可以batch16起步显存小就降到8或4。第三个是epochs901张图不算多建议在150到300之间试先跑200看曲线。第四个是mosaic增强这个下面避坑章节会展开这里先提示小图加mosaic容易出现目标被裁掉一半的情况。4.3 训练命令与日志观察一切就绪训练命令长这样python train.py \ --data data.yaml \ --weights yolov5s.pt \ --imgsz 320 \ --batch 16 \ --epochs 200 \ --device 0参数含义逐个说--data指定数据集配置文件--weights指定预训练权重如果该文件不在本地YOLOv5会尝试联网下载离线环境就得手动准备或去掉这个参数--imgsz设为320和推理时的尺寸保持一致--batch是每批次图片数量显存吃紧就调小--epochs设200--device 0表示用第一张GPU只有CPU环境就改成--device cpu但训练速度会慢很多。训练启动后日志会持续打印每轮的结果核心指标是P精度、R召回率、mAP0.5和mAP0.5:0.95。在小数据集上前50轮P和R波动大是正常的重点看后50轮是否稳定。训练结束后runs/train/exp目录下会生成weights/best.pt和weights/last.pt后续推理和验证都用best.pt。5. 避坑小分辨率目标检测最容易翻车的四个地方5.1 现象类别全乱左转被识别成右转训练过程看起来一切正常loss在降mAP也不差但推理时发现左转箭头被识别成右转红灯绿灯互相混淆。这类问题最迷惑的地方在于它不是完全错乱而是有规律的错所有结果都偏移固定位置。原因data.yaml里names列表的顺序和标签txt里的类别索引没有对齐。标签txt里写0代表“左转”但data.yaml里第0个名字却是“右转”整个序列错位了一个位置。模型学的特征是对的只是名称对应错了于是输出结果全部平移。解决把classes.txt的内容逐行打印出来确认第1行是什么类别然后照抄进data.yaml的names列表。不要凭印象填不要用Excel打开txt后另存那可能改变编码。改完后重新走一遍2.3节的类别统计脚本确认编号和名称一一匹配再开训。5.2 现象训练中断提示找不到权重文件命令敲下去几秒后报错提示无法获取yolov5s.pt或者卡在类似下载界面的位置迟迟不动。常见于离线环境或者防火墙严格的实验室网络YOLOv5的自动下载逻辑被拦住了。原因--weights yolov5s.pt让train.py去本地找这个文件本地没有就尝试从官方仓库下载。网络不通或者下载地址被墙整个过程就卡住或直接报错。这和小数据集本身无关纯粹是环境问题。解决两种方案任选。第一在有网的环境下先把yolov5s.pt下载到本地放到YOLOv5源码的weights/目录下再执行训练第二把--weights参数去掉从零训练。对这份8类别小数据集从零训练是可行的只是前期收敛慢一些epoch数要增加到300。注意yolov5s.pt下到本地后不要改文件名训练脚本是按名字找的。5.3 现象loss一直在掉val曲线却飘忽不定训练日志里train loss稳步下降看起来很有希望但val集的mAP在零附近震荡或者干脆一路走平。跑完200轮best.pt的效果跟随机猜测差不多。原因最常见的是val路径指向了错误目录导致验证集实际上和训练集重叠模型在“背答案”而不是“学规律”。另一种常见情况是mosaic增强过度200x120的小图像经过拼接裁剪后目标被切掉大半标签也跟着失效模型学到了残缺特征。解决先检查data.yaml里的val路径是否指向images/val。再检查训练日志里的验证集图片数量YOLOv5会打印类似val: Scanning ... 225 images的信息如果数字不对说明路径有问题。最后处理增强问题小分辨率数据集建议在训练时关闭mosaic或者至少把mosaic的启用概率调低。在源码的数据增强配置里找到mosaic相关参数设成0或注释掉重新训练一轮对比val曲线。5.4 现象推理时检测框大面积偏移训练时mAP还挺好看部署到小车上实测摄像头的实时画面里指示牌明明在画面中央检测框却偏到一侧或者框的大小明显和指示牌不符。原因摄像头输入尺寸和训练尺寸不一致。训练用了--imgsz 320推理时却保持默认的640输入模型收到的画面比例完全变了特征位置自然也偏了。另一个常见来源是实车摄像头分辨率设置得过高采集的画面是1280x720甚至更大直接喂给模型前没有缩放处理。解决训练和推理统一尺寸。推理时显式指定--imgsz 320如果画面比例不一致用letterbox填充而不是直接拉伸。摄像头采集端保持200x120或同等宽高比的画面输入。记住一个原则训练时怎么预处理推理时就怎么预处理任何一边改了另一边必须跟上。6. 模型收敛之后验证指标、推理落地与导出注意点6.1 用val做一次可信的精度评估训练结束后用best.pt在验证集上跑一次正式评估拿到最终指标python val.py \ --data data.yaml \ --weights runs/train/exp/weights/best.pt \ --imgsz 320重点关注mAP0.5。在这份8类别小数据集上mAP0.5能达到0.9以上说明模型学得足够好如果只有0.7到0.8先不要急着部署回到训练侧做调整。mAP0.5:0.95在小目标场景下普遍偏低0.4到0.5都是正常水平不需要过度焦虑。class-wise的AP更有价值逐类看哪个类别在拖后腿通常样本量最少的类别AP最难看。6.2 推理参数置信度、IoU和输入尺寸推理阶段有两个阈值需要根据实测场景调--conf-thres是置信度阈值默认0.25赛道场景建议调到0.35到0.4减少把背景误判成指示牌的假正例--iou-thres是NMS的IoU阈值默认0.45如果检测框在同一个目标上重复出现适当调高到0.5到0.6。这几个参数的调整直接决定实车上的误检率值得反复实测。6.3 导出ONNX固件部署前的最后一步如果小车的推理端是端侧设备需要把PyTorch模型导出成ONNX格式方便后续转成端侧推理框架的格式python export.py \ --weights runs/train/exp/weights/best.pt \ --imgsz 320 \ --opset 12导出后确认输入尺寸是320opset用12或以上。端侧设备如果支持半精度推理导出时加上--half参数速度能提升一截前提是设备端支持FP16计算。导出完用onnxruntime加载测一遍输出再进固件集成。这一步卡住最常见的原因是opset版本过低导致算子不支持直接用12基本能绕开这类问题。我自己的习惯是每次拿到一份新数据集先把3.3节的遍历脚本跑一遍再开训练。那次帮某个竞赛队伍调模型上手就发现验证集里混了十几张没有标签的图模型把路牌背景当成了目标来学val曲线怎么都救不回来。从那以后数据集验证脚本永远是训练前的第一道工序强制走一遍才安心。这份8类别数据集整体标注质量不错但批次间难免有零星噪点把可视化脚本跑一遍再开训会省下好几轮试错的时间。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑