☰
电池数据集实战:YOLOv7 训练调参与 97.7% 识别率复现
2026/10/10 11:46:39 网站建设 项目流程

简介:本资源为面向计算机视觉与目标检测学习者的电池识别数据集,聚焦9伏电池、纽扣电池与干电池三类常见电池的检测任务,适合从事YOLO系列模型训练、课程设计或工业分拣场景验证的开发者使用。压缩包内共2000个文件,以1999个txt标注文件和1个yaml配置文件为主,txt文件对应每张图像的YOLO格式标注框信息,yaml则用于定义数据集路径与类别名称,整体包大小约65.72MB。数据集包含2030张640×640分辨率的原始图像,均已完成yolov7格式标注,官方给出正确识别率约97.7%,可直接用于模型训练、微调与精度对比实验。目前已有49人学习下载,适合需要快速获取标注规范、类别均衡且开箱即用的电池检测数据集的读者,能有效减少自行采集与标注的时间成本,为算法验证与项目落地提供可靠基础。

1. 电池数据集:2030 张 640×640 原图与 97.7% 识别率背后的落地账

做电池分拣、回收质检或者产线物料盘点的人,大概率都遇到过同一个尴尬:模型在实验室里跑得挺欢,一上真实工位就翻车——9V 方块电池和干电池侧影混在一起,纽扣电池小到只有几十个像素,反光一打直接消失。这份电池数据集就是冲着这个场景来的:2030 张原始图,统一 640×640 分辨率,按 YOLOv7 格式标注,覆盖 9 伏、纽扣电池、干电池三类,官方给出的正确识别率是 97.7%。它不是那种几百张凑数的玩具集,而是能直接拿去训练、验证、部署的工程级素材。适合谁?做工业视觉落地的算法工程师、带学生做检测课题的高校团队、以及想快速验证电池识别方案的产品侧同学。下面我按「拿到手怎么用 → 参数怎么调 → 坑在哪」的顺序,把这份资源拆开讲透。

2. YOLOv7 标注格式拆解:从文件名到 .txt 的对应关系

2.1 目录结构与标签文件命名规律

先把压缩包解开,你会看到图片和标签是成对出现的。从项目正文给出的文件名能看出规律:图片名经过了一次 URL 编码,比如-E9-9B-BB-E6-B1-A0...这一段其实是中文「锂电池」的 UTF-8 编码被转义后的结果,后面跟着mp4-t-9-8_jpg.rf.9fda1ea0a91ad15397f70c0257bdcaca这样的后缀。.rf.后面那串哈希是标注工具导出时自动生成的唯一标识,用来防止重名覆盖。对应的标签文件就是把图片扩展名换成.txt,前缀完全一致。

这种命名方式有个好处:图片和标签靠文件名就能一一对应,不需要额外的映射表。但也有个坑——文件名里带-和.混用,某些老版本的 DataLoader 在解析时会误判扩展名。我一般会先跑一遍校验脚本,确认图片和标签数量对得上、没有孤儿文件。

import os from pathlib import Path img_dir = Path("images") lbl_dir = Path("labels") imgs = {p.stem for p in img_dir.glob("*.jpg")} lbls = {p.stem for p in lbl_dir.glob("*.txt")} # 图片有但标签没有 missing_lbl = imgs - lbls # 标签有但图片没有 missing_img = lbls - imgs print(f"图片总数: {len(imgs)}, 标签总数: {len(lbls)}") print(f"缺标签: {len(missing_lbl)}, 缺图片: {len(missing_img)}")

这段脚本做的是集合差运算。p.stem取的是不含扩展名的文件名,这样.jpg和.txt就能对齐比较。跑完如果两个缺失数都是 0,说明配对完整;如果有缺失,优先检查是不是解压时中断导致文件损坏。参数上没什么可调的,唯一要注意的是glob的大小写敏感问题——Linux 下*.jpg不会匹配.JPG,如果你的图里有大写扩展名,得改成*.jpg加*.JPG两次匹配。

2.2 YOLO 标签行的五个字段含义

每个.txt里的一行代表一个目标框,格式是:

<class_id> <x_center> <y_center> <width> <height>

五个字段全部归一化到 0~1 之间。class_id从 0 开始,这份数据集三类电池对应的编号需要你打开data.yaml或者classes.txt确认,常见顺序是 0=9V、1=纽扣、2=干电池,但不同导出批次可能不一样,千万别凭猜。后四个值是框的中心点坐标和宽高,都除以了图片的宽和高。

# 快速看一个标签文件的内容 cat labels/IMG_0888_jpeg.rf.47b752b0a3690fd384b62252fbc33946.txt

假设输出是0 0.512 0.634 0.221 0.318,意思是:类别 0,框中心在图片横向 51.2%、纵向 63.4% 的位置,框宽占全图 22.1%,框高占 31.8%。换算回像素(640×640):中心点约 (328, 406),框大小约 141×204 像素。这个换算在排查「框画歪了」的时候特别有用。

