news 2026/10/7 6:06:04

273张食品数据集下的YOLO系列目标检测训练实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
273张食品数据集下的YOLO系列目标检测训练实战解析

简介:一套面向YOLO系列算法的食品目标检测数据集,聚焦鸡蛋、冰箱、米饭等常见物品,适合目标检测初学者学习模型训练流程,也适合开发者快速搭建食品识别应用。压缩包共547个文件,包含273张jpg图像、273个配套txt标签和1个yaml配置文件;标签按YOLO标准格式写入,每行依次为类别索引、归一化中心点x坐标、y坐标、框宽度和框高度,数值均在0~1之间,数据划分与类别设置已就绪,可在YOLOv5至YOLO11多个版本中直接调用,也可按要求转换为VOC格式。整体大小仅13.7MB,轻量、易下载,训练迭代速度快,能有效省去自行采集标注与分配数据集的步骤。目前已有56人学习下载。这套数据适合作为YOLO模型效果对比实验的数据基础,也可以作为食品识别、智慧零售等项目的迁移学习素材,帮助完成从数据准备到模型验证的完整目标检测任务。

1. 一份273张的食品数据集,yolo系列算法训练够不够用

先给结论:273张图、带YOLO格式标签的食品数据集,放在yolov5到yolo11全系列上都能直接开训,前提是你别指望一张图塞五六个密集小目标还能一次收敛。这份资源覆盖的场景很明确——鸡蛋、冰箱里的食材、米饭这类“餐厨食品目标检测”,标签是标准的<class> <x_center> <y_center> <width> <height>归一化坐标,已经划分好训练集、验证集和测试集,少了自己写split脚本这一步。适合两类人:一类是刚开始接触yolo系列目标检测,想拿一份干净、标签没毛病的现成数据集跑通yolov5或yolov8全流程;另一类是要做食品识别、餐饮视觉相关原型验证,手里没有标注数据,先拿这份资源起底做可行性测试。我的建议是:把它当“跑通流程的基准数据集”用,而不是当“生产级训练集”用。273张的体量决定了它更适合验证模型结构、调试训练参数、熟悉标签格式,真正上线前你大概率还得自己扩数据。接下来我会从数据集结构、标签校验、实际训练、增广策略到避坑记录,把这份资源从头到尾拆一遍。

2. 数据集结构与YOLO标签格式:先拆目录,再谈训练

2.1 目录结构与文件对应关系

解压后你会看到典型的YOLO数据集布局:images目录下分train、val、test三个子目录,labels目录下的子目录结构与之完全对应。文件名像img_0132_5.jpg和img_0132_5.txt这样一一配对,前缀相同、后缀不同。这种“同名不同扩展名”的映射是yolo系列训练器读取数据的基础,images/train/img_0132_5.jpg对应的标签文件必须位于labels/train/img_0132_5.txt,路径层级错一层都读不到。

我自己拿到这类资源的第一件事,不是急着配yaml文件,而是先写一段脚本统计每个集里图片和标签的数量是否一致。由于这份数据集的划分已经做好了,少了这个检查,训练时大概率会撞上Image not found或者Label not found的中断。

import os for split in ['train', 'val', 'test']: img_dir = f'images/{split}' lbl_dir = f'labels/{split}' imgs = {f.split('.')[0] for f in os.listdir(img_dir) if f.endswith('.jpg')} lbls = {f.split('.')[0] for f in os.listdir(lbl_dir) if f.endswith('.txt')} only_img = imgs - lbls only_lbl = lbls - imgs print(f'[{split}] images={len(imgs)} labels={len(lbls)}') if only_img: print(f' 缺标签的图片: {list(only_img)[:3]}') if only_lbl: print(f' 缺图片的标签: {list(only_lbl)[:3]}')

这段脚本用集合差集找出“有图无标签”和“有标签无图”的文件,逻辑很简单:先把文件名去掉扩展名做成集合,再求差集。任何一边查到非空集合,都说明这份资源的文件配对有问题,需要手动补齐或删除多余文件。正常情况是两边数量完全相等,only_img和only_lbl都为空集。

