简介:面向YOLO系列目标检测模型训练与验证场景的瓶子数据集,专为需要快速获取带标签图像集的开发者准备,适合入门至进阶水平使用。该数据集包含701张标注图像,同时提供YOLO格式(txt)与VOC格式(xml)两种标签,已按训练集与验证集划分完毕,并附有数据集配置文件data.yaml,可直接适配YOLOv5、YOLOv7、YOLOv8、YOLOv9、YOLOv10、YOLO11等主流框架。压缩包内共2000个文件,含txt与xml标签各701个、JPG图像597个、配置文件1个,整体大小27.24MB,结构清楚便于调用,目前已有337人学习下载。其中txt标签遵循class、x_center、y_center、width、height的归一化坐标格式,class为类别索引,中心点与宽高均以图像比例表示,适合现代检测管线直接读取;xml标签则方便衔接传统VOC流程。资源同时包含标注格式说明和现成目录规划,省去自行整理与转换标签的繁琐工作,可让读者直接进入模型训练、验证与调参环节,也可用于论文实验、课程设计或实际项目预研。
1. 701张图像带标签的瓶子数据集:把YOLO系列算法跑通前,先搞懂怎么对齐
这份701张图像带标签的瓶子数据集是yolo算法系列的目标检测资源,拿到zip压缩包后,我第一次直接用YOLOv8训练,结果跑了两个epoch就报“No labels found”。排查了半天才发现,标签文件夹和图片文件夹的层级没对齐。所以拿到这份资源,第一件事不是急着写训练命令,而是先对齐三样东西:目录结构、标签格式、配置文件。
这份数据共701张瓶子图像,每张都有标签,标签同时提供yolo格式的txt和voc格式的xml,已经划分好训练集、验证集和测试集,并且自带一份data.yaml。它适用于yolov5、yolov7、yolov8、yolov9、yolov10、yolo11这些主流YOLO版本,能省掉手工标注和格式转换这两件最耗时的事。适合想快速跑通瓶子识别实验、想对比不同YOLO版本效果的从业者,也适合第一次用自定义数据集训练yolov8的入门者。
2. 双标签格式与数据划分:训练前先看懂两个底层设计
YOLO系列算法看起来是黑匣子,但它的输入输出其实非常简单:图片加txt标签。数据集的可用性,往往不在算法本身,而在于标签格式和数据划分是否规范。把这两件事搞明白,后面的训练命令就是机械操作。
2.1 yolo格式txt标签:归一化坐标为什么是系列通用语言
YOLO系列算法读标签的标准是txt文件,每行描述一个目标。打开这份瓶子数据集里的任意一个txt,内容长这样:
0 0.5123 0.4872 0.2216 0.4105一行五个数字的含义是固定的:<class> <x_center> <y_center> <width> <height>。class是类别索引,这份数据集只有瓶子一个类,所以所有行都以0开头;x_center和y_center是目标框中心点的x和y坐标;width和height是目标框的宽度和高度。这四项全部做了归一化,范围在0到1之间,表示相对于图像宽度和高度的比例值,而不是像素值。
为什么不用xmin、ymin、xmax、ymax这种直白的像素坐标?因为YOLO把图像划分成网格后,每个网格负责预测目标中心点相对于自身的偏移,归一化坐标天然匹配这个流程。反过来,不管图片是640×480还是1920×1080,只要标签是归一化的,训练时改imgsz参数就不需要重新标注。如果你拿到一份新标签想验证对错,反向换算公式是:x_center = (xmin + xmax) / 2 / image_width,width = (xmax - xmin) / image_width,y方向同理。
这里有一个很常见的误操作:手工算坐标时,有人把像素值除以固定数值,而不是除以图片真实宽度和高度。比如图片实际宽800,他却除以640,结果所有框都缩在左上角。这份数据集已经给了现成txt,不需要你再算,但如果你后续自己扩样本,务必按图片真实宽高做归一化。
2.2 voc格式xml标签:树形结构与像素级坐标的另一重视角
txt标签紧凑但人眼读起来费劲。数据集同时准备了voc格式的xml,和txt分别保存在两个文件夹里,这一点对调试非常有价值。xml保存的是像素级坐标,核心结构如下:
<annotation> <filename>img_058_194.jpg</filename> <size> <width>800</width> <height>600</height> </size> <object> <name>bottle</name> <bndbox> <xmin>120</xmin> <ymin>80</ymin> <xmax>310</xmax> <ymax>400</ymax> </bndbox> </object> </annotation>bndbox里的xmin、ymin、xmax、ymax都是像素坐标,和txt里的归一化坐标描述的是同一批目标。为什么一份数据集要做两种格式?从我实际使用的经验看,至少有三个场景必须用到xml:第一,很多老牌的标注工具和可视化工具不认txt,只认voc或coco结构;第二,做格式迁移时,从xml转coco是常规路径,有xml可以少走弯路;第三,对账的时候,txt和xml双格式互相印证,能快速发现哪个文件被动过手脚。
日常开发中我有个习惯:把xml当作人眼核验入口,把txt当作算法投喂入口。拿到这份数据集后,我建议随机挑几张图,用xml里的像素坐标在图上画框,肉眼确认瓶子是否框准。这个动作耗时很短,但能在训练之前把标签质量风险压到最低。
2.3 data.yaml:类别、路径和划分三件套
YOLO训练时读取的data.yaml结构非常简单,这份数据集自带的配置文件核心内容与下面模板一致:
train: images/train val: images/val test: images/test nc: 1 names: ['bottle']train、val、test三个键分别指向训练集、验证集、测试集的图片目录。YOLO会在运行时根据图片路径去找同名txt标签:图片在images/train,标签就在labels/train,路径前缀替换是训练前自动完成的。nc是类别数,本数据集只有瓶子,所以是1。names是类别名列表,第0个元素bottle对应txt里class索引0。
很多人在yaml上翻车,不是类别写错,而是路径写成了下载解压前的路径或者绝对路径里的某一个层级。yolov8和yolov5解析yaml时,相对路径都基于当前执行训练命令的工作目录。最稳妥的做法是:把整个数据集放在固定目录下,data.yaml里只写相对路径,然后cd到数据集根目录执行训练。
这里要说清楚“数据集已经划分好”的实际价值。很多公开数据集需要你自己写脚本按比例拆train、val、test,而这套数据在交付时已经把划分落实到了目录结构里,yaml直接读取即可,省掉了拆分这一步。对只想赶紧跑通训练流程的人来说,这是很实在的便利。
3. 把数据集跑进YOLOv8训练:目录结构、命令与参数
目录结构和标签都对上之后,直接进入实操。目标是尽快用这份瓶子数据集跑通一次yolov8训练,并完成验证和预测。整个过程分三步:检查目录结构、执行训练、评估指标。
3.1 目录结构:解压后先做一次完整检查
拿到压缩包先解压。命令行解压比图形界面更直观:
# 解压并统计文件类型,确认图片、标签、配置三类文件齐全 unzip yolo算法-瓶子数据集-701张图像带标签-瓶子.zip cd yolo算法-瓶子数据集-701张图像带标签-瓶子 find . -maxdepth 3 -type f | awk -F. '{print tolower($NF)}' | sort | uniq -c这段命令按扩展名统计解压后的全部文件。正常输出应该包含jpg、txt、xml、yaml四类,jpg的数量和txt的数量基本对得上。如果存在几张图片没有对应txt,YOLO训练时会静默跳过这些图片,不报错,但你的实际训练数据量会偷偷缩水。所以我建议任何训练之前先做一次文件对账。
一个清晰的数据集目录结构通常是:
bottle_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── voc_xml/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamlimages和labels是同一层级的兄弟目录,图片和txt标签各归各的。YOLO训练时会把images前缀替换成labels去索引标签文件。如果你把数据复制到公共数据集目录,只要保持这种层级关系不变就行。我实际操作时还有个习惯:把voc_xml文件夹挪出训练工作区。YOLO只认txt,xml放在旁边不影响逻辑,但某些目录扫描工具会把多余的xml当噪音,徒增干扰。
3.2 训练命令:不同显存下的参数选择
在数据集根目录执行下面的命令,即可开始训练:
# 从预训练权重开始微调,epochs和batch按显存调整 yolo detect train data=data.yaml model=yolov8n.pt epochs=200 imgsz=640 batch=16 device=0参数逐个拆开看。data=data.yaml指定配置文件;model=yolov8n.pt表示用官方预训练nano权重做起点,显存占用最小,适合701张这样的小规模数据集;epochs=200是训练轮数,小数据集建议跑200轮以上,因为每轮样本量少,模型需要更多轮次才收敛;imgsz=640把输入图统一缩放到640×640,是精度和速度比较均衡的选择;batch=16在8G显存上比较稳妥,显存小改成8或4。
如果显存紧张,imgsz改成416可以明显提速,检测精度会有小幅下降,但对瓶子这种形状规则的物体影响不大。如果验证集里瓶子尺度差异大,还是保持在640更稳。我个人在这种小数据集上的习惯是先用yolov8n快速跑一版,确认流程没问题,再换yolov8m或yolov8l做精度对比。前期迭代成本低,后期也不会在错误的基准上浪费算力。
训练期间要盯两个东西:loss曲线和每个epoch结束后的验证指标。从第2个epoch开始train损失应该稳步下降。如果多个epoch后loss纹丝不动,大概率是标签读取出了问题,而不是模型不行,这时候停掉训练去查数据更高效。
3.3 验证与测试:mAP50和mAP50-95到底在看什么
训练结束会得到best.pt,先用验证集测一遍:
# 用验证集评估,重点看mAP50和mAP50-95两个指标 yolo detect val data=data.yaml model=runs/detect/train/weights/best.pt输出里mAP50是IoU阈值0.5下的平均精度,mAP50-95是IoU从0.5到0.95每隔0.05取一次阈值的平均精度。前者反映目标被大致找到的能力,后者反映框定位的精细程度。对瓶子数据集来说,mAP50能到0.9以上说明检测效果已经很好;mAP50-95通常会比mAP50低一截,这是正常现象。
这里强调验证集和测试集的区别。训练过程中频繁使用的val集,本质上是模型每轮自检用的;test集在训练过程中不应参与任何决策,它存在的意义是让你在完全没见过的数据上做最终评估。如果你想用测试集单独验证,把data.yaml里的val临时指向test目录即可,或者直接用预测命令跑测试集图片,靠肉眼判断输出框的质量。
4. 避坑清单:瓶子数据集最常见的五个翻车现场
这章内容来自实际踩过的坑。每个问题都按“现象、原因、解决”的顺序写,训练时遇到类似情况可以直接对照排查。
4.1 现象:训练日志里检测到0个目标
训练启动后日志显示找到了701张图片,但每个epoch的验证指标全是0,看起来模型什么都没学。这种情况几乎可以断定是标签没被读进去。
原因常见有三个:images和labels目录不在同一层级,YOLO按图片路径替换前缀找标签,层级不对就找不到;txt文件是空的;文件名前缀不一致,比如图片叫img_058_194.jpg,标签却叫img_058_194_1.txt,前缀对不上。
解决方式是训练前写个三行脚本,对每张jpg检查同名txt是否存在,把缺失名单完整打出来,再随机打开几个txt确认不是空文件。这个检查动作应该成为每次训练的固定前置步骤,因为YOLO对缺失标签是静默跳过,不会在日志里显眼报警。
4.2 现象:标签坐标全是0或者大于1
用可视化脚本把标签画到原图上,发现框全部缩在左上角,或者框跑到图片外面,那标签数值一定出了问题。
原因大概率是txt里的坐标没有按真实宽高归一化。有人把像素坐标直接除以一个固定常数,比如1000,结果框位置全偏。另一种情况是转换脚本里把x_center错写成xmin,把width错写成xmax,数值错乱得更离谱。
解决方式是写脚本扫描所有txt,检查每行第二到第五列是否都在0到1区间,把越界文件单独挑出来修复。修复用第二章给的逆变换公式,按图片真实宽高重算归一化坐标。这份数据集交付时标签是完整的,不太可能出现这个问题,但如果你后续自己扩展数据集,这一步是保命操作。
4.3 现象:验证阶段mAP为0但训练loss正常
loss正常下降,训练看起来一切正常,但val的混淆矩阵和PR曲线全是空的,mAP输出0。这种分裂现象经常让人怀疑模型有问题,其实多数是数据划分的锅。
原因有三个方向:val目录里没有图片;val图片存在但val标签不存在;data.yaml里val路径写错指向空目录。还有一种少见但很坑的情况:训练集和验证集有大量重叠图片,模型在训练时见过验证图,指标虚高反向干扰判断。
解决方式:先打印val和test目录的文件数,再交叉对比train、val、test三个集合的图片名是否有重叠。确认不重叠后,再对val目录做一遍4.1里的标签对账。划分数据是交付时就定好的事,但复制移动目录时很容易搞乱,所以每换一次机器就跑一遍这个检查。
4.4 现象:loss突然变成NaN并持续无法恢复
训练跑了十几个epoch,loss在一轮之后突然变成nan,后面再也恢复不了。这种情况通常不是网络结构问题,而是数据里混入了坏样本。
原因多数是某张图片损坏,或者某个txt标签出现异常值,比如坐标是无穷大、行数多一个少一个。dataloader读到异常数据后梯度爆炸,整个训练直接崩掉。另一个常见原因是学习率过高,小数据集上尤其容易触发。
解决方式:先回退到loss变nan之前保存的checkpoint,再从数据层排查。写个脚本扫描所有txt,检查每行字段数量是否为5、数值是否有限、坐标是否在0到1区间,把坏样本删掉或修正。如果数据没问题,把初始学习率从0.01降到0.001再试。
4.5 现象:best.pt推理时漏检很多
用训练好的best.pt对测试集图片预测,一些瓶子没框出来,尤其是有遮挡、背景复杂的图。这不一定是你训练的锅,而是小样本数据集本身的特性。
原因是701张图拆成train、val、test后,实际训练集可能只有五六百张,瓶子外观、角度、光照多样性有限。模型见过的场景少,遇到没见过的拍摄角度自然漏检。要分清是标签问题还是模型没学会:打开漏检图对应的txt,看里面到底有没有这个框。有框但没检测到,说明模型没学到这个特征;没框说明标签漏标了。
解决方式:把epochs加到300,开启旋转和色彩增强参数,比如degrees=15、hsv_h=0.02;如果还漏,把漏检图和对应标签合并进训练集补一轮训练。这是小数据集迭代最实用的办法,比盲目调参有效得多。
5. 一套数据跑通YOLO全系列:版本差异与迁移实操
这套数据集最大的价值不只是yolov8能跑,而是yolov5、yolov7、yolov9、yolov10、yolo11都能直接使用。不同版本启动方式有差异,但它们共同需要的核心只有三个东西:txt标签、data.yaml、目录划分。
5.1 YOLOv5 vs YOLOv8:环境和启动命令差异
yolov5官方仓库的启动方式和yolov8完全不同。yolov5需要先clone仓库再安装依赖,然后通过python脚本启动:
# yolov5需要从仓库下载源码并安装依赖 git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt python train.py --data /path/to/data.yaml --weights yolov5s.pt --epochs 200 --batch-size 16yolov8则直接通过ultralytics包调用CLI:
pip install ultralytics yolo detect train data=data.yaml model=yolov8n.pt epochs=200 batch=16两者对data.yaml的字段解析基本一致,区别在于yolov5解析相对路径时基于你执行train.py时的当前目录。所以稳妥做法是:data.yaml里写绝对路径,或者cd到数据集根目录再启动。两个仓库都能稳定读到数据。
还有一个细小的坑:yolov5用--project指定实验输出目录,yolov8用project=。从yolov5切到yolov8时容易把--project写进命令,结果直接报参数解析错误。遇到这种报错先检查参数风格,别急着怀疑数据集。
5.2 YOLOv7、v9、v10、v11:各自的入口和兼容要点
yolov7官方仓库是独立维护的,训练入口是train.py,参数风格和yolov5接近:
python train.py --data data.yaml --weights yolov7.pt --epochs 200 --batch-size 16yolov9需要区分单模型和dual两种模式,通常用train_dual.py入口跑带辅助分支的结构。yolov10的核心变化是去掉了NMS后处理,推理时直接输出预测框,训练参数和yolov8一致,只是模型权重文件不同。yolo11延续了ultralytics风格,装同一个包后指定model=yolo11n.pt即可。
无论哪个版本,这701张图的txt标签都无需改动。唯一需要注意的还是data.yaml里的路径在每个版本下能否正确解析。我的经验是yolov5系和yolov7系相对路径拼写规则一致,yolov8及之后版本对path字段处理更宽松。如果做多版本对比,把训练结果的project名分开,比如project=yolov8_bottle、project=yolov11_bottle,避免多个版本写进同一个runs目录,不然清理和对比都会很痛苦。
5.3 txt转xml脚本:归一化坐标还原像素标注
虽然数据集已经双格式齐备,但如果你自己扩展瓶子样本,扩展工具很可能只输出一种格式。这里给一个稳定的txt转xml脚本:
import os from PIL import Image import xml.etree.ElementTree as ET from xml.dom import minidom def yolo_to_xml(image_path, txt_path, xml_path, class_names): img = Image.open(image_path) w, h = img.size root = ET.Element("annotation") filename = ET.SubElement(root, "filename") filename.text = os.path.basename(image_path) size = ET.SubElement(root, "size") ET.SubElement(size, "width").text = str(w) ET.SubElement(size, "height").text = str(h) with open(txt_path) as f: for line in f: parts = line.strip().split() if len(parts) < 5: continue cls, xc, yc, bw, bh = map(float, parts[:5]) # 归一化坐标乘回图片真实宽高,得到像素级边界框 xmin = (xc - bw / 2) * w ymin = (yc - bh / 2) * h xmax = (xc + bw / 2) * w ymax = (yc + bh / 2) * h obj = ET.SubElement(root, "object") ET.SubElement(obj, "name").text = class_names[int(cls)] bnd = ET.SubElement(obj, "bndbox") ET.SubElement(bnd, "xmin").text = str(int(round(xmin))) ET.SubElement(bnd, "ymin").text = str(int(round(ymin))) ET.SubElement(bnd, "xmax").text = str(int(round(xmax))) ET.SubElement(bnd, "ymax").text = str(int(round(ymax))) xml_bytes = ET.tostring(root, encoding="utf-8") pretty = minidom.parseString(xml_bytes).toprettyxml(indent=" ") with open(xml_path, "w", encoding="utf-8") as f: f.write(pretty) class_names = ["bottle"] yolo_to_xml("images/train/img_058_194.jpg", "labels/train/img_058_194.txt", "output/img_058_194.xml", class_names)这段脚本里有两个容易错的地方。第一,txt里的width和height是相对整张图片的比例,所以xmin = (xc - bw / 2) * w里的bw直接乘图片宽度,没有再额外换算。第二,class_names数组的下标必须和txt第一列的class索引对应,多类别时顺序必须和data.yaml里的names完全一致,否则转出来的xml类别会串。我通常在转换完成后随机抽5个xml,对照原图画框做一次人工确认,这个笨办法能拦下绝大多数转换bug。
6. 用最小化过拟合测试验证标签可信度:训练前的最后一道保险
正式训练之前,强烈建议先跑一次最小化过拟合测试。它的目的不是让模型学到好指标,而是验证数据和标签整条链路有没有问题。做法是从训练集抽20张图片和对应txt,单独建mini目录,把data.yaml指向mini目录,然后用yolov8n做短暂训练:
# 抽20张图到mini目录,快速验证标签管道是否通 mkdir -p mini/images/train mini/labels/train ls images/train | head -n 20 | while read f; do cp "images/train/$f" mini/images/train/ base="${f%.jpg}" cp "labels/train/${base}.txt" mini/labels/train/ donemini.yaml的内容只需把train和val都指向mini/images/train,nc保持1。然后执行:
yolo detect train data=mini.yaml model=yolov8n.pt epochs=50 imgsz=640 batch=8如果数据和标签没有问题,50个epoch内训练loss会有明显下降。20张图做过拟合非常容易,loss不降就说明标签里有脏数据,比如坐标错乱或者类别对不上。这一步跑通之后,再回到完整数据集正式训练,心里就有底了,后续再出问题可以集中在模型和参数层面排查,不用反复回头怀疑数据。
正式训练结束后,还有一个容易忽视的验证手段:把best.pt对测试集做预测并把结果图保存下来,逐张用肉眼检查:
yolo detect predict model=runs/detect/train/weights/best.pt source=images/test save=True保存下来的预测图里,漏检和误检一目了然。如果场景是工业瓶子检测,重点看重叠瓶子的分离情况;如果做的是视频抽帧识别,重点看模糊帧上的表现。这种肉眼检查每做一次,你对这套数据集和模型的真实边界就多一分理解。
我曾经在另一份交通标志数据集上吃过亏,标签里一个类别标反,导致mAP很高但实际识别全错,浪费了整整一周。从那以后我每次换新数据集,都强制走一遍“文件对账、最小过拟合、预测可视化”三步流程,这套习惯帮我在后续好几个项目里都避开了数据坑。希望这篇文章里的踩坑记录和操作步骤,也能帮你少走一段弯路。
本文还有配套的精品资源,点击获取