ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLOv7电池检测实战:2030张原图训练与97.7%识别率复现

YOLOv7电池检测实战:2030张原图训练与97.7%识别率复现 简介这份电池数据集面向计算机视觉与目标检测方向的学习者和开发者聚焦于9伏电池、纽扣电池与干电池三类常见电池的识别任务可用于智能分拣、电池回收分类、工业质检等场景的模型训练与验证。资源包共约2000个文件以1999个txt标注文件和1个yaml配置文件为主txt文件对应每张图像的YOLO格式标注框信息yaml则用于定义数据集路径与类别名称压缩包整体约65.72MB便于快速下载与本地部署。图像原始分辨率为640×640共2030张采用yolov7标注规范官方给出的正确识别率可达97.7%可直接接入YOLO系列训练流程。目前已有48人学习下载适合希望快速搭建电池检测基线、验证标注质量或开展迁移学习实验的读者参考使用。1. 电池数据集与 YOLOv7从 2030 张原图到 97.7% 识别率的落地路径手里有一批 2030 张、640×640 分辨率的电池原始图标注格式是 YOLOv7类别覆盖 9V 方形电池、纽扣电池和干电池官方给出的正确识别率是 97.7%。这个数字放在工业质检、电池回收分拣、实验室耗材盘点这些场景里已经足够支撑一条自动化流水线的原型验证。但真正拿到数据集的人第一反应往往不是兴奋而是三个具体问题这 2030 张图够不够训一个能用的模型YOLOv7 的标注格式怎么转成训练脚本能吃的结构97.7% 是在什么划分和阈值下测出来的我自己复现能不能对上这篇笔记就按「数据集结构 → 训练环境 → 标注与增强 → 参数调优 → 避坑 → 验证技巧」的顺序把这条路径拆成能照着敲命令的步骤。适合已经跑过 YOLO 系列、想拿电池类小目标练手或做产线预研的工程师也适合刚接触数据标注、想搞清楚 YOLOv7 标注文件长什么样的新手。2. 拆开电池数据集2030 张原图与 YOLOv7 标注的目录结构2.1 三类电池的视觉差异与标注难点9V 方形电池、纽扣电池、干电池这三类目标在 640×640 的图里尺度差异很大。9V 电池通常是长方体长宽比接近 1:1.5边缘有金属扣干电池是细长圆柱长宽比能到 1:4 甚至 1:5纽扣电池是扁圆片直径小、反光强在整图里可能只占 30×30 像素。YOLOv7 的 anchor 机制对细长目标和极小目标本身就不算友好所以标注框的贴合度直接决定召回率。常见做法是干电池的框要贴住圆柱两端不要为了省事画成正方形纽扣电池的框要卡住圆形边缘宁可略大 2 到 3 像素也不要切掉边缘反光区。标注工具用 LabelImg 或 CVAT 都可以导出时选 YOLO 格式每张图对应一个同名 .txt 文件每行是class_id x_center y_center width height全部归一化到 0 到 1 之间。2.2 目录树与 data.yaml 的对应关系拿到数据集后先别急着改代码把目录理成 YOLOv7 官方仓库能直接读的结构。下面这棵树是我一般会先搭好的骨架images和labels必须一一对应文件名去掉扩展名后要完全一致。battery_dataset/ ├── images/ │ ├── train/ # 约 1420 张 │ ├── val/ # 约 305 张 │ └── test/ # 约 305 张 ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamldata.yaml里要写清类别数和类别名顺序必须和标注时的 class_id 一致。如果标注时 0 是 9V、1 是纽扣、2 是干电池那这里就不能乱。train: ./battery_dataset/images/train val: ./battery_dataset/images/val test: ./battery_dataset/images/test nc: 3 names: [9v_battery, button_cell, dry_battery]逻辑说明YOLOv7 的train.py会通过data.yaml里的路径去索引图片再自动把路径里的/images/替换成/labels/去找同名 txt。参数上nc必须等于 names 列表长度多一个少一个都会在加载模型头的时候报维度不匹配。如果原始数据没有划分用split_train_val.py按 8:1:1 随机切但要注意同一场景连拍的图不要跨集否则验证集精度会虚高。2.3 用脚本检查标注框是否越界或漏标2030 张图靠人眼过一遍不现实写个短脚本统计每个类别的框数量、宽高分布和越界情况。下面这段 Python 会遍历 labels 目录输出异常文件。import os import glob label_dir ./battery_dataset/labels/train class_count {0: 0, 1: 0, 2: 0} bad_files [] for txt_path in glob.glob(os.path.join(label_dir, *.txt)): with open(txt_path, r) as f: lines f.readlines() if len(lines) 0: bad_files.append((txt_path, empty)) continue for line in lines: parts line.strip().split() if len(parts) ! 5: bad_files.append((txt_path, format_error)) continue cls, x, y, w, h int(parts[0]), *map(float, parts[1:]) class_count[cls] class_count.get(cls, 0) 1 # 归一化坐标越界检查 if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): bad_files.append((txt_path, out_of_range)) if x - w/2 0 or x w/2 1 or y - h/2 0 or y h/2 1: bad_files.append((txt_path, box_cross_border)) print(类别框数:, class_count) print(异常文件数:, len(bad_files)) for item in bad_files[:20]: print(item)逻辑说明这段脚本不依赖任何深度学习库纯标准库就能跑。参数上x - w/2是框左边界小于 0 说明框超出图像左边缘训练时虽然会被裁剪但会引入噪声。如果bad_files里出现大量empty说明有图片没有对应标注要么补标要么从训练集里剔除。我一般会把异常文件单独移到一个review目录人工过一遍再决定去留。3. 用 YOLOv7 在本地跑通电池检测训练3.1 环境搭建与权重选择YOLOv7 官方仓库对 PyTorch 和 CUDA 版本比较敏感我踩过的坑是 torch 1.12 配 CUDA 11.3 能跑但 torch 2.x 有时候会在自定义算子那里报错。稳妥起见用 conda 建一个干净环境。conda create -n yolov7_battery python3.9 -y conda activate yolov7_battery pip install torch1.12.1cu113 torchvision0.13.1cu113 --extra-index-url https://download.pytorch.org/whl/cu113 git clone https://github.com/WongKinYiu/yolov7.git cd yolov7 pip install -r requirements.txt逻辑说明torch1.12.1cu113是官方仓库 README 里验证过的组合能避开大部分编译问题。权重文件用yolov7.pt做迁移学习起点如果显存只有 8GB可以换yolov7-tiny.pt但小目标召回会掉几个点。参数上--weights yolov7.pt加载的是 COCO 预训练权重--cfg cfg/training/yolov7.yaml指定模型结构--data data/battery.yaml指向前面写好的配置文件。3.2 训练命令与关键超参设置单卡训练直接用train.py下面这条命令是我在 2030 张图上跑通并复现 97% 左右精度的配置。python train.py \ --weights yolov7.pt \ --cfg cfg/training/yolov7.yaml \ --data data/battery.yaml \ --hyp data/hyp.scratch.p5.yaml \ --epochs 150 \ --batch-size 16 \ --img-size 640 640 \ --device 0 \ --workers 8 \ --name battery_yolov7逻辑说明--img-size 640 640和原始图分辨率一致不需要额外缩放避免小目标进一步变小。--batch-size 16在 8GB 显存上比较稳如果报 OOM 就降到 8同时把--accumulate设成 2 来等效大 batch。--hyp用hyp.scratch.p5.yaml里面lr0默认 0.01lrf0.1momentum0.937这些对电池这种三类目标够用。如果发现纽扣电池召回低可以把hyp里的box损失权重从 0.05 提到 0.08让模型更关注框回归。训练日志里重点看mAP0.5和mAP0.5:0.95前者到 0.97 以上、后者到 0.75 左右基本就接近标题里的识别率了。3.3 用 TensorBoard 盯住三类目标的精度曲线训练启动后在另一个终端跑tensorboard --logdir runs/train浏览器打开 6006 端口。重点看三件事第一val/box_loss是否在 50 epoch 后还在下降如果平了说明学习率该降了第二每个类别的precision和recall曲线纽扣电池的 recall 通常最低如果低于 0.9回去检查标注框是不是太小第三lr/pg0曲线YOLOv7 默认用余弦退火如果它提前掉到 0说明lrf设小了。我一般会在 100 epoch 时把--weights换成runs/train/battery_yolov7/weights/best.pt再微调 50 epoch这样比一口气跑 200 epoch 更稳。4. 标注质量与数据增强97.7% 背后的隐形参数4.1 标注一致性比标注数量更影响精度2030 张图不算多如果标注框松紧不一模型学到的边界会很模糊。我见过同一个纽扣电池有人画 28×28有人画 35×35训练时回归损失忽大忽小最后 mAP 卡在 0.92 上不去。解决办法是定一份标注规范9V 电池框贴住外壳边缘干电池框贴住正负极两端纽扣电池框以可见圆形边缘为准反光导致边缘不清时按直径估计值画。规范定完后抽 50 张图让两个人分别标算 IoU 一致性低于 0.85 就重新对齐标准。这一步花半天比后面调参三天都值。4.2 YOLOv7 内置增强的开关与参数YOLOv7 的hyp.scratch.p5.yaml里已经开了 mosaic、mixup、copy-paste 这些增强。对电池数据集mosaic 概率mosaic: 1.0可以保留它能把四张图拼成一张变相增加小目标上下文。但mixup: 0.1要谨慎电池类别之间颜色差异大mixup 后可能出现半透明叠影反而干扰学习我一般会降到 0.05 或直接关掉。copy-paste: 0.1对纽扣电池有用能把小目标复制到其他位置提升召回。另外degrees: 0.0保持默认电池在产线上不会大角度旋转开了反而引入不真实样本。flipud: 0.0、fliplr: 0.5可以保留左右翻转对三类电池都合理。4.3 用 SAHI 切片推理提升小目标召回如果训练完发现纽扣电池在整图里还是漏检可以上 SAHI 做切片推理。它把 640×640 的图切成带重叠的小块分别推理后再合并对小目标提升明显。安装和调用如下。from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction model AutoDetectionModel.from_pretrained( model_typeyolov7, model_pathruns/train/battery_yolov7/weights/best.pt, confidence_threshold0.25, devicecuda:0 ) result get_sliced_prediction( test_image.jpg, model, slice_height320, slice_width320, overlap_height_ratio0.2, overlap_width_ratio0.2 ) result.export_visuals(export_dirsahi_output/)逻辑说明slice_height和slice_width设成 320相当于把 640 图切成 4 块加边缘重叠纽扣电池在切片里像素占比翻倍更容易被检出。overlap比例 0.2 是为了避免目标被切在边界上。参数上confidence_threshold可以降到 0.2因为切片后误检会被 NMS 合并掉一部分。代价是推理速度变慢大概 3 到 4 倍适合离线质检不适合高帧率产线。5. 电池检测落地避坑从标注到部署的 5 个翻车现场5.1 现象训练 loss 正常下降但验证集 mAP 始终为 0原因data.yaml里的names顺序和标注文件里的class_id对不上或者val路径写成了相对路径但训练时工作目录变了。解决用绝对路径重写data.yaml再跑一遍test.py确认能加载到验证图。另外检查labels/val里是不是混进了classes.txt这类非标注文件YOLOv7 会把它当空标注读。5.2 现象纽扣电池 recall 只有 0.7干电池和 9V 都正常原因纽扣电池在 640 图里太小YOLOv7 的 P3 特征图下采样 8 倍后只剩几个像素。解决把--img-size提到 1280 再训一版或者用 SAHI 切片推理。如果不想重训可以在hyp里把anchor_t从 4.0 降到 3.0让更多小框参与匹配。我一般会先试anchor_t不行再上切片。5.3 现象模型把反光强烈的纽扣电池误判成 9V 电池原因两类目标在强反光下纹理接近标注时如果 9V 电池的金属扣区域被框进去模型会学到错误特征。解决重新检查 9V 电池的标注框把金属扣排除在外只框住电池主体。同时在增强里加hsv_v: 0.3让模型对亮度变化更鲁棒。如果误判还是多在data.yaml里加一个ignore类别把难分的样本标成 ignore训练时不计损失。5.4 现象训练到 80 epoch 后 mAP 突然掉点原因学习率余弦退火到底后模型在局部最优附近震荡或者mosaic增强在后期引入太多噪声。解决在train.py里加--linear-lr让学习率线性下降或者在 80 epoch 时手动停掉 mosaic把hyp里的mosaic改成 0.0 再跑 20 epoch。我习惯在--name里加_finetune后缀保留两个阶段的权重方便对比。5.5 现象导出的 ONNX 模型在 TensorRT 上推理结果和 PyTorch 不一致原因YOLOv7 的export.py默认输出三个检测头TensorRT 解析时如果--grid参数没对齐框的解码会错位。解决导出时加--grid并确认--img-size和训练一致然后用trtexec转 engine 时指定--fp16或--int8前先跑一遍校准。如果还是不一致检查预处理里的归一化是不是 0 到 1TensorRT 默认不做这个缩放。6. 验证 97.7% 是否可复现一个具体技巧标题里的 97.7% 大概率是mAP0.5或者某一类别的 precision但不同划分和置信度阈值下这个数字会浮动。我一般会做三件事来验证第一固定随机种子在train.py里加--seed 42保证每次划分一致第二用test.py在独立测试集上跑命令是python test.py --weights best.pt --data data/battery.yaml --img-size 640 --conf 0.25 --iou 0.65输出里看P、R、mAP0.5三个值第三把测试集按类别拆开单独算每个类别的 AP如果 9V 和干电池都在 0.98 以上纽扣在 0.95 左右加权平均到 0.977 是合理的。如果复现出来只有 0.95先别怀疑数据集按这个顺序排查标注框越界比例是否超过 2%、验证集里是否有训练集同场景连拍图、conf阈值是不是设成了 0.5 以上。我踩过的血泪经验是conf从 0.25 提到 0.5mAP 能掉 3 到 5 个点因为很多低置信度框其实是正确的。另外YOLOv7 的test.py默认--augment是关的打开 TTA 能再涨 0.5 到 1 个点但推理时间翻倍产线上要权衡。最后说一个我自己的习惯每次训完模型把best.pt、data.yaml、hyp.yaml和测试集预测结果打包到一个带日期的文件夹里再写一行README记下mAP和conf阈值。这样过两个月回头看能立刻知道当时 97.7% 是在什么条件下测的不用靠回忆去猜。电池检测这个方向数据集质量比模型结构重要标注一致性比数据量重要希望帮到你。本文还有配套的精品资源点击获取
返回列表