
简介面向YOLO系列目标检测算法的烟盒图像数据集收集了1934张已标注图片并完成训练集与验证集划分携带data.yaml配置文件可直接在YOLOv5、YOLOv8、YOLOv9、YOLOv7、YOLOv10、YOLO11等主流版本中调用。压缩包共2000个文件整体大小约192.79MB其中包含1545个XML文件和455个TXT文件分别对应VOC与YOLO两种标签格式二者存放在独立文件夹内方便按项目需求选取。TXT标签采用类别索引加中心点坐标和宽高的归一化方式记录所有坐标均映射到0到1区间贴合大多数YOLO训练脚本的直接读取要求例如类别索引从0开始中心点与宽高均为相对图像尺寸的比例值训练时无需额外转换。XML标签则保留Pascal VOC结构适用于习惯VOC式标注的流程。该数据集已具备开箱即用的特点适合需要快速搭建烟盒检测原型的算法工程师、研究人员及相关专业学生使用。目前已有176人学习或下载可有效减少数据采集与标注耗时将精力集中在模型调参与效果优化上。1. 拿到1934张带标签的烟盒图像先别急着开箱做目标检测的人大多有个执念数据集越大越好。但一套单类烟盒检测任务1934张带标签的图其实已经踩在了“够用”的及格线上。真正决定模型能不能落地的不是这1934张图的绝对数量而是这批标签的标注质量、图像分辨率的分布以及训练集和验证集有没有被混进同源图片。我见过有人拿了几万张公开数据集训练后 mAP 卡在 0.7 上不去也见过用一千多张精心清洗过的工业图像把准确率干到 0.95 以上的案例。这套 yolo 算法的烟盒数据集zip 解压后是一套标准的 YOLO 标签格式目标适合无人货柜、门店禁烟区域监测这类需要识别烟盒的视觉场景适用的用户是那些想用 YOLO 做单类目标检测、又不想从零开始打标的人。拿到压缩包后第一个动作不是解压而是先确认这 1934 张图里到底有没有坑。2. 拆开这个烟盒数据集的 zip目录结构、标签五元组与对齐校验2.1 先看清 JPEGImages 和 labels 的目录结构解压后第一件事是用 tree 命令把目录展开确认图像和标签是不是一一对应。常见做法是压缩包内部按 images 和 labels 两个顶层目录分开存放图像文件统一是 jpg 或 png标签文件是纯文本的 txt文件名前缀和对应图像完全相同。这套结构直接决定了后面训练脚本怎么写数据加载路径也决定了你用 labelimg 补标时保存到哪个目录。用下面这条命令先看整体结构unzip yolo算法-烟盒数据集-1934张图像带标签.zip -d cigarette_dataset cd cigarette_dataset find . -maxdepth 2 -type d | sort find . -maxdepth 2 -type f | wc -l逻辑说明unzip 的作用是把压缩包解压到 cigarette_dataset 目录-d 参数指定解压目标路径find 命令配合 -maxdepth 2 只列出两层目录避免图像文件刷屏。第二步的 wc -l 统计文件总数正常情况下应该是图像数加标签数再加目录本身占用的少量文件数如果总数偏差明显先怀疑压缩包是否传完整。参数说明-maxdepth 的数值根据实际目录层级调整如果压缩包内部还包了一层文件夹就改成 3。统计文件数时不要用 ls -l 直接看因为子目录很多时输出会很长且容易漏算。2.2 YOLO 标签五元组class_id、cx、cy、w、h 到底怎么读YOLO 标签的每一行固定是五个数字用空格分隔类别编号、目标中心点的 x 坐标、中心点的 y 坐标、目标宽度、目标高度。后四个值全部是相对于图像宽高的归一化比例取值范围在 0 到 1 之间。比如一行标签写着0 0.512 0.438 0.206 0.173表示该目标类别是 0中心点位于图像横向 51.2%、纵向 43.8% 的位置宽度占图像宽度的 20.6%高度占图像高度的 17.3%。这个格式和 labelimg 自动保存的 YOLO 格式完全一致。写个脚本把某个标签文件解析成人能看懂的像素坐标便于抽查import os def yolo_to_pixel(label_path, img_width, img_height): with open(label_path, r, encodingutf-8) as f: lines f.readlines() for line in lines: parts line.strip().split() if len(parts) ! 5: print(f非法行: {line}) continue class_id, cx, cy, w, h map(float, parts) x1 int((cx - w / 2) * img_width) y1 int((cy - h / 2) * img_height) x2 int((cx w / 2) * img_width) y2 int((cy h / 2) * img_height) print(f类别{class_id}: 左上({x1},{y1}) 右下({x2},{y2})) # 示例调用需根据实际图片尺寸填写 yolo_to_pixel(labels/000001.txt, 640, 640)逻辑说明这个脚本把归一化的 YOLO 坐标还原成图像像素坐标方便你用画图工具打开原图核对标注框是否贴合烟盒边缘。它先按空格拆分每行再校验字段个数最后做中心点坐标到左上右下角点的换算。参数说明img_width 和 img_height 必须和对应图片的实际尺寸一致否则还原出来的坐标是偏移的。如果你的图像不是正方形注意别把宽高写反这是人工核对标注时最常见的低级错误。2.3 图像和标签对不上写脚本自动找出孤儿文件数据集里一旦出现只有图像没有标签、或者只有标签没有图像的情况训练时要么报错、要么模型把缺失标签的图像当成背景样本直接影响收敛效果。手工检查 1934 个文件名不现实用脚本自动比对是唯一可靠的办法。import os from pathlib import Path image_dir Path(images) label_dir Path(labels) image_stems {p.stem for p in image_dir.glob(*.jpg)} image_stems.update(p.stem for p in image_dir.glob(*.png)) label_stems {p.stem for p in label_dir.glob(*.txt)} only_image image_stems - label_stems only_label label_stems - image_stems print(f缺少标签的图像数: {len(only_image)}) for name in sorted(only_image)[:20]: print(f {name}.jpg) print(f缺少图像的标签数: {len(only_label)}) for name in sorted(only_label)[:20]: print(f {name}.txt)逻辑说明脚本把 images 目录下所有 jpg、png 文件的主文件名收集到一个集合把 labels 目录下的 txt 主文件名收集到另一个集合然后做集合差运算。only_image 是那些有图但没对应 txt 的文件only_label 则相反。参数说明glob 模式里的 jpg 和 png 按实际数据集情况增删如果还有 bmp、jpeg 后缀的图需要加一行 update 语句。这个脚本同样适配其他目标检测数据集不只是烟盒场景。3. 训练前的必修课标签质检、目标尺度评估与去重3.1 用脚本揪出越界框、空标注和类别噪声不少公开数据集的标签看着整齐实际上存在坐标越界、负宽度、空文件这类问题。越界框指的是 cx、cy、w、h 出现了小于 0 或大于 1 的数值负宽度等于这个框的方向反了空标注则是 txt 文件里面没有任何内容。烟盒这种目标形状规整出现这些错误基本就是打标时手滑或转换脚本有 bug。from pathlib import Path label_dir Path(labels) bad_files [] for txt_path in label_dir.glob(*.txt): lines txt_path.read_text(encodingutf-8).strip().splitlines() if len(lines) 0: bad_files.append((txt_path.name, 空标注)) continue for line in lines: parts line.strip().split() if len(parts) ! 5: bad_files.append((txt_path.name, f字段数异常: {line})) continue cid, cx, cy, w, h map(float, parts) if not (0 cx 1 and 0 cy 1): bad_files.append((txt_path.name, f中心点越界: {line})) if w 0 or h 0 or cx w / 2 1 or cy h / 2 1: bad_files.append((txt_path.name, f框越界或宽高异常: {line})) if bad_files: print(f发现 {len(bad_files)} 个异常: ) for name, err in bad_files[:30]: print(f {name}: {err}) else: print(标签全部正常)逻辑说明遍历每个 txt 文件按行读取后先检查字段数量是否为 5再检查归一化坐标是否在有效范围内。中心点加半宽超过 1 说明框的一侧超出图像右边界或下边界这种框在训练时会被 YOLO 强制裁剪导致目标看起来是残缺的。参数说明这段代码默认了标签行内用空格分隔。如果你的标签文件是用逗号分隔的需要先把split()改成split(,)。检查通过不代表高枕无忧它只保证数值合法不保证框真的框住了烟盒后者只能靠可视化抽查。3.2 目标尺度过小怎么办重新理解图像缩放的选择烟盒在画面里如果只占二十分之一甚至更小的面积把它缩放到 640×640 输入模型时特征图上的目标可能只剩几个像素点。YOLOv8 默认训练会做 letterbox 缩放也就是把整张图等比缩放再填充灰边这种做法保留全局信息但小目标会进一步缩水。常见做法是先用脚本统计所有标注框宽度和高度的像素分布看中位数是多少。如果大量目标宽度不足图像的 10%优先尝试把训练尺寸从 640 提升到 960 或 1280让每个烟盒在特征图上占更多像素。显存不够时再考虑把原始高分辨率图像切成若干小块训练也就是 ai 拼接的变体检测时再把预测框映射回大图坐标。这里的关键不是盲目套用某个图像缩放原理而是根据你业务相机安装高度决定的烟盒尺度来定输入尺寸。如果统计下来目标确实很小还有一种做法是裁剪训练把每个烟盒框周围扩大一定比例裁成子图同时生成对应的新标签等于人工制造一批“近距离视角”。这种方式会增加标注分布和真实场景的偏差部署时需要对相机画面做同样的裁剪逻辑。我的建议是优先调大 imgsz效果不够再做裁剪因为裁剪训练会间接改变目标的宽高比分布导致模型对原始构图下的检测变差。3.3 重复图像检查用哈希去重避免数据泄露公开数据集最隐蔽的问题是重复或近似重复的图像被拆进了训练集和验证集。这类同源图片会让验证指标虚高部署到新场景时性能立刻现原形。图像内容完全相同的情况用 md5 哈希就能查出来相似但经过缩放、轻度压缩的图则需要感知哈希一般场景下 md5 足够。import hashlib from pathlib import Path def md5_of_file(path): h hashlib.md5() with open(path, rb) as f: for chunk in iter(lambda: f.read(8192), b): h.update(chunk) return h.hexdigest() image_dir Path(images) hash_map {} for img_path in sorted(image_dir.glob(*.jpg)): digest md5_of_file(img_path) if digest in hash_map: print(f重复图像: {hash_map[digest]} 与 {img_path.name}) else: hash_map[digest] img_path.name逻辑说明按 8KB 一块读取图像文件并累加计算 md5避免一次性读入大图占内存。hash_map 以文件哈希为键、文件名为值遇到重复哈希就输出一对重名图像。发现重复后手动看一眼这两张图确认是同一画面后删除其中一张同时删除它对应的标签文件。参数说明8KB 的块大小对 md5 计算速度影响不大不需要专门调。如果你的数据集里有大量 png 图把 glob 改成*.png再跑一遍。这里应该用“ 注意”提示去重必须同时删标签只删图不删标签会直接触发上一节的孤儿文件报错。4. 用 YOLOv8 训练烟盒检测最小脚本、超参清单与损失曲线4.1 目录规范与 data.yaml 的写法ultralytics 框架对数据集目录有固定期待数据集的 images 下分 train 和 val 子目录labels 下同样分 train 和 val。上一章解压出来的扁平结构需要先拆分。常见做法是随机抽样 10% 到 15% 的图像作为验证集同时确保对应的标签文件跟着移动。mkdir -p dataset/images/train dataset/images/val dataset/labels/train dataset/labels/val python split_dataset.py # 移动文件到上述目录拆分时的随机种子要固定比如random.seed(42)否则每次拆分结果不同复现实验时指标对不上会非常折磨人。拆分完成后写一个 data.yaml 指向数据集根目录path: ./cigarette_dataset train: images/train val: images/val nc: 1 names: 0: cigarette_pack参数说明path 可以填绝对路径或相对路径相对路径相对于你执行训练命令的目录。nc 是类别数量烟盒检测就填 1。如果你后面要加入场景中的手机、打火机等目标改成 3 并在 names 里补齐对应名称即可。4.2 最小训练命令从 YOLOv8n 起步单类检测没必要一上来就上 YOLOv8xn 模型的参数量小、训练快用来先建立一个性能基线非常合适。先用下面的命令跑通全流程确认没报错再根据基线指标决定是否换成 s 或 m 版本yolo detect train datadataset/data.yaml \ modelyolov8n.pt \ epochs100 \ batch16 \ imgsz640 \ device0 \ patience20 \ project./runs \ namesmoke_pack_v1参数说明yolov8n.pt是预训练权重框架会自动下载并在 COCO 预训练基础上做迁移学习batch16 按你显卡显存调整6GB 显存建议降到 824GB 显存可以拉到 32 以上patience20 表示连续 20 个 epoch 验证集指标没有提升就提前停止训练。训练过程的日志会输出到runs/smoke_pack_v1目录。逻辑说明迁移学习对这类中小型数据集很关键因为烟盒的表面纹理、反光特征和 COCO 里的通用物体有很大重叠预训练权重能显著加快收敛。如果不用预训练权重从零开始训100 个 epoch 大概率不够。4.3 训练时看什么loss 曲线和混淆矩阵训练过程中很多人只盯着 loss 数字其实更该看的是每轮结束后的验证集指标。YOLOv8 的损失由三部分构成框回归损失、分类损失、分布焦点损失。训练 loss 下降但验证集 mAP 不涨方向在哪可以建立表格对比观察项正常形态异常形态train/box_loss前 20 个 epoch 快速下降后趋缓持续震荡或完全不降train/cls_loss单调下降后期平稳反复反弹val/mAP50稳步爬升后进入平台期训练集涨、验证集不涨如果 mAP50 已经超过 0.95但对小尺寸烟盒的召回率偏低重点看混淆矩阵里烟盒类别被预测成背景的比例。出现大量漏检时一般不是模型能力问题而是数据集里小目标的标注框本身太少或注释边缘留白过大导致正负样本失衡。这时回头去看第三章的尺度统计结果。5. 烟盒数据集训练避坑记录从 zip 解压失败到显存 OOM5.1 现象zip 解压到一半报 CRC 校验错误下载完成的数据集 zip 文件在解压过程中提示某个图片文件 CRC 校验失败重试多次仍然在同一位置中断。这种情况在网盘转存的文件里很常见。原因是文件在传输过程中出现字节损坏或者原压缩包本身制作不完整也不排除 zip 伪加密导致解压工具误判。解决办法分两步先用unzip -t测试压缩包完整性确认坏文件具体是哪几个如果只有少数几个文件损坏用unzip命令配合通配符跳过坏文件解压出其余内容后再重新下载损坏的部分。对于查出来是伪加密的压缩包用 7-Zip 打开时往往能直接看到文件列表但解压时要求密码这种一般丢掉换源重新下载。5.2 现象标签可视化翻车框大面积偏移解压后把标注画到原图上检查发现烟盒框整体往右上偏移而且偏移量和目标位置有关越靠右下角的框偏移越明显。这类问题的根源基本是标签坐标的归一化基准和实际图像尺寸不一致比如打标时用的原图是 1920×1080而压缩包里的图像被脚本压缩成了 1280×720标签却没有重新计算。解决办法是用脚本把全部标签除以缩放比例重算。具体做法是统一读取每张图像的实际宽高和当前标签的比例做归一化映射重新保存。这个坑尤其隐蔽因为损失函数仍然会收敛mAP 指标也可能不差但可视化检测框就是肉眼可见地偏部署时框和烟盒错位会导致后续业务逻辑误判。5.3 现象训练集 loss 正常下降验证集 mAP 一直卡在 0.6 上不去训练流程没报错loss 曲线也符合预期但每轮验证集的 mAP50 始终在 0.6 左右模型明显是欠拟合或学到了一些假特征。拆开验证集的预测结果后发现漏检集中在样本数量极少的特定角度烟盒上——比如俯视视角的烟盒只出现了几十张训练集中正样本严重不足。解决方向是补数据而不是调参。先用训练好的模型在未标注的图像上做伪标注人工挑出置信度高且框准确的烟盒补进训练集迭代一轮后再看指标。如果补数据不方便也可以给这类稀缺角度图像做在线增强把上下翻转和左右翻转的增强概率调高YOLOv8 默认开启的 mosaic 和 mixup 对这种问题有一定帮助但效果不如真实样本数据。5.4 现象16GB 显存训练 YOLOv8m 中途 OOM显存充足的情况下仍然在训练中途弹出 CUDA out of memory通常不是 batch 太大而是 mosaic 增强阶段同时拼接了多张高分辨率图临时缓存把显存峰值顶穿了。这属于旧版训练流程的经典翻车点解决方案是降低 batch 到 8 并开启梯度累积或者换更小的模型变体。梯度累积的做法是设batch8、accumulate4等效于 32 的批量大小但显存只占 8 张图。同时检查系统里是否还有其他进程占用显存养成训练前用nvidia-smi看一眼的习惯能省去很多玄学排查时间。对于单卡 16GB 的环境烟盒单类检测建议直接用 YOLOv8n 或 s不需要上 m。6. 验证与微调把烟盒模型的置信度阈值调到可以上线的状态模型训练完成后先跑一次验证集输出完整指标再根据业务场景调置信度阈值。YOLOv8 默认的检测置信度阈值是 0.25NMS 的 IoU 阈值是 0.7。无人货柜这类部署场景里漏检一盒烟比误检一盒烟的成本高得多这时候把置信度阈值降到 0.15 左右能显著提高召回率代价是可能出现少量误报。yolo detect val \ datadataset/data.yaml \ modelruns/smoke_pack_v1/weights/best.pt \ conf0.15 \ iou0.7执行后会生成混淆矩阵图、F1-曲线、PR 曲线和每类的详细指标。重点关注 recall 这一列如果烟盒类别的召回率不足 0.9第一优先级不是调锚框而是补漏检角度的训练样本。只有基准精度和召回都达标了再考虑用 TensorRT 导出 INT8 量化模型提升推理速度。如果你的部署场景需要精确的烟盒位置而非粗略框也可以考虑切到 YOLOv8 实例分割分支标签从框级补充到掩码级这些操作和再训练一套模型的成本相当决策前先确认业务是否真的需要像素级轮廓。我习惯在每次实验前固定随机种子并保留全部训练命令的日志文件这样一旦调参翻车还能回滚到上一个有效版本已经成了一种省时间的本能。这条路我自己走通了好几轮希望帮到你。本文还有配套的精品资源点击获取