注意:归一化坐标如果出现大于 1 或者负数,说明标注时框超出了图片边界,YOLOv7 训练时虽然会做裁剪,但这类样本多了会拉低小目标的召回。

2.3 用脚本把标签画回图片做可视化抽检

标注质量不能只看数字,得画出来看。下面这段脚本随机抽 9 张图,把框和类别叠上去,存成一张对比图。

import cv2 import random from pathlib import Path img_dir = Path("images") lbl_dir = Path("labels") class_names = ["9V", "button", "dry"] # 按你的 data.yaml 改 def draw(img_path, lbl_path): img = cv2.imread(str(img_path)) h, w = img.shape[:2] if lbl_path.exists(): for line in lbl_path.read_text().strip().split("\n"): cid, xc, yc, bw, bh = map(float, line.split()) x1 = int((xc - bw/2) * w) y1 = int((yc - bh/2) * h) x2 = int((xc + bw/2) * w) y2 = int((yc + bh/2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, class_names[int(cid)], (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) return img samples = random.sample(list(img_dir.glob("*.jpg")), 9) canvas = [draw(p, lbl_dir / (p.stem + ".txt")) for p in samples] rows = [cv2.hconcat(canvas[i:i+3]) for i in range(0, 9, 3)] grid = cv2.vconcat(rows) cv2.imwrite("check_grid.jpg", grid)

逻辑很直白:读图、读标签、反归一化算出像素坐标、画框写字。class_names必须和你的data.yaml里names的顺序严格一致,否则类别名会张冠李戴。抽检时重点看三种情况:框有没有把电池本体漏掉一截、纽扣电池这种小目标框是不是明显偏大、以及有没有把背景里的圆形杂物误标成纽扣电池。这三类问题在电池数据集里出现频率最高。

3. 训练参数配置:640 分辨率下三类电池的调参实战

3.1 data.yaml 与模型配置文件的对应

YOLOv7 训练前要准备两个 YAML:数据配置和模型配置。数据配置长这样:

# data.yaml train: ./images/train val: ./images/val nc: 3 names: ['9V', 'button', 'dry']

nc是类别数,这份数据集是 3。names的顺序决定了class_id的含义,必须和标签文件里的编号对齐。模型配置用yolov7.yaml就行,但要把里面的nc改成 3。很多人直接拿官方yolov7.yaml不改nc,训练时 loss 不降反升,排查半天才发现是类别数没对上——这是血泪经验里排前三的翻车点。

# 训练启动命令 python train.py \ --weights yolov7.pt \ --cfg cfg/training/yolov7.yaml \ --data data.yaml \ --img 640 640 \ --batch-size 16 \ --epochs 100 \ --device 0 \ --workers 8 \ --name battery_yolov7

参数逐个说:--img 640 640和数据集分辨率一致,不要改成 1280,否则小目标纽扣电池的标注框会被缩放得很难学;--batch-size 16是 8G 显存下的稳妥值,显存够可以上 32;--epochs 100对 2030 张图来说偏保守,实际观察到 60~80 轮 mAP 就基本收敛,但多跑不亏;--workers 8是数据加载线程数,设成 CPU 核数的 0.8 倍左右比较稳。

3.2 学习率与锚框的适配调整

YOLOv7 默认学习率是 0.01,配合 SGD 优化器。但这份数据集只有 2030 张,属于小规模,默认学习率容易在后期震荡。我一般会降到 0.005,同时把 warmup 轮数从 3 提到 5,让模型在前几轮更温和地适应。

# 在 train.py 的参数里追加 --hyp data/hyp.scratch.p5.yaml \ --lr0 0.005 \ --warmup-epochs 5

锚框方面,YOLOv7 自带的锚框是基于 COCO 聚类的,对电池这种「大目标(9V)+ 小目标(纽扣)」混合的场景不一定最优。如果训练几轮后发现纽扣电池的召回明显低于另外两类,可以用 k-means 在自己的标注框上重新聚一组锚框。常见做法是跑utils/autoanchor.py里的函数,把anchors参数替换掉。不过这一步不是必须的,先跑基线,看每类的 AP 再决定要不要动。

3.3 训练过程监控与 97.7% 识别率的复现条件

训练时重点盯三个指标:box_loss、obj_loss、以及验证集上的mAP@0.5。box_loss反映框回归的误差,正常应该在前 10 轮快速下降然后趋缓;obj_loss是目标置信度损失,如果它一直高位不降,多半是正负样本划分出了问题,检查data.yaml路径有没有写错导致加载了空标签。

官方给的 97.7% 正确识别率,我理解是在特定验证集上的 mAP 或者分类准确率。要复现这个数字,有几个前提:验证集和训练集同分布、没有严重的光照偏移、纽扣电池的样本量不能太少。如果你自己切分数据集时把纽扣电池全分到了训练集,验证集里一个都没有,那这个类别的 AP 直接是 0,整体数字自然上不去。建议按 8:1:1 分层切分,保证每类在验证集里都有足够样本。

