简介:面向目标检测开发者的烹饪工具数据集,收录2107张标注图像,覆盖盘子、叉、勺子、杯子、碗、刀六类日常厨具。标签同时提供YOLO格式(txt)与VOC格式(xml),并已按训练/验证集划分,附带data.yaml配置,可直接用于YOLOv5、v7、v8、v9、v10、v11等主流系列模型的训练与测试。压缩包共2000个文件,以xml和txt标签文件为主,其中txt采用class、中心坐标、宽高的归一化格式,便于不同框架间无缝切换,整体大小约167.73MB。目前已有85人学习下载,适合需要快速获得高质量厨具检测数据的算法工程师、科研人员及目标检测初学者,解压后无需额外整理标注,即可专注模型调优与效果验证。
1. 烹饪工具检测数据集:拿到2107张带标签图片后先做什么
做厨房场景的图像识别时,最卡人的不是模型选型,而是数据。自己标一批盘子和碗很容易,但要标到几千张、覆盖不同光照和角度,工作量直接劝退。这份以“yolo算法-烹饪工具检测数据集”命名的zip包,解压后是2107张已经标注好的图片,类别覆盖盘子、叉、勺子、杯子、碗、刀六类,标签是YOLO格式的txt文件,意味着拿到手可以直接喂给YOLO系列模型训练。适合正在做厨房机器人、智能家电、餐饮结算或餐具识别的开发者,解决“没数据”的起步问题。本文按我实际跑数据的顺序,把解压、检查、训练、调参和踩坑过程完整过一遍。
2. 把zip变成可训练的YOLO数据集:解压、格式核对与标签解析
2.1 解压与目录结构:别急着训练,先看清文件
这份数据集是zip压缩包,第一步当然是解压。我拿到手后习惯先看一下压缩包内容,而不是直接解压全员。因为之前遇到过压缩包内嵌套多层目录,或者某些文件是macOS的隐藏文件,直接解压会污染数据集目录。用unzip -l先列出内容,确认顶层结构,再解压到固定工作目录。
# 查看zip内容,确认内部目录层级 unzip -l yolo算法-烹饪工具检测数据集-2107张图像带标签-盘子-叉-勺子-杯子-碗-刀.zip | head -30 # 解压到dataset/目录 mkdir -p dataset/cooking unzip yolo算法-烹饪工具检测数据集-2107张图像带标签-盘子-叉-勺子-杯子-碗-刀.zip -d dataset/cooking第一条命令的head -30只是先看前30行,防止文件过多刷屏。第二条命令的-d指定解压目标,避免解压到当前目录造成混乱。解压后建议用tree或find统计文件数量和扩展名分布。
# 统计图片和标签数量 find dataset/cooking -type f -name "*.jpg" | wc -l find dataset/cooking -type f -name "*.txt" | wc -l一般这个数据集里jpg和txt应该各是2107份(或者txt多一份包含类别名字的文件),如果数量对不上,后面训练必然报错。实际见过的情况是,有些打包工具会额外生成Thumbs.db或者.DS_Store,这些文件不碍事,但会在训练时被误读。建议统一清理。
find dataset/cooking -name ".DS_Store" -delete find dataset/cooking -name "Thumbs.db" -delete2.2 标签格式逐行解析:YOLO的txt到底存了什么
解压后每张jpg旁边会有一个同名的txt文件,这就是YOLO训练要的标签。YOLO格式的txt是纯文本,每一行代表一个目标,格式为:class_id x_center y_center width height。注意这里的四个坐标值全部是归一化比例,范围0到1,计算方式是目标框的绝对像素坐标除以图片宽高。很多人第一次看txt以为坐标是0到640之间的整数,这是最常见的误解。
我拿其中一个txt文件来看:
# 随便找一个标签文件显示内容 cat dataset/cooking/images/plate_001.txt输出示例(假设):
0 0.523437 0.412109 0.182813 0.246094 3 0.701562 0.715625 0.129688 0.187500第一行的0表示类别编号,对应你训练时的类别顺序;后面的0.523437是框中心点的x比例,0.412109是y比例,0.182813是框宽比例,0.246094是框高比例。一个文件中有几行就代表图里有几个目标。类别编号从0开始,所以这六个类别依次是:盘子=0,叉=1,勺子=2,杯子=3,碗=4,刀=5。至于具体哪个编号对应哪个类别,要看压缩包自带的classes.txt或者数据集说明。如果压缩包没写,就用图片名和标签内容去反推,拿一张只有一个目标的图对照着看。
2.3 用脚本校验图片-标签配对
训练前必须确认:每张图片都有对应txt,每个txt里的类别编号在合法范围内,坐标值都在0到1之间。不能等到训练跑起来才排查。我一般会写一个快速校验脚本,把不合格的文件筛出来。
import os from pathlib import Path img_dir = Path("dataset/cooking/images") label_dir = Path("dataset/cooking/labels") allowed_classes = {0,1,2,3,4,5} problems = [] for img_path in img_dir.glob("*.jpg"): label_path = label_dir / (img_path.stem + ".txt") if not label_path.exists(): problems.append(f"缺标签: {img_path.name}") continue with open(label_path, "r", encoding="utf-8") as f: for line in f: parts = line.strip().split() if len(parts) != 5: problems.append(f"格式错误: {label_path.name}: {line.strip()}") continue cls, x, y, w, h = map(float, parts) if int(cls) not in allowed_classes: problems.append(f"类别越界: {label_path.name} -> class {cls}") if not (0 <= x <= 1 and 0 <= y <= 1 and 0 < w <= 1 and 0 < h <= 1): problems.append(f"坐标越界: {label_path.name}: {line.strip()}") if problems: for p in problems[:20]: print(p) print(f"共 {len(problems)} 个问题") else: print("全部图片标签配对正常")这个脚本做了三件事:检查标签文件是否存在、解析每行是否正好5个字段、验证类别编号和坐标范围。跑完如果输出“全部图片标签配对正常”就可以进行下一步。要注意的是,归一化坐标里x_center理论上可以是0或1(目标中心在边缘),但width和height必须大于0,等于0说明标注退化成了点,训练会出NaN。
3. 划分数据集并配置训练:从零跑通YOLOv8的最小流程
3.1 数据划分脚本:按比例切分train/val/test
数据集2107张不算大,直接全量训练会过拟合,而且评估没意义。常见做法是按8:1:1切分成训练、验证、测试三份目录。YOLO训练只需要train和val,test可留到最后手动验证。我习惯同时生成test,方便推理阶段用没见过的新图看效果。
import random from pathlib import Path import shutil random.seed(42) img_dir = Path("dataset/cooking/images") label_dir = Path("dataset/cooking/labels") out_root = Path("dataset/cooking_splits") for split in ["train", "val", "test"]: (out_root / "images" / split).mkdir(parents=True, exist_ok=True) (out_root / "labels" / split).mkdir(parents=True, exist_ok=True) all_imgs = sorted(img_dir.glob("*.jpg")) random.shuffle(all_imgs) n = len(all_imgs) train_imgs = all_imgs[:int(n*0.8)] val_imgs = all_imgs[int(n*0.8):int(n*0.9)] test_imgs = all_imgs[int(n*0.9):] for split, imgs in [("train", train_imgs), ("val", val_imgs), ("test", test_imgs)]: for img in imgs: label = label_dir / (img.stem + ".txt") shutil.copy(img, out_root / "images" / split / img.name) shutil.copy(label, out_root / "labels" / split / label.name) print(f"{split}: {len(imgs)} 张")这里用固定随机种子42,保证每次划分结果一致,方便复现。拷贝而不是移动,原数据集保留作备份,这也算是一份“后悔药”。如果内存和磁盘紧张,也可以改成shutil.move,但我个人建议保留原始数据,后面想改划分或者重新标注时还有退路。
3.2 写data.yaml:类别顺序错了全盘皆废
训练YOLO需要一个yaml文件,声明数据路径和类别名。很多人在这里出错:类别顺序和标签里的数字必须严格一致。如果标签里0对应盘子,yaml里第一个名字就必须是plate,不能因为单词长短换顺序。我见过有人把杯子写在前面,结果0成了杯子,模型训练出来全乱套。
# dataset/cooking_splits/data.yaml path: ../cooking_splits train: images/train val: images/val test: images/test nc: 6 names: 0: plate 1: fork 2: spoon 3: cup 4: bowl 5: knifepath这里建议写相对路径,相对于当前运行命令的目录。如果把整个目录移动了,相对路径容易失效,这时可以改成绝对路径。nc必须等于names里的条目数,多一个少一个都会在训练时报错。
3.3 训练命令与四个关键参数
现在用ultralytics的YOLOv8来训练。安装后直接运行命令:
yolo detect train \ data=dataset/cooking_splits/data.yaml \ model=yolov8s.pt \ imgsz=640 \ batch=16 \ epochs=100 \ project=runs/cooking \ name=yolov8s_baseline \ device=0这里model=yolov8s.pt表示从COCO预训练权重开始迁移学习,而不是从头初始化。对2107张这种小数据集,迁移学习能大幅降低训练难度。imgsz=640是输入分辨率,目标检测通用设置;如果图片本身接近正方形,640没问题,如果图片是长条形,也可以尝试800或者512。batch=16取决于显存,12GB显存跑16没太大压力,显存不够就降到8。epochs=100对小数据集偏保守,但配合早停一般会在四五十轮收敛。device=0用第一张GPU,没GPU就改device=cpu,但速度慢很多。
训练输出会显示每个epoch的box_loss、cls_loss、dfl_loss以及验证集的mAP50、mAP50-95。关注mAP50是否稳定上涨即可,如果验证集mAP50已经超过0.95还继续涨,大概率是过拟合,要留意后面会不会掉点。
4. 评估与推理:怎么确认模型真的认得出盘子和小刀
4.1 用val命令计算mAP与混淆矩阵
训练结束后,模型文件保存在runs/cooking/yolov8s_baseline/weights/best.pt。先用验证集评估,看整体指标:
yolo detect val \ data=dataset/cooking_splits/data.yaml \ model=runs/cooking/yolov8s_baseline/weights/best.pt \ project=runs/cooking \ name=val_best输出里会看到每类别的精确率、召回率、mAP50、mAP50-95。除了看平均值,一定要看每个类别的单类指标。因为我实际跑过的类似数据集里,“叉”和“刀”这种细长条目标经常被漏检,因为长宽比和盘子、碗差太多。如果发现某个类别mAP50明显低,比如小于0.8,就需要针对这个类别做专门处理,比如增加这类图片的复制粘贴增强,或者调整模型输入分辨率。
4.2 写推理脚本并做可视化
命令行predict可以快速输出结果图,但为了能自定义输出,我一般用Python脚本调模型。可以打印每个目标的类别、置信度和框位置,也可以存结果图。
from ultralytics import YOLO model = YOLO("runs/cooking/yolov8s_baseline/weights/best.pt") results = model.predict( source="dataset/cooking_splits/images/test", conf=0.25, iou=0.6, save=True, project="runs/cooking", name="predict_test" ) for res in results: names = res.names boxes = res.boxes print(f"图: {res.path}") for box in boxes: cls = int(box.cls) conf = float(box.conf) xyxy = box.xyxy.tolist() print(f" {names[cls]} 置信度 {conf:.2f} 框 {xyxy}")conf=0.25是置信度阈值,低于这个的不会显示。对小目标或者遮挡严重的目标,0.25可能漏检,可以调低到0.1试试;但如果调低后全是假阳性,就不值得。iou=0.6是NMS阈值,控制在框重叠时保留哪个。save=True会把标注结果图存下来,方便肉眼检查。
4.3 边界与失败案例:肉眼过不过关才算数
指标好不等于能直接用。我每次都会把预测结果图放大看,重点看两类错误:一是把勺子当成叉,因为两者都是长条,形状接近;二是多个物体重叠时只输出一个框。如果可视化里出现同一场景下盘子漏检、杯子误检,那就得回到数据层面解决。指标是“机器觉得好”,而业务上真正要的是“厨房里确实能用”。这个差距只能靠抽样看原图来弥补。
5. 避坑指南:训练烹饪检测模型最常见的5个坑
5.1 图片损坏与路径报错
现象:训练刚开始几分钟就报错,提示Image corrupt或broken JPEG,程序直接退出。
原因:数据集打包时个别图片文件不完整,或解压过程中出现0字节文件。YOLO加载图片时会解码失败。
解决:先用脚本扫描所有图片,尝试用PIL解码,无法解码的直接过滤掉,并从标签中同步删除。我就因为一张损坏的杯子图片让两小时训练白跑。
from PIL import Image from pathlib import Path img_dir = Path("dataset/cooking_splits/images/train") bad_imgs = [] for img in img_dir.glob("*.jpg"): try: with Image.open(img) as im: im.verify() except Exception: bad_imgs.append(img) if bad_imgs: print(f"发现 {len(bad_imgs)} 张损坏图片") for b in bad_imgs: print(b.name) b.unlink() b.with_suffix(".txt").unlink() else: print("全部图片解码正常")5.2 标签坐标越界
现象:训练时loss出现负数或NaN,某些batch后验证集mAP直接变成0。
原因:标签txt里的x_center、y_center或宽高换算后超出0-1范围,或者宽高写成绝对像素值。YOLO在计算正样本时索引越界,导致梯度爆炸。
解决:用前面章节的校验脚本提前筛出问题文件。如果只是少量坐标在0边界(比如x=0.9999),可以容忍;但如果出现负值或大于1,必须修正或删除。常见原因是标注工具导出时勾选了像素模式而不是归一化模式。
5.3 类别不平衡
现象:跑了100轮,整体mAP不错,但“杯子”这一类的召回率始终低于0.5。
原因:数据集中杯子样本明显少于盘子。2107张图里如果盘子占一半,杯子只有几十张,模型对杯子学不到足够特征。
解决:先按类别统计目标数量。若不平衡严重,优先做基于过采样的增强,把杯子图片重复放入训练集,或对杯子目标做随机复制粘贴。更稳妥的做法是估计类别权重,在YOLO的loss里给低样本类别更高的权重,但ultralytics没有直接暴露这个参数,我一般用增强解决。
5.4 类别ID与yaml顺序不一致
现象:训练正常,但推理时模型把“刀”标成“盘子”,而且置信度很高。
原因:数据集txt里的class id很可能不是按字母序排列的。比如压缩包里classes.txt写的顺序是“盘子 叉 勺子 杯子 碗 刀”,但你的yaml写成了“刀 碗 杯子 勺子 叉 盘子”,完全对不上。
解决:训练前一定打开样本txt,确认第0行到底对应什么。最可靠的方式是找一张只含单一目标的图,比如一张只有叉子的图片,看它的txt第一行是几,然后对照图片内容确定这个数字对应“叉子”。然后把这个对应关系写进yaml的names。
5.5 中文路径和空格
现象:训练时报错找不到图片,但路径明明存在;或者下载权重时失败。
原因:数据集路径中包含中文“烹饪工具检测数据集”,部分环境或库对Unicode路径支持不好;路径中带空格也会导致命令行解析错误。
解决:把整个数据集复制到纯英文路径下,例如D:/datasets/cooking_dataset,同时保证该路径下没有空格。zip文件名中的中文不影响解压后的内容,但解压目标目录最好改成英文。这一步能避免大量莫名其妙的读取异常。
6. 进阶:让模型在自家厨房场景更可用
6.1 先用小模型冒烟测试
拿到新数据集,我不会直接训练yolov8s,而是先跑一个yolov8n,只训练10个epoch,用batch=4。目的是验证数据流、标签解析、训练管线是否能走通,而不是追求精度。10分钟后如果看到正常输出loss下降,再切回正式配置。很多问题(比如标签错位)只有跑到几十轮后才暴露,小模型快速跑一遍能省大量时间。
6.2 数据增强与迁移学习
2107张图片规模不大,增强是必须的。ultralytics默认开启马赛克增强、随机翻转、色彩抖动等。可以按场景调整增强参数:厨房光照变化大,可以增加hsv_h和hsv_s;叉子有各种角度,可以把度旋转打开(但要注意90度旋转可能让长条形目标语义翻转)。更激进的做法是使用MixUp或复制粘贴增强,如果默认管线对“刀”这种细长目标漏检,复制粘贴增强能直接增加该类目标出现的密度。
同时,迁移学习不要只用一个模型。可以试yolov8m或yolov8l,但小数据集用大模型容易过拟合。我通常的做法是先用s跑通,拿到基线,如果mAP50已经高于0.95就不换大模型,直接在增强策略上做文章。更大的模型换来的提升往往不如多修几轮标签。
6.3 最终验证与上线注意
训练和评估跑通之后,拿一张完全没有出现在数据集里的真实厨房照片,看推理结果。如果模型在强逆光、密集摆放、刀具反光等场景下有明显问题,需要采集更多现场数据做增量训练。增量训练的做法是在原数据集基础上加入新图片,重新划分训练集,再用best.pt作为初始权重,继续训练20到30轮。注意新数据标签风格必须与旧数据一致,尤其是类别顺序和边界框粒度。
我的习惯是每次训练前把数据集版本、yaml内容、训练命令做一个备份,便于复现。遇到过在不同机器上同配置结果不一致的情况,后来发现是随机种子和cuDNN的差异导致,至少保证自己可控的版本统一。还有一次忘了关闭输出日志导致磁盘写满,训练中断,从那以后我都在训练命令里加上项目名并定期清理旧的runs目录。这个方向的核心不是模型多复杂,而是数据和流程是否扎实。希望帮到你。
本文还有配套的精品资源,点击获取