2.2 YOLO标签格式逐项拆解与代码校验

摘要里写得很清楚,标签格式是<class> <x_center> <y_center> <width> <height>,五个字段全部是空格分隔,坐标值归一化到0到1之间。<class>是类别索引,从0开始;<x_center>和<y_center>是目标框中心点相对于图像宽高的比例;<width>和<height>是目标框宽高相对于图像宽高的比例。注意这里存的是相对值,不是像素绝对值,所以同一张图缩放后标签依然有效。

光看格式定义没用,我习惯抽查几个标签文件,把归一化坐标换算回像素值看一眼,确认有没有越界或明显的标框错误。下面这段脚本会读取某一张图的宽高,把标签里的归一化中心点和宽高换算成像素坐标,再用OpenCV画出来,直接目检。

import cv2 img_path = 'images/train/img_0132_5.jpg' label_path = 'labels/train/img_0132_5.txt' img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path, 'r') as f: for line in f.readlines(): parts = line.strip().split() cls = int(parts[0]) x_center = float(parts[1]) * w y_center = float(parts[2]) * h box_w = float(parts[3]) * w box_h = float(parts[4]) * h x1 = int(x_center - box_w / 2) y1 = int(y_center - box_h / 2) x2 = int(x_center + box_w / 2) y2 = int(y_center + box_h / 2) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(cls), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imwrite('check_visual.jpg', img)

这段脚本把一行标签拆成五个字段,前两个坐标乘以图像宽高得到像素坐标,宽高同样换算后画矩形框。画出来的框如果明显偏离目标本体,说明标签本身有问题;如果框边界超出图像范围,说明归一化坐标计算时把宽高和中心点搞混了。这种目检对任何yolo数据集都是第一道质检工序,花两分钟能省下后面几小时的无效训练。

2.3 类别统计与数据平衡性检查

273张图听上去不多,但如果三个类别的样本分布极不均衡——比如鸡蛋出现200次而米饭只出现20次——训练出来的模型会产生严重的类别偏向。yolo系列训练时会根据每个batch里的目标数量计算损失,类别样本少的那一类损失贡献小,训练结果往往是对多数类过拟合、对少数类几乎不检测。

from collections import Counter cls_counter = Counter() for split in ['train', 'val', 'test']: lbl_dir = f'labels/{split}' for name in os.listdir(lbl_dir): with open(os.path.join(lbl_dir, name), 'r') as f: for line in f.readlines(): cls_id = int(line.strip().split()[0]) cls_counter[cls_id] += 1 print(cls_counter)

运行结果会告诉你每个类别ID在整份数据集里的目标框总数。假如类别分布悬殊,可以在data.yaml里调整weight参数或者针对少数类单独做增广。食品检测场景里,鸡蛋、冰箱、米饭这三类目标形态差异大,但鸡蛋这种小而圆的物体最容易因为标注框偏移一两像素导致AP值波动明显,类别统计是提前发现风险的手段。这套流程走完,数据集本身的状态你心里就有底了。

3. YOLOv8实战训练:配置、命令与损失函数观察

3.1 环境准备与data.yaml配置

训练之前先把data.yaml配好。yolo系列从v5到v11的配置文件格式基本一致,核心就是path、train、val、test四个路径和nc、names两个字段。这份资源已经划分好,直接把路径指到对应的三个目录即可。

path: ./food-items-gldps train: images/train val: images/val test: images/test nc: 3 names: 0: egg 1: fridge 2: rice

路径最好填绝对路径或相对path字段的路径,不要填train: ./food-items-gldps/images/train这种把完整路径写死的形式。yolo训练器在读取时会把path和train拼接成完整路径,写重复了会报AssertionError。nc的值要和标签文件里出现过的类别索引最大值+1保持一致,比如标签里只出现过0、1、2,nc就是3。names的排列顺序会决定模型预测输出的类别名称,随便起名可以,但顺序不能乱。