from sklearn.model_selection import train_test_split from pathlib import Path all_imgs = list(Path("images").glob("*.jpg")) # 按类别分层需要先读标签统计主类别,这里简化为随机切分 train, val = train_test_split(all_imgs, test_size=0.2, random_state=42) val, test = train_test_split(val, test_size=0.5, random_state=42) print(f"train: {len(train)}, val: {len(val)}, test: {len(test)}")

random_state=42保证每次切分结果一致,方便复现。分层切分需要额外读标签文件统计每张图包含的类别,代码会长一些,但对小目标类别更友好。

4. 避坑与排查:电池数据集训练中最容易翻车的五件事

4.1 现象:训练 loss 正常但验证 mAP 始终为 0

原因通常是data.yaml里的val路径指向了不存在的目录,YOLOv7 不会报错,而是静默加载空验证集,导致 mAP 计算分母为 0。解决方法是训练启动后看日志里val:后面的样本数,如果是 0 就立刻停掉检查路径。另一个可能是标签文件的class_id超出了nc范围,比如nc: 3但标签里出现了3,这类样本会被跳过。

4.2 现象:纽扣电池几乎检测不到

纽扣电池在 640×640 下往往只有 30~50 像素,属于典型小目标。原因可能是锚框尺寸偏大,或者训练时--img被改成了 1280 导致小目标进一步缩小。解决办法是保持 640 分辨率,检查锚框里最小的那组是否在 20~60 像素量级,必要时用--img 640配合 Mosaic 增强提升小目标出现频率。另外,纽扣电池的反光会导致边缘模糊,标注时框可以适当放宽 2~3 像素。

4.3 现象:9V 电池和干电池互相误判

这两类在侧影下都是长方体,颜色也接近,模型容易混淆。原因是训练集里缺少「9V 正面 + 干电池侧面」这类对比样本。解决办法是在数据增强里加入随机旋转和色彩抖动,同时检查标签有没有把两类标反。我遇到过标注员把 9V 的标签写成干电池的编号,导致模型学出来的决策边界完全错位,这种只能靠可视化抽检发现。

4.4 现象:训练到一半显存溢出

--batch-size设太大,或者--workers过高导致数据加载进程占用过多内存。解决办法是把 batch 降到 8 或 4,同时开--accumulate做梯度累积模拟大 batch。另外,如果用了 Mosaic 增强,四张图拼接后实际输入尺寸不变但计算量增加,显存紧张时可以临时关掉 Mosaic 跑几轮看看。

4.5 现象:推理时框的位置整体偏移

多半是推理脚本里的预处理和训练时不一致。训练时 YOLOv7 会把图片 letterbox 到 640×640 并填充灰边,推理时如果直接 resize 而不 letterbox,坐标反算就会偏。解决办法是推理时复用datasets.py里的letterbox函数,保证预处理链路一致。这个坑很隐蔽,因为框看起来「差不多对」,但 IoU 就是上不去。

5. 从训练到部署:用 ONNX 导出验证 97.7% 是否真实可复现

训练完拿到best.pt之后,别急着信那个 97.7%,自己跑一遍验证才算数。我一般会做两件事:先在验证集上跑test.py拿每类的 AP,再把模型导出成 ONNX,用 ONNXRuntime 跑一遍推理,对比两者的输出差异。如果 ONNX 和 PyTorch 的输出框偏差超过 1 个像素,说明导出时有算子不兼容,部署到边缘设备上会出问题。

# 导出 ONNX python export.py --weights runs/train/battery_yolov7/weights/best.pt \ --include onnx --img 640 640 --simplify # 用 ONNXRuntime 验证 python -c " import onnxruntime as ort import numpy as np sess = ort.InferenceSession('best.onnx') inp = np.random.randn(1, 3, 640, 640).astype(np.float32) out = sess.run(None, {sess.get_inputs()[0].name: inp}) print('输出张量形状:', [o.shape for o in out]) "

--simplify会调用 onnx-simplifier 做图优化,去掉冗余算子,这一步在部署到 TensorRT 时几乎是必须的。输出张量形状一般是[1, 25200, 8](3 类 + 5 个框参数),25200 是三个检测头的网格总数。如果形状对不上,检查nc是否在导出时正确传入。

验证 97.7% 的具体做法:在测试集上跑test.py,看输出的mAP@0.5。如果三类都在 95% 以上,整体 97.7% 是可信的;如果某一类明显低,比如纽扣只有 88%,那整体数字就是被另外两类拉高的,实际部署时纽扣电池的漏检会让你很难受。我习惯把每类的 AP 单独记下来,而不是只看一个总数。

python test.py --weights best.pt --data data.yaml --img 640 --task test

从那以后我每次拿到标注数据集,都强制先跑一遍可视化抽检和类别分布统计,再开始训练。电池数据集的质量整体不错,但纽扣电池的样本量和反光问题需要你提前有预期。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询