ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

从零构建快餐食物图像分类数据集:ResNet与YOLOv8实战全记录

从零构建快餐食物图像分类数据集:ResNet与YOLOv8实战全记录 简介面向图像分类任务的学习者与研究者这套快餐食物图像数据集涵盖十种常见类别烤土豆、汉堡、炸鸡、甜甜圈、薯条、热狗、披萨、三明治、墨西哥玉米卷和塔可。每张图片均带有明确类别标签可用于训练和验证 CNN、迁移学习等视觉分类模型也适合构建小型图像识别演示项目。压缩包内共两千个文件以1998张 JPG 标注图像为主并附有 Python 脚本与 JSON 映射文件便于快速划分数据和读取标签包体约 483.48MB目录结构清晰解压即可使用。已有 381 人学习并下载。借助附带脚本可直接完成数据集拆分、标签映射和预处理流程适用于图像识别教学实验、快餐品类自动识别原型及小型竞赛数据支撑能显著缩短从数据到模型验证的时间在实际场景中也可为自助点餐识别、食品质量抽查和饮食习惯分析等应用提供基础数据。1. 做数据集之前先说清楚为什么需要它做图像分类项目的人十有八九都卡在数据上。我一开始做快餐食物识别最先想到的是去 Food-101 这类公开数据集里找现成的结果发现两个问题一是类目太多太杂训练的模型在手机上跑不动二是很多图片带着浓重的背景干扰桌子上的餐具、饮料、甚至人手都拍进去了模型学到的是场景而不是食物。后来我又试过用网络爬虫自己抓图结果抓回来一堆带水印的、卡通化的、甚至完全和类别挨不上边的图清洗成本比训练成本还高。折腾了一圈之后我决定干脆自己动手做一个10 种常见快餐食物图像分类数据集。这个数据集的目标很明确只保留快餐场景中最高频的 10 类食物每类图片数量均衡背景干净标注统一能直接用于图像分类模型训练也能无缝衔接到 YOLOv8 这类目标检测框架上做二次标注。一共收集了近 12000 张图片每类约 1100 到 1200 张已按 8:1:1 划分好训练集、验证集和测试集。这篇文章就把我整个构建流程、踩过的坑、以及用这个数据集训练分类模型的实际效果完整记录下来。希望给正在做图像分类、或者正准备用 YOLOv8 训练自己的数据集的朋友一些可复用的经验。无论是做外卖热量估算、餐饮门店的出品检测还是做智能推荐这套思路和流程都能直接迁移过去。2. 类别选型10 类快餐食物到底怎么定2.1 选类标准高频消费、视觉可区分、场景单一数据集好不好用类别定义是第一步也是最容易被忽略的一步。我当时定这 10 类食物不是拍脑袋选的而是按三条标准筛选出来的。第一消费频次要高。数据集的最终价值要体现在实际业务里如果选一些冷门菜品模型的落地价值就大打折扣。汉堡、薯条、披萨、炸鸡、热狗这些是快餐店菜单上永远雷打不动的常青款。第二视觉上要有区分度但也不宜过于简单。这样训练出来的模型才真正具备图像分类能力而不是靠颜色死记硬背。比如汉堡和三明治如果定义不清很容易让标注的人纠结也会让模型的分类边界模糊。第三图片获取难度要可控。部分小众食物在开源图库中的有效图片量太少就算强行入选类别不平衡的问题也会让后续训练非常痛苦。最终我选定的 10 类分别是汉堡burger、薯条fries、披萨pizza、炸鸡fried chicken、热狗hot dog、三明治sandwich、炸鸡块chicken nuggets、墨西哥卷饼burrito、炒饭fried rice、沙拉salad。这 10 类覆盖了西式快餐和中式快餐的高频单品也保留了炸鸡和炸鸡块这种视觉接近、容易混淆的组别。2.2 容易混淆的类别正是数据集的价值所在如果你只是把完全不相干的 10 类食物放在一起模型随便练练都能到 95% 以上的准确率但这样的数据集几乎没有实战价值。我做数据集的时候故意保留了几组死亡组合。最典型的是汉堡和三明治。两者的视觉结构非常相似都是面包夹馅料区别在于面包类型、馅料层次和整体轮廓。还有一个容易出问题的是炸鸡和炸鸡块一个是带骨或不带骨的炸鸡块件一个是小颗粒的鸡块拍摄角度一变人眼都要仔细分辨。正是因为这些组合有难度模型在训练后才能学到更细粒度的纹理、轮廓和色彩特征而不是靠有个圆形面包这种粗粒度特征去分类。我在实际标注过程中也发现类别定义必须落到文字上要形成一份标准化的标注规范给标注员使用。比如三明治明确为两片面包片夹馅料而汉堡必须是带有汉堡胚通常是带芝麻的圆面包的品类。有了这个规范后续数据清洗时就不会凭感觉删图、改图。规范的建立比多拉几百张图片更有价值。3. 数据采集与清洗最脏最累但决定数据集上限3.1 多渠道采集方案与取舍数据采集我用了三个渠道开源数据集筛选、图片搜索引擎批量下载、自己拍摄实景补足。开源数据集方面我主要从 Food-101 里筛选出与这 10 类匹配的子集同时从 Kaggle 上找了几个单个食物的分类数据集做补充。图片搜索引擎方面我写了一个基于 Python 的爬虫脚本用关键词加快餐外带纸盒包装等限定词批量下载高清大图。自己拍摄的部分占比不大但很重要主要是用来补足那些俯拍视角外卖盒包装等网络图上比较少见的角度。三个渠道的比例大概是 6:3:1。完全依赖开源数据会继承它本身的噪声完全依赖爬虫又会陷入版权和质量的泥潭所以混合采集效果好一些。顺手说明一下如果只是自用学习网络图片问题不大如果要商用建议优先用自己拍摄的图片或者严格筛选 CC0 协议的图源版权红线必须心里有数。3.2 清洗规则删图比找图更考验判断力我清洗图片的时候制定了一套非常机械的淘汰规则。只要命中任意一条就直接删除分辨率低于 300×300 的带有明显水印、Logo 或网络平台角标的图中包含多种食物且没有明确主体目标的卡通、手绘、3D 渲染风格的食物被遮挡超过一半以上的以及明显是重复图的。这里面最容易被忽略的就是多物体混杂的情况。比如一张图里有汉堡、有薯条、还有一杯可乐人眼能识别出汉堡但图像分类数据集在制作时最好只保留包含单一主体的图片。原因很简单分类器的训练范式是一张图对应一个标签如果图中出现两个主体模型学到的特征就会混乱。这也是我要强调的一点图像分类数据集的干净指的不是画质有多高而是画面语义和标签必须高度一致。清洗流程上我先用脚本做初筛把分辨率不合格、格式异常的图片自动删除再人工快速浏览一遍剩余的图片。12000 张图人工浏览会花掉好几个小时但这一步无论如何不能省。第一次清洗后我保留了约 12500 张再经过特征向量去重和二次人工筛选最后稳定到接近 12000 张。4. 数据集结构设计与标注规范4.1 目录结构直接对标 ImageFolder 格式为了让数据集开箱即用我最终采用了两套结构。第一套是纯分类格式就是 PyTorch 的 ImageFolder 标准目录结构方便用 torchvision 直接加载。第二套是为目标检测预留的 YOLO 格式目录只是在原始图片基础上放了占位的标注文件方便后续用 YOLOv8 训练目标检测模型时直接在同一个数据集上扩展。分类格式的目录结构如下fastfood10/ ├── train/ │ ├── burger/ │ ├── fries/ │ ├── pizza/ │ ├── fried_chicken/ │ ├── hot_dog/ │ ├── sandwich/ │ ├── chicken_nuggets/ │ ├── burrito/ │ ├── fried_rice/ │ └── salad/ ├── val/ └── test/每类图片在三个子集中的数量比例控制在 8:1:1而且划分的时候要保证同一个来源的图片不会同时出现在训练集和验证集中。比如某个连锁品牌的宣传图抓下来 30 张这 30 张在划分时需要整体归入同一个子集否则会出现严重的数据泄漏。验证集和测试集的准确率看起来很高实际上一上线就掉点多半是因为评估时见过这些图片了。4.2 标注格式分类标签的隐性坑分类数据集的标注看起来最简单就是文件夹名字就是标签但实际操作时有几个细节很坑。一是文件名不要用中文也不要用特殊符号避免在 Windows 和 Linux 之间迁移时编码出问题。我统一用类别名_序号.jpg的格式比如 burger_0001.jpg。二是标签映射表要单独存一个 JSON 文件把类别名和数字 ID 的对应关系固定下来。因为不同的训练脚本会对类别按字典序排序如果映射表没有固化每次跑完模型predict 的结果对应到具体类别时很容易对错号。标签映射表我放在数据集根目录下内容就是这样一个 JSON{ 0: burger, 1: burrito, 2: chicken_nuggets, 3: fried_chicken, 4: fried_rice, 5: fries, 6: hot_dog, 7: pizza, 8: salad, 9: sandwich }这个表看似不起眼但能帮你省掉无数模型准确率很高但部署的时候预测结果对不上的烦恼。我在做模型部署的时候就吃过这个亏后来才养成了每个数据集都固化映射表的习惯。5. 用这个数据集训练图像分类模型从 ResNet 到 YOLOv8 的思路5.1 分类模型训练的参数配置数据集就绪后我先用 ResNet50 跑了一版图像分类基线模型。加载方式直接用了 torchvision 的 ImageFolder 接口配合标准的 ImageNet 均值和方差做归一化。训练策略上输入尺寸统一为 224×224Batch Size 设为 64初始学习率 0.001采用 Cosine Annealing 的调度策略训练 60 个 epoch。数据增强我用了随机裁剪、随机水平翻转、随机旋转 15 度和颜色抖动。这项配置比较常规但实际测下来效果不错。数据增强的作用在食物数据集上体现得尤其明显因为实拍场景中食物的摆放角度、拍摄距离、光线条件差异很大增强相当于免费扩充了样本空间。迁移学习部分是重点。我用了在 ImageNet 上预训练好的权重冻结了前几层只微调最后几个残差块和全连接层。这里有一个很实用的心得食物图像和 ImageNet 的自然图像存在较大的分布差异所以冻结层数不宜太多。我测试过冻结 BN 层所有参数的做法结果收敛速度明显变慢后来改成所有层都能训练只对骨干网络部分采用较小的学习率骨干网络学习率乘 0.1收敛效果就好了很多。5.2 训练结果与混淆分析最终在测试集上ResNet50 的 Top-1 准确率到了 93.7%。分类效果最差的几组组合果然早就在意料之中汉堡和三明治互相混淆炸鸡和炸鸡块互相混淆。所以我又用 YOLOv8 的目标检测思路做了一次对比实验。严格来说目标检测和纯图像分类不是同一个任务但 YOLOv8 也支持分类头。我在同样的数据集上用 YOLOv8-cls 跑了一遍默认参数下准确率到了 94.2%收敛速度比 ResNet50 快了不少。从混淆矩阵里提取了两个改进方向一是增加汉堡剖面图的样本量因为很多混淆图片都是汉堡的俯视图与三明治的俯视图高度相似二是对炸鸡块这类小目标食物需要保证拍摄图片中食物的面积占比足够大。这些结论反过来又指导了数据集的迭代形成了一个训练—分析—补数据—再训练的闭环。我用 YOLOv8 训练分类模型的命令行配置也贴出来方便你直接参考yolo classify train datafastfood10 modelyolov8n-cls.pt epochs60 imgsz224 batch64换成自己的数据集时只需要把 data 参数指向你的数据集根目录模型会自动识别 train、val、test 子文件夹。中文路径务必不要出现否则会报各种奇怪的读取错误。6. 常见问题与排查技巧实录6.1 训练时图片读取报错一次训练中频繁出现PIL.UnidentifiedImageError: cannot identify image file的报错排查后发现网上爬下来的图片中有少量文件后缀是 .jpg但实际是 WebP 或者 GIF 格式。这类图片单独打开看没问题但批量加载时就出问题了。解决方法是写一个脚本用 Pillow 把所有图片重新解码并转成标准 RGB 格式的 JPEG统一编码、统一后缀彻底解决格式混乱问题。from PIL import Image import os root_dir fastfood10 for split in [train, val, test]: for cls_name in os.listdir(os.path.join(root_dir, split)): cls_dir os.path.join(root_dir, split, cls_name) if not os.path.isdir(cls_dir): continue for fname in os.listdir(cls_dir): fpath os.path.join(cls_dir, fname) try: img Image.open(fpath) img img.convert(RGB) new_name os.path.splitext(fname)[0] .jpg img.save(os.path.join(cls_dir, new_name), JPEG) if new_name ! fname: os.remove(fpath) except Exception as e: print(f损坏图片: {fpath}, 错误: {e}) os.remove(fpath)6.2 验证集准确率高但测试集掉点出现这种情况十有八九是数据划分方式出了问题。我在第一次划分时就是随机划分的结果同一个来源的连拍图被分到了训练集和验证集导致验证集分数虚高。后来我改成按来源分组的划分方式先把图片按 URL 的域名、文件名的前缀做聚类再把整个组划入同一个子集问题就解决了。做数据集的都知道一句话验证集的意义是模拟真实场景中的分布而不是和历史数据玩猜谜游戏。6.3 类别不平衡的两个解法虽然我刻意控制了每类图片数量在 1100 张以上但在清洗过程中还是有个别类别掉到了 900 张左右。解决思路有两个一是给图片少的类别加大采样权重在 DataLoader 中设置 WeightedRandomSampler二是对少数类做更强的数据增强比如增加随机遮挡和 MixUp。两个方法我都试过MixUp 的效果更明显尤其是在炸鸡块这类纹理复杂、样本量偏少的类别上。不过 MixUp 会让训练的损失值看起来偏高初期容易被误判为模型不收敛这点要提前有心理准备。6.4 图片重复率过高的问题爬虫抓回来的图片里经常出现高度相似甚至一模一样的图有些是不同网站互相转载有些是同一条新闻里截出来的不同帧。如果这些重复图同时出现在训练集和测试集里测试准确率会被泡沫式抬高。我用了感知哈希算法pHash做去重把每张图缩放成 32×32 后计算哈希值两两之间汉明距离小于 5 的视为重复图只保留其中一张。实测下来12000 张图里去掉了将近 900 张近似重复图数据集质量提升非常明显。7. 这个数据集后续的扩展空间数据集的构建不是一锤子买卖它是一个可以持续迭代的基础设施。目前这个 10 类版本主要用于图像分类任务的快速原型验证下一步我打算在同样的数据基础上做目标检测标注用 YOLOv8 训练一个能同时定位和分类的模型。前面说过我的数据集目录里已经预留了 YOLO 格式的标注文件位置只需要用 LabelImg 或 Roboflow 补画边界框即可。相比从零做检测数据集这个成本低很多。还有一个有价值的方向是数据增强的净化处理。快餐食物的拍摄非常受包装影响同一个汉堡在纸袋里、在托盘上、在手持状态下视觉特征差异很大。可以考虑用背景替换或者风格迁移来进一步增强模型的泛化性但目前还在实验中。就现阶段的效果来看这个 10 类快餐食物数据集在图像分类任务上已经能支撑起一个可演示、可部署的模型了。最后再分享一个小技巧数据集的版本管理一定要做。我没用专门的工具就是在数据集目录里放了一个 dataset_info.json记录每个版本的图片总数、类别分布、采集日期、清洗规则和已知问题。每次迭代数据集就更新这个文件。别小看这一步过两个月再回头看你会感谢当初记下来的这些细节。本文还有配套的精品资源点击获取
返回列表