环境方面yolov5和yolov8的依赖差异不大,核心就是torch和torchvision。建议先装CPU版跑通流程,再用GPU版训练,避免一上来就撞CUDA版本不匹配的坑。同样一份数据集,在RTX 3060上yolov8n训练300轮大概50分钟,纯CPU可能要三四个小时,图省事可以先减少轮数验证流程。

3.2 训练命令与参数选择

拿yolov8为例,最短的训练命令一行就够:

yolo detect train data=data.yaml model=yolov8n.pt epochs=100 imgsz=640 batch=16 patience=20

model=yolov8n.pt这里有个习惯性操作:直接用官方预训练权重做迁移学习,而不是从零开始训练(yolov8n.yaml)。273张图的数据量从零训练几乎不可能收敛,迁移学习是唯一务实的选择。epochs=100对这份数据来说是合理区间,再多就很容易过拟合。imgsz=640是yolo系列的黄金分辨率,食品目标不算极小,640够用。patience=20控制早停,如果验证集mAP连续20轮不涨就自动终止,这个参数对防止过度训练很有用。

如果换成yolov5,命令会变成:

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

yolov5和yolov8在参数命名上有差异:v5用--img,v8用imgsz;v5的--weights对应v8的model。这份数据集的标签格式两者通用,不需要额外转换。yolov7的命令行参数风格又不同,走的是train.py加--data、--weights、--batch的方式。无论哪个版本,标签文件始终是那份五个字段的txt,这正是资源“适用yolo系列算法”这句话的实际含义。

3.3 训练过程中的损失函数观察

训练日志里有两组关键指标:box_loss、cls_loss、dfl_loss以及验证集的mAP50和mAP50-95。yolo系列最新版本的损失函数组合一般是分类损失(BCE)加上边界框回归损失(CIoU或DFL),三者加权重合成最终loss。训练时如果看到box_loss从2.x降到0.9左右、cls_loss从1.x降到0.3以下,说明模型在学习;如果cls_loss降到0.1以下但mAP还是拉胯,问题大概率在标签本身,不在损失函数。

yolo detect train data=data.yaml model=yolov8n.pt epochs=100 imgsz=640 batch=16 patience=20 project=runs name=food_exp

加project和name参数可以让每次实验的输出放到独立目录,避免后续实验覆盖掉之前的权重和曲线。训练结束后,模型权重保存在runs/food_exp/weights/best.pt和last.pt,前者是验证集指标最优的权重,后者是最后一轮的权重。我的习惯是优先用best.pt做推理测试,last.pt留作过拟合对比。验证集曲线里的mAP50-95对这张273张的数据集而言能在0.7以上已经算不错,食品检测场景mAP50更有参考价值,它只要求在50% IoU下检测到目标就算命中,更贴近实际应用的判定标准。

4. 把273张用出2730张的效果:增广策略与小数据集训练技巧

4.1 yolo内置增广与超参数设置

273张图要训练出能用的检测模型,必须靠数据增广撑场。yolo系列最核心的增广手段是mosaic,把四张图随机拼接成一张再参与训练,变相扩大了单次训练看到的样本组合和目标尺寸分布。yolov8的超参数里默认已经开启mosaic,但针对食品这类目标边缘清晰的场景,可以进一步把hsv_h、hsv_s、hsv_v调高,因为餐厨环境的灯光色温变化本来就大,鸡蛋在黄光下和白光下的颜色差异显著,augment的颜色抖动越强,模型对光照变化的鲁棒性越好。

# hyp.scratch.yaml 片段,只列调整项 mosaic: 1.0 hsv_h: 0.02 hsv_s: 0.8 hsv_v: 0.6 fliplr: 0.5 scale: 0.5

mosaic: 1.0代表每轮训练都有mosaic增广参与,但对小数据集来说mosaic有个副作用:如果参与拼接的图中目标特别少,拼出来的图大半区域是背景,模型学到的背景特征会增多。scale: 0.5控制随机缩放比例,这个值不宜过大,否则鸡蛋这种小目标被缩到十几个像素就彻底失去检测意义。我的经验是食品数据集里scale调到0.4到0.6之间最稳。

4.2 外部增广与类别平衡手段

内置增广做的是锦上添花,外部增广才是把小数据集盘活的真正手段。常见做法是用albumentations对原始图片做离线增广,生成扩增后的图片和标签,再并入原数据集。具体操作是把原图做水平翻转、随机亮度和对比度调整、轻微模糊,每张图生成两到三个变体,标签坐标随之同步变换。

import albumentations as A import cv2 import os transform = A.Compose([ A.HorizontalFlip(p=0.5), A.RandomBrightnessContrast(p=0.8), A.GaussNoise(p=0.2), ], bbox_params=A.BboxParams( format='yolo', label_fields=['class_labels'] )) out_img_dir = 'images/train_aug' out_lbl_dir = 'labels/train_aug' os.makedirs(out_img_dir, exist_ok=True) os.makedirs(out_lbl_dir, exist_ok=True) for img_name in os.listdir('images/train'): if not img_name.endswith('.jpg'): continue img_path = os.path.join('images/train', img_name) lbl_name = img_name.replace('.jpg', '.txt') lbl_path = os.path.join('labels/train', lbl_name) image = cv2.imread(img_path) with open(lbl_path, 'r') as f: lines = f.readlines() boxes = [] labels = [] for line in lines: parts = list(map(float, line.strip().split())) labels.append(int(parts[0])) boxes.append(parts[1:]) for i in range(2): augmented = transform(image=image, bboxes=boxes, class_labels=labels) aug_img = augmented['image'] aug_out = f'{img_name.split(".")[0]}_aug{i}.jpg' cv2.imwrite(os.path.join(out_img_dir, aug_out), aug_img) with open(os.path.join(out_lbl_dir, aug_out.replace('.jpg', '.txt')), 'w') as f: for bbox, label in zip(augmented['bboxes'], augmented['class_labels']): f.write(f'{label} {" ".join(map(str, bbox))}\n')

关键点在于bbox_params里的format='yolo'。albumentations要求框坐标必须和输入图片的格式声明一致,这里声明yolo格式,它内部会先转换成像素格式做变换,再转换回归一化坐标输出。增广过程中boxes里的坐标顺序是[x_center, y_center, width, height],和YOLO标签字段顺序完全一致,不需要调整。生成的新图放在train_aug对应目录后,再把images/train_aug和labels/train_aug并入data.yaml的train路径即可,训练时原图加增广图混合参与。

4.3 小数据集训练的轮数与早停策略

外部增广做完后,数据集可能从273张扩到600张上下。这时候epochs可以适当增加,但不要无脑拉满。我的经验是300轮以内配合早停足够,再多的轮数对这个小规模数据只会让模型把训练集里的噪声细节背下来,验证集指标反而下滑——典型的过拟合信号是train_loss持续下降而val_loss开始回升,mAP曲线同步掉头。看到这种情况直接取best.pt做模型即可。

数据增广的有效性可以用一个简单实验验证:同一份数据集分别关闭和开启增广训练,对比验证集mAP50的差距。如果差距小于0.05,说明原始数据已经足够丰富,增广只是锦上添花;如果差距在0.1以上,说明增广是这份资源训练成功的决定性因素。食物类目标的边缘和颜色特征比较鲜明,增广效果通常很显著。

5. 常见问题与避坑:换模型、转格式、小样本的五个坑

5.1 换yolov5时标签索引从1开始导致类别错乱

现象:用yolov5训练这份数据集时,模型推理输出所有目标的类别索引都比实际大1,鸡蛋被识别成冰箱,或者输出类别ID直接越界。

原因:Kaggle等平台导出的数据集经常沿用VOC标注习惯,类别索引从1开始;而YOLO格式的<class>必须从0开始。如果前一个使用者手动改了标签文件里的一些索引,或者数据集原始标注里0号类别是背景类没被清掉,就会出现这种错位。

解决:写脚本遍历labels下所有txt文件,把class字段整体减1或加1。关键是先看data.yaml里names定义的类别顺序,再对照标签文件里实际出现的类别ID最大值。如果标签里出现3而names只有3个类别,几乎可以确定是从1开始计数的残留问题。

5.2 直接用文本编辑器打开标签文件看到的是乱码或全0

现象:用记事本打开标签txt,发现内容不是预期的五个数字,而是一行乱码或者全是0。

原因:YOLO标签文件是纯文本,正常情况用任何编辑器打开都是可读的数字。如果出现乱码,可能是文件本身以UTF-8带BOM格式保存,BOM头干扰了训练器的读取;如果全是0,大概率是标注工具导出时把归一化坐标写成了整数0,真正的坐标值丢失了。

解决:检查文件编码,用sed -i 's/^\xEF\xBB\xBF//'去掉BOM头,或者在Python里统一按utf-8-sig编码读入再重新写回。全0的文件直接删除并在训练前重新标注,不要试图修复,因为原始坐标信息已经不存在了。

5.3 273张小数据集直接训练300轮mAP反而下降

现象:损失函数一路下降,训练集mAP接近1,但验证集mAP在100轮后不升反降,推理结果出现大量漏检。

原因:这是典型的过拟合。273张图的信息量撑不起300甚至500轮高容量模型的训练需求,模型到后期在背诵训练集图像的背景纹理和目标摆放位置,而不是学习通用的“鸡蛋特征”。尤其冰箱这类背景占比大的场景,模型很容易把特定角度、特定光线的冰箱局部当作特征记住。

解决:把epochs控制在100左右,开启patience=20提前终止,同时用4.2节的外部增广扩充数据量。还有一个实操技巧:如果mAP下降来得特别早(比如30轮内),先检查是不是学习率衰减策略太激进,把lr0从默认0.01调低到0.005重训一轮对比。

5.4 训练时报错找不到类别ID对应的名称

现象:data.yaml里nc设置为3,但训练日志在读取某个标签时抛出class index out of range的错误。

原因:标签文件里存在大于nc-1的类别ID。这份资源里如果出现某个class字段等于3,而配置的nc=3,合法索引只有0、1、2,3就超界了。常见原因是数据集混入了其他来源的标签文件,或者原始标注里把某类标成了不存在的ID。

解决:跑一遍2.3节的类别统计脚本,把标签里出现的所有类别ID列出来,找出超界的那几个文件,手动改到正确类别。检出超界文件本身就能说明数据集里混入了不属于这份资源的标签,稳妥起见直接删除该文件并重新标注。

5.5 验证集样本太少,一个batch全是一个类别的图

现象:验证集指标忽高忽低,同一份权重在两次评估间的mAP波动超过0.1。

原因:原始划分的验证集可能只有30到40张图,分布不均,某个类别在某些验证batch里完全没出现,导致mAP计算时该类别AP为0,拉低整体指标。食品数据集类别少,这个问题更明显。

解决:训练时把val的batch设成1,让每张验证图单独参与评估,或者干脆把测试集并进验证集用。用yolov8可以直接在训练命令里加batch=1配合val评估,虽然会慢一些但指标更稳定。如果验证集确实太小,另一个办法是重新划分训练验证集,按类别分布做分层采样保证每类在验证集里至少有5到8个目标实例。

6. 从训练到落地的最后一公里:混淆矩阵、单张推理与模型导出

训练完不等于交付完。我拿到一份新训练好的食品检测权重,第一件事永远是打开训练输出目录里的confusion_matrix.png。别急着看mAP数字,混淆矩阵能告诉你模型真正分不清什么。食品场景里最容易出问题的往往是鸡蛋和米饭的误检——鸡蛋在特定光照下表面反光,颜色接近米饭的米白色,如果混淆矩阵里这两个类别的交叉格子数值偏高,说明特征区分度不够,需要回到增广阶段给这两个类别单独加对比度和饱和度扰动。

from ultralytics import YOLO model = YOLO('runs/food_exp/weights/best.pt') results = model.predict(source='images/test/img_0812_75.jpg', conf=0.25, save=True)

conf=0.25是一个经验值。yolo系列的置信度阈值默认是0.25,但食品检测这种误检代价低的场景可以调到0.2,把召回率提上来;如果部署到工业质检场景则要调到0.4以上,宁可漏检不能错检。save=True会把带框的结果图存到runs/detect/predict目录,直接肉眼检查检测框和标签的重合程度。我一般会在测试集里挑一张目标密集的图片和一个低对比度场景各跑一次推理,前者看漏检,后者看过检。

模型导出到ONNX是整个流程最容易翻车的环节,但也是部署到边缘设备的必经之路:

yolo export model=runs/food_exp/weights/best.pt format=onnx opset=12 imgsz=640

opset=12是为了兼容老设备。如果你用的是yolo11或yolov10的新权重,部分算子可能要求opset更高,但食品检测场景用不到那些新特性,opset=12能覆盖大多数边缘推理框架。导出完成后顺手跑一遍onnxruntime推理验证导出的图和PyTorch原模型输出是否一致,差距在0.01以内就说明导出成功。从那以后我每次做完小样本训练,都强制走一遍“混淆矩阵→单张推理→ONNX导出”的三步流程,不做完不交付。

这份273张的食品数据集能帮你跑通yolo全流程,但真正的检测效果还得看你在数据增广和阈值调参上下的功夫。希望这份拆解能让你少走几步弯路,早日跑出自己满意的模型。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 6:04:59

单卡V100 16G跑通27B大模型:量化与KV cache优化全解析

说实话&#xff0c;刚拿到这个任务时&#xff0c;我的第一反应和大多数人一样&#xff1a;魔幻。V100 16G&#xff0c;27B 参数&#xff0c;256K 上下文&#xff0c;这三个词放在一起&#xff0c;稍微懂点大模型推理的人都会觉得“绝对不可能”。但现实是&#xff0c;我确实在一…

作者头像 李华
网站建设 2026/10/7 6:04:51

Java+Swing+MySQL教务管理系统课设源码:数据库、界面与JDBC实操解析

简介&#xff1a;这份JavaSwingMySQL实现的学校教务管理系统源码&#xff0c;面向Java初学者与需要完成期末大作业、课程设计的高校学生&#xff0c;涵盖学生信息管理、课程安排、成绩录入等典型教务功能&#xff0c;项目难度适中&#xff0c;本地编译可运行&#xff0c;评审分…

作者头像 李华
网站建设 2026/10/7 6:04:50

常见电容类型与选型实战:从原理、参数到故障排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/7 6:04:48

水泥泵车目标检测VOC数据集构建与工程落地指南

简介&#xff1a;本资源是一套专为工程车辆目标检测任务构建的Pascal VOC格式数据集&#xff0c;聚焦水泥泵车&#xff08;shuinibengche&#xff09;单类别识别&#xff0c;适用于计算机视觉初学者、AI算法工程师及智能交通领域研究者开展模型训练与验证。数据集共1209个文件&…

作者头像 李华
网站建设 2026/10/7 6:04:16

MAIC多智能体课堂:从单模型困境到AI协同教学实践

1. 从“一个老师讲、几十个学生听”到“一群AI各司其职”&#xff1a;MAIC到底在解决什么第一次看到“MAIC多智能体课堂”这个说法&#xff0c;很多人会下意识觉得又是一个把AI塞进PPT里的概念包装。但我实际拆下来发现&#xff0c;它想动的是课堂里最根深蒂固的一件事&#xf…

作者头像 李华
网站建设 2026/10/7 6:03:56

多引擎同步优化:构建可落地的AI流量运营操作系统

1. 这不是“AI工具教学”&#xff0c;而是一套可落地的流量运营操作系统你刷到过这样的标题吗&#xff1f;“3分钟学会用ChatGPT做小红书爆款”、“用AI一天生成100条抖音脚本”——这类内容我看过不下两百篇&#xff0c;点开后全是界面截图模糊指令结果截图三件套。真正做流量…

作者头像 李华