news 2026/10/25 12:56:59

电力红外14类变压器检测数据集:VOC/YOLO转换、划分与训练避坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
电力红外14类变压器检测数据集:VOC/YOLO转换、划分与训练避坑

简介:面向电力场景电气设备红外检测需求,这份数据集资料围绕变压器及相关设备的目标检测任务整理,适合电力巡检、缺陷识别方向的研究人员与工程师用于模型训练和算法验证。配套文档约1MB,仅含1个docx文件,集中说明数据集的构成、标注规范与使用边界,便于在正式取数前快速判断其适用性。数据覆盖4271张红外图像,采用Pascal VOC与YOLO双格式标注,共14个类别、11896个矩形框,涉及空气断路器、电流互感器、连接器、避雷器、负荷开关、塑壳断路器、电压互感器、真空断路器和柜身等对象;其中Connection类框数最多,PF类较少,类别分布差异可供采样与损失设计参考。资料同时注明标注工具为labelImg、标注规则为逐类画框,并提示不对训练模型精度作保证。已有101人学习,适合需要了解红外电力设备数据规格、评估数据质量与规划检测实验的读者查阅。

1. 电力红外变压器检测数据集:4271 张图与 14 类标签先看清

电力场景电气设备红外图像变压器检测数据集,4271 张红外图配 VOC 与 YOLO 双格式标注,14 类设备框共 11896 个。它不是拿来就涨点的万能包,最大价值是把 ACB、CT、MCCB、VCB、PT 等一次凑齐,让你能把“设备定位”这件事先跑通。适合做电力巡检算法验证的工程师、做课程设计的学生,也适合想练类别不均衡和小目标检测的熟手;如果你的任务只是识别单一变压器,直接上这份数据集反而会把问题复杂化。拿到压缩包后先别急着训练,先看标签拼写、空框和类别分布,这三件事比选模型更影响最终结果。

2. VOC 与 YOLO 双格式拆解:14 类标签的读法、分布与合并决策

2.1 VOC xml 与 YOLO txt 各自管什么

这份数据集给的是 jpg 图片、VOC 格式 xml、YOLO 格式 txt,数量都是 4271,没有分割路径的 txt,也没有 mask 图。VOC 的 xml 里,一张图对应一个<annotation>,里面包含<size>的宽高,以及若干个<object>,每个 object 有<name>和<bndbox>的 xmin、ymin、xmax、ymax。YOLO 的 txt 每行是class_id cx cy w h,坐标已经归一化到 0 到 1,class_id 从 0 开始,具体类别名不在 txt 里,而是由训练配置里的 names 列表决定。两边唯一的硬约束是:xml 的 size 必须和 jpg 实际宽高一致,否则转换出来的归一化坐标会整体跑偏。

常见翻车点是把 VOC 的 xmax、ymax 当成宽高,或者把 YOLO 的 cx、cy 当成左上角。VOC 是绝对像素坐标,左上角加右下角;YOLO 是中心点加宽高,再除以图片宽高。用 labelImg 标注时,框的边界偶尔会贴到 0 或图片最大宽高,转换时要做一次裁剪,不然会出现负数或大于 1 的坐标。训练器一般会报 warning,但不会帮你修数据,最后表现成框偏移、mAP 虚低。

2.2 14 类标签分布:先看框数再谈模型

原始类别名是["ACB","CT","Conection","Connection","LA","LBS","MCCB","MOF","PF","PT","VCB","body","connection","core"]。注意这里有三个高度相似的写法:Conection、Connection、connection。输入里明确给出中文含义的只有 ACB 空气断路器、CT 电流互感器、Connection 连接器、LA 避雷器、LBS 负荷开关、MCCB 塑壳断路器、PT 电压互感器、VCB 真空断路器、body 柜身;MOF、PF、core 以及拼写变体没有给出中文,先按标签字面保留,不要自己猜。

标签中文含义(按给定)框数观察
ACB空气断路器94小类,容易漏
CT电流互感器790与 PT 外形接近
Conection标签字面,疑似拼写变体471与 Connection 混淆
Connection连接器3961最大类,主导损失
LA避雷器267小类
LBS负荷开关548中等
MCCB塑壳断路器1600第二大类
MOF标签字面273小类
PF标签字面56极少,先查是否有漏标
PT电压互感器661与 CT 易混
VCB真空断路器144小类
body柜身380大框,可能包住其他类
connection标签字面,小写变体1952与 Connection 混淆
core标签字面699中等

总框数 11896。Connection一类就占 3961,加上Conection的 471 和connection的 1952,连接器相关框合计 6384,超过一半。PF 只有 56 个框,ACB 94 个,VCB 144 个,这三个类在训练集里很可能被大类压住。先做一次统计,不要凭感觉调参。

from pathlib import Path import xml.etree.ElementTree as ET from collections import Counter raw = Path("dataset/raw") xmls = sorted(raw.rglob("*.xml")) counter = Counter() empty_xml = [] bad_boxes = [] for xml_path in xmls: root = ET.parse(xml_path).getroot() objects = root.findall("object") if not objects: empty_xml.append(xml_path.name) continue for obj in objects: name = (obj.findtext("name") or "").strip() counter[name] += 1 box = obj.find("bndbox") if box is None: bad_boxes.append((xml_path.name, name, "missing bndbox")) continue try: x1 = float(box.findtext("xmin")) y1 = float(box.findtext("ymin")) x2 = float(box.findtext("xmax")) y2 = float(box.findtext("ymax")) except (TypeError, ValueError): bad_boxes.append((xml_path.name, name, "non-numeric")) continue if not (0 <= x1 < x2 and 0 <= y1 < y2): bad_boxes.append((xml_path.name, name, (x1, y1, x2, y2))) print("类别框数:", counter) print("空 xml 数:", len(empty_xml), empty_xml[:5]) print("异常框数:", len(bad_boxes), bad_boxes[:5])

这段脚本做三件事:统计每个<name>的框数、找没有 object 的空 xml、找坐标非法或缺失 bndbox 的框。raw换成你解压后的图片和 xml 根目录;strip()不能省,标签名前后有空格会让类别对不上。跑出来的 Counter 应该能和上表对上,如果对不上,先检查是不是重复解压了目录,或者 xml 和 jpg 不在同一层。

2.3 合并重复类还是保留原样:一张映射表定决策

我一般会做两组实验,而不是一上来改标签。第一组是原始 14 类,完全按 txt 里的 class_id 走,作为 baseline;第二组把Conection和connection映射到Connection,类别数从 14 变成 12,总框数仍是 11896。合并后连接器类 6384 个框,MCCB 1600,CT 790,body 380,core 699,PT 661,小类仍然小。这个对照能回答一个问题:模型到底是被“连接器样本多”带偏,还是被“同一类拆成三个名字”带偏。

不建议把 CT 和 PT 合并,也不建议把 body 和 core 合并。CT 电流互感器、PT 电压互感器在红外图里可能外形接近,但语义不同;body 是柜身,core 是标签字面核心部件,框的层级可能不一样,合并会把大框和小框混成一类。合并只处理明显拼写和大小写变体,别扩散。

RAW_CLASSES = [ "ACB", "CT", "Conection", "Connection", "LA", "LBS", "MCCB", "MOF", "PF", "PT", "VCB", "body", "connection", "core" ] MERGE_MAP = { "Conection": "Connection", "connection": "Connection", } MERGED_CLASSES = [] for name in RAW_CLASSES: target = MERGE_MAP.get(name, name) if target not in MERGED_CLASSES: MERGED_CLASSES.append(target) print(MERGED_CLASSES) # ['ACB', 'CT', 'Connection', 'LA', 'LBS', 'MCCB', 'MOF', 'PF', 'PT', 'VCB', 'body', 'core']

MERGE_MAP为空时就是原始 14 类;启用后类别数变成 12。关键点:映射之后必须重新生成 YOLO txt 的 class_id,不能只改 names 列表。训练配置里的 names 顺序和 txt 的编号是一一对应的,顺序错一位,所有框都会学到错误类别。原始 14 类 baseline 和 12 类合并实验各留一份 data.yaml,别覆盖。

2.4 用脚本把标签健康度扫一遍

除了类别统计,还要看每张图的框数分布。红外图里经常出现一张图只有柜身大框,或者只有一个小连接器,这种样本对定位有帮助,但对分类帮助有限。统计每张图框数,可以快速找空 txt、单框图和异常多框图。空 txt 不是一定有问题,它可能被当成背景图使用;但如果空 txt 数量很大,说明标注覆盖不完整,训练时背景样本会压低召回。

from pathlib import Path from collections import Counter label_dir = Path("dataset/raw/labels") box_per_image = Counter() empty_txt = [] for txt in label_dir.glob("*.txt"): lines = [ln for ln in txt.read_text(encoding="utf-8").splitlines() if ln.strip()] box_per_image[len(lines)] += 1 if not lines: empty_txt.append(txt.name) print("每图框数分布:", sorted(box_per_image.items())[:10]) print("空 txt 数:", len(empty_txt), empty_txt[:10])

box_per_image的键是框数,值是该框数对应的图片数。如果 0 框图片占比超过 10%,先确认这些图是不是纯背景;如果 1 框图片大量集中在 body,说明很多图只标了柜身,没有标内部设备,训练时模型会倾向于只输出大框。空 txt 可以保留少量作背景,但不要大量保留,否则小类召回会被拉低。

3. 从原始压缩包到可训练目录:划分、转换与加载的三个脚本

3.1 目录怎么摆:images 与 labels 严格对应

解压后先把原始文件放成dataset/raw/images和dataset/raw/labels,图片和 xml 可以同目录,但转换后的 YOLO txt 单独放labels。最终训练目录用dataset/transformer_ir,下面分train、val、test,每个 split 里各有images和labels。文件名 stem 必须完全一致,abc.jpg对应abc.txt,不要出现abc.JPG和abc.txt大小写不一致,Linux 上会直接找不到标签。

常见做法是先转换再划分,这样划分脚本只复制 jpg 和 txt,不碰 xml。转换脚本读 xml 和 jpg,输出 txt 到dataset/transformer_ir/labels,图片复制到dataset/transformer_ir/images。不要在原始目录上直接改,留一份 raw 方便回滚。

3.2 VOC 转 YOLO:归一化、裁剪与类别映射

下面这段转换脚本同时处理类别映射、坐标裁剪和未知类别报错。未知类别直接抛异常,不要用continue悄悄跳过,否则你会在训练后发现少了一个类,回头查很费时间。

from pathlib import Path from PIL import Image import xml.etree.ElementTree as ET import shutil RAW = Path("dataset/raw") OUT = Path("dataset/transformer_ir") RAW_CLASSES = [ "ACB", "CT", "Conection", "Connection", "LA", "LBS", "MCCB", "MOF", "PF", "PT", "VCB", "body", "connection", "core" ] MERGE_MAP = {"Conection": "Connection", "connection": "Connection"} CLASSES = ["ACB", "CT", "Connection", "LA", "LBS", "MCCB", "MOF", "PF", "PT", "VCB", "body", "core"] def clip(v, lo, hi): return max(lo, min(v, hi)) def convert_one(xml_path, img_path): w, h = Image.open(img_path).size root = ET.parse(xml_path).getroot() lines = [] for obj in root.findall("object"): name = (obj.findtext("name") or "").strip() name = MERGE_MAP.get(name, name) if name not in CLASSES: raise ValueError(f"未知类别 {name} in {xml_path}") box = obj.find("bndbox") if box is None: continue x1 = float(box.findtext("xmin")) y1 = float(box.findtext("ymin")) x2 = float(box.findtext("xmax")) y2 = float(box.findtext("ymax")) x1 = clip(x1, 0, w - 1) y1 = clip(y1, 0, h - 1) x2 = clip(x2, 0, w) y2 = clip(y2, 0, h) if x2 <= x1 or y2 <= y1: continue cx = (x1 + x2) / 2.0 / w cy = (y1 + y2) / 2.0 / h bw = (x2 - x1) / w bh = (y2 - y1) / h cls_id = CLASSES.index(name) lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}") return "\n".join(lines) (OUT / "images").mkdir(parents=True, exist_ok=True) (OUT / "labels").mkdir(parents=True, exist_ok=True) for img_path in sorted(RAW.rglob("*.jpg")): xml_path = img_path.with_suffix(".xml") if not xml_path.exists(): print("缺 xml:", img_path) continue shutil.copy2(img_path, OUT / "images" / img_path.name) txt = convert_one(xml_path, img_path) (OUT / "labels" / f"{img_path.stem}.txt").write_text(txt, encoding="utf-8")

RAW是解压后的根目录,OUT是转换输出;MERGE_MAP为空字典时保留 14 类,启用时是 12 类;CLASSES的顺序就是 YOLO 的 class_id 顺序,必须和 data.yaml 的 names 完全一致。坐标裁剪到图片范围内,防止 labelImg 的边界框贴边产生负值。:.6f保留六位小数,足够训练用。转换完先看OUT/images和OUT/labels的文件数是否都是 4271 左右,少一张都要查。

3.3 按图像划分训练/验证/测试并防泄漏

划分按图片级别做,不要按框级别做。同一张图的多个框必须落在同一个 split,否则验证集会出现训练时见过的设备,mAP 虚高。常见比例是 8:1:1,小数据集可以 7:2:1,验证集至少留 300 张以上,测试集至少 300 张,不然单类指标波动很大。随机种子固定,划分结果存一份 csv,后续换模型才能公平比较。

import random import shutil import hashlib from pathlib import Path OUT = Path("dataset/transformer_ir") random.seed(202405) images = sorted((OUT / "images").glob("*.jpg")) random.shuffle(images) n = len(images) n_val = int(n * 0.1) n_test = int(n * 0.1) splits = { "val": images[:n_val], "test": images[n_val:n_val + n_test], "train": images[n_val + n_test:], } seen = {} for p in images: h = hashlib.md5(p.read_bytes()).hexdigest() if h in seen: print("重复图片:", p.name, "与", seen[h]) seen[h] = p for split, files in splits.items(): img_dir = OUT / split / "images" lbl_dir = OUT / split / "labels" img_dir.mkdir(parents=True, exist_ok=True) lbl_dir.mkdir(parents=True, exist_ok=True) for img in files: shutil.copy2(img, img_dir / img.name) shutil.copy2(OUT / "labels" / f"{img.stem}.txt", lbl_dir / f"{img.stem}.txt") print({k: len(v) for k, v in splits.items()})

seed=202405可以换成你们团队固定的种子;n_val和n_test各取 10%,剩下 80% 训练;md5 检查重复图片,重复图跨 split 是最隐蔽的泄漏源。复制而不是移动,原始转换目录保留一份,后面做 12 类合并实验可以重新划分,不用重跑转换。划分后检查每个 split 的 jpg 数和 txt 数是否一致。

3.4 自定义 Dataset 检查一圈再交给训练器

训练前用一个小 Dataset 或检查脚本把路径、标签、类别范围过一遍。重点看三件事:图片能否打开、txt 每行是否 5 个值、class_id 是否小于类别数。红外 jpg 偶尔有损坏文件,PIL 打开时报UnidentifiedImageError,这种图直接剔除或重新解压。

from pathlib import Path from PIL import Image OUT = Path("dataset/transformer_ir") num_classes = 12 # 14 类 baseline 改成 14 for split in ["train", "val", "test"]: imgs = {p.stem for p in (OUT / split / "images").glob("*.jpg")} lbls = {p.stem for p in (OUT / split / "labels").glob("*.txt")} print(split, "图片", len(imgs), "标签", len(lbls), "缺标签", len(imgs - lbls), "多标签", len(lbls - imgs)) for stem in list(imgs)[:200]: Image.open(OUT / split / "images" / f"{stem}.jpg").verify() for line in (OUT / split / "labels" / f"{stem}.txt").read_text().splitlines(): parts = line.split() if len(parts) != 5: print("坏行", stem, line) continue cls_id = int(parts[0]) if not (0 <= cls_id < num_classes): print("越界类别", stem, cls_id)

num_classes要和 data.yaml 的 names 数量一致;verify()只检查文件完整性,不保证像素能解码,真正训练时还会再读一次。坏行和越界类别必须清零,不要带着 warning 开跑。data.yaml 写成下面这样,路径用相对路径,换机器时只改path。

path: dataset/transformer_ir train: train/images val: val/images test: test/images names: 0: ACB 1: CT 2: Connection 3: LA 4: LBS 5: MCCB 6: MOF 7: PF 8: PT 9: VCB 10: body 11: core

如果保留 14 类,names 要按原始顺序补回Conection和connection,id 不能错位。这份数据集不保证训练精度,标签质量要自己抽检:每个类随机抽 20 张图,把框画回图上,看框是否贴住设备、类别是否标错。抽检比盲目加 epoch 有用。

4. YOLO 训练参数落地:红外小目标、类别不均衡与增强边界

4.1 基线训练配置:先让 14 类都跑起来

第一轮不要追求高 mAP,先把 14 类原始标签跑通,确认数据管道、类别数、评估流程没有错。模型选团队已有的检测权重,不要拿分类权重硬改头;输入尺寸先 640,显存不够降到 512,小目标多再上 960。batch 根据显存调,8 或 16 都行,workers 在 Linux 上 4 到 8,Windows 上先 0 或 2,避免多进程卡死。

from ultralytics import YOLO model = YOLO("baseline.pt") # 替换成本地已有的检测权重 model.train( data="dataset/transformer_ir/data.yaml", imgsz=640, epochs=100, batch=8, workers=4, device=0, optimizer="AdamW", lr0=0.001, lrf=0.01, warmup_epochs=3, mosaic=0.4, close_mosaic=10, hsv_h=0.0, hsv_s=0.1, hsv_v=0.2, degrees=0.0, translate=0.1, scale=0.3, fliplr=0.5, flipud=0.0, project="runs_ir", name="baseline_14cls", seed=202405, )

baseline.pt是占位,换成本地权重文件;device=0是单卡,CPU 改成"cpu";imgsz=640是基线,PF、ACB 这种小类如果框很小,可以再做一组 960 的对照;epochs=100配close_mosaic=10,最后 10 轮关掉 mosaic 让模型收一收;optimizer用 AdamW 对学习率不敏感,SGD 需要更大的 lr0。project和name用来分目录,别把 14 类和 12 类实验混在一起。

4.2 红外图像增强边界:HSV、Mosaic 与旋转怎么设

红外图有两种常见形态:灰度图和伪彩图。灰度图没有色相语义,hsv_h设 0,hsv_s也可以设 0,hsv_v小幅度调,模拟曝光和温度对比变化。伪彩图的颜色对应温度带,hsv_h大了会把高温色改成低温色,模型学到的颜色线索直接乱掉,所以hsv_h=0.0是保守起点,最多给到 0.01。hsv_s=0.1、hsv_v=0.2属于轻增强,不要照搬自然图像的 0.7。

Mosaic 会把四张图拼成一张,对密集小目标有帮助,但电力柜体有明确结构,拼得太狠会把柜身、连接器、断路器的上下文切碎。mosaic=0.4比默认 1.0 温和,小目标多可以 0.5,PF 只有 56 个框时不要开到 1.0。degrees=0.0是因为设备安装方向固定,旋转 10 度以上会出现不存在的姿态;flipud=0.0是上下翻转在电力场景不真实,fliplr=0.5左右翻转一般可以接受,但涉及固定柜门方向时先抽检。scale=0.3控制缩放范围,translate=0.1控制平移,别让框被裁掉太多。

4.3 类别不均衡处理:重采样、损失与阈值

14 类里 PF 56 框、ACB 94 框、VCB 144 框,Connection 相关 6384 框。直接训练时,大类会主导分类损失,小类容易变成背景。第一步不是复制小类,而是看 per-class AP:如果 PF 的 AP 为 0,先查测试集里 PF 有多少框,测试集本身太少的话指标没有统计意义;如果测试集够但 AP 低,再考虑训练集过采样。过采样可以复制含小类的图片,但要在训练集内部复制,不能跨到验证集,复制倍数 2 到 3 倍就够,太多会过拟合。

损失层面,YOLO 的分类损失对类别频率有一定敏感性,但不要指望换损失解决所有问题。更实际的做法是:先跑 14 类 baseline,再跑 12 类合并版,比较 PF、ACB、VCB 的单类 AP;如果合并后小类 AP 明显上升,说明拼写重复类在分散学习能力;如果没变化,问题在样本本身。推理阶段可以按类设阈值,PF 这种小类降低置信度阈值,MCCB 这种大类提高阈值,减少误检。

4.4 训练日志看什么:分项损失与单类 AP

训练日志里重点看box_loss、cls_loss、dfl_loss和验证集的 mAP50、mAP50-95。box_loss降不下去,先查框坐标和图片尺寸是否匹配;cls_loss降但 mAP 不升,查标签类别是否错位;dfl_loss波动大,可能是小目标框太小或增强太强。验证集 mAP50 高、mAP50-95 低,说明框的位置不够准,红外图边缘模糊时很常见,可以把imgsz提上去,或者减少 mosaic。

单类 AP 比总 mAP 更有诊断价值。PF、ACB、VCB 如果一直是 0,不要继续加 epoch,先抽 20 张测试图看模型输出;如果模型根本不输出这些小类,说明训练集里小类被压制,做训练集过采样或切图训练;如果输出了但框错,查标注框是否把设备局部当成了整体。训练日志和验证图一起看,别只看一个总指标。

5. 避坑与排查:拼写重复类、空框和误检的 5 个现场记录

5.1 拼写重复类把模型学散

现象:训练完看混淆矩阵,Conection、Connection、connection三个类互相串,单类 AP 都不高,但总 mAP 看起来还能接受。原因:三个名字在数据里是三个 class_id,模型把它们当成三个不同类别学,连接器样本被拆成 3961、1952、471 三份,每一份都不够纯;标注时同一个人可能今天写Connection,明天写connection,标签本身就不一致。

解决:先做映射实验,把Conection和connection归到Connection,类别数从 14 变 12,重新生成 txt 和 data.yaml。不要只改 names,必须改 txt 的 class_id。映射后跑一组对照,重点看连接器类的召回和误检是否下降。如果业务上确实要区分大小写变体,那得先确认它们代表不同设备;从这份数据的命名看,更像是拼写不统一,不像两个独立类别。

提示:映射前备份原始 labels,合并实验和原始实验各留一份目录,否则回头做 14 类 baseline 又要重新解压。

5.2 空标注与坐标越界让框跑偏

现象:训练时出现大量corrupt label或坐标越界 warning,验证图上的框整体偏移,甚至跑到图片外面。原因:labelImg 保存时框贴边,xmin 小于 0 或 xmax 大于图片宽度;也有 xml 的<size>和 jpg 实际尺寸不一致,转换脚本用 xml 宽高归一化,坐标就全错;空 xml 被转成空 txt,训练器把整张图当背景。

解决:转换时用 PIL 读 jpg 实际宽高,不要信 xml 的 size;坐标裁剪到[0, w]和[0, h];空 txt 单独列出,少量保留作背景,大量空标注先回查标注流程。训练前跑一遍坏行检查,len(parts) != 5和cls_id越界必须清零。坐标问题不要靠增强掩盖,增强只会让偏移更随机。

5.3 图像级划分泄漏把验证集刷虚高

现象:验证集 mAP 很高,测试集一落千丈;或者同一张图在训练集和验证集都出现,只是文件名不同。原因:按框随机划分,同一张图的多个框被分到不同 split;或者数据集中有重复图片,md5 相同但文件名不同,划分时没去重。红外巡检图经常连续拍摄,同一设备多角度,文件名不同但画面几乎一样,随机划分很容易泄漏。

解决:按图片 stem 划分,同一张图的全部框跟着图走;划分前算 md5,重复图只保留一张或强制分到同一侧;连续帧按时间或设备分组划分。验证集和测试集不要参与任何过采样。划分结果存 csv,换模型时复用同一份,别每次重新随机。

5.4 小类 PF、ACB、VCB 被大类淹没

现象:总 mAP 看着还行,但 PF 的 AP 是 0,ACB 和 VCB 也很低;推理时小类几乎不输出,或者输出框很大,把整个柜体框住。原因:PF 只有 56 个框,ACB 94 个,VCB 144 个,训练时被 Connection 和 MCCB 的大类损失压住;小目标在 640 输入下像素太少,下采样后特征消失;body 大框和 core 中框又抢了定位能力。

解决:先确认测试集里这些小类有足够框,测试集太少就只看训练集召回,不强行报 AP;训练集对含小类的图做 2 到 3 倍过采样;输入尺寸提到 960 做对照;小目标密集时用切块训练或切块推理,把大图切成重叠子图再检测。阈值按类调,PF 用低阈值保召回,MCCB 用高阈值压误检,别一套 0.25 走到底。

5.5 推理阈值照搬默认值导致漏检和误检

现象:训练指标不错,部署后要么漏掉小设备,要么背景热斑被当成设备。原因:验证时用的是低置信度算 PR 曲线,部署时直接套 0.25,小类分数普遍低,全被过滤;红外图背景有热源,模型把热斑学成连接器或断路器;不同类别的分数分布不一样,统一阈值不适合。

解决:在测试集上按类扫阈值,画 precision-recall 曲线,选业务可接受的平衡点;PF、ACB、VCB 适当降低阈值,MCCB、Connection 适当提高;部署前用负样本集跑一遍,统计误检来源。阈值表写进配置文件,不要写死在代码里,换场景时只改配置。

6. 验证与进阶技巧:用混淆矩阵和热区回看模型到底学了什么

6.1 混淆矩阵先看 CT/PT 与连接器互串

训练完不要只看 mAP,先导混淆矩阵。CT 和 PT 外形接近,红外图上都可能是圆柱或方块,互串很常见;Connection合并后样本多,容易把body上的局部结构也吸过去;core和body的框可能有包含关系,混淆矩阵里会表现为大框套小框。把混淆矩阵按行归一化,看每一类的召回,比看总准确率有用。

from ultralytics import YOLO model = YOLO("runs_ir/baseline_14cls/weights/best.pt") metrics = model.val( data="dataset/transformer_ir/data.yaml", split="test", conf=0.001, iou=0.6, ) print("mAP50-95:", metrics.box.map) print("mAP50:", metrics.box.map50) print("每类 AP:", metrics.box.ap_class_index, metrics.box.ap)

conf=0.001是为了让 PR 曲线覆盖低分框,部署阈值另算;iou=0.6是评估匹配阈值,和训练时的 NMS 不是一回事。跑完看ap_class_index对应的类别,PF、ACB、VCB 如果还是 0,回到第 5 章查小类,不要直接换更大的模型。

6.2 按类阈值与热区回看

我一般会把测试集误检按置信度排序,取前 50 张画框回看。重点看两类:背景热斑被误检成设备,以及小设备被大框包住。背景热斑的典型特征是框内没有明显设备边缘,只有一块亮区;小设备被包住时,模型输出的是 body 大框,里面没有独立的小框。前者加负样本或提高阈值,后者切图训练或过采样。

检查项看什么处理
混淆矩阵CT/PT、Connection/body 互串补难例,别急着合并语义类
单类 APPF、ACB、VCB 是否为 0过采样、提输入尺寸、切块
误检 Top50背景热斑、柜体局部加负样本,按类调阈值
漏检 Top50小目标、遮挡设备降阈值,切块推理

从那以后我每次拿到类似红外数据集,都强制先做一遍类别拼写合并审计和空框扫描,再谈训练;模型选型放在数据健康度后面,能少走很多回头路。希望帮到你。

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

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

CS229讲义作业与讲解:系统学习路径和避坑实践

简介&#xff1a;CS229全课程资料包系统整理了Andrew Ng教授斯坦福机器学习课程的讲义、作业与作业讲解&#xff0c;服务自学机器学习的在校学生、数据从业者与面试准备者&#xff0c;免去零散搜集、缺少配套练习的困扰。压缩包共47个文件、约9.22MB&#xff0c;以30个PDF讲义和…

作者头像 李华
网站建设 2026/10/25 12:53:49

从仿生到智能:OpenClaw多指协同技术全解析与TaoToken接入实践

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

作者头像 李华
网站建设 2026/10/25 12:48:05

text-to-cad 实战:从自然语言到 STEP/STL 模型全流程

1. 从一句话到三维模型&#xff1a;text-to-cad 到底在解决什么问题第一次听到 “text-to-cad” 这个词&#xff0c;我脑子里蹦出来的画面是&#xff1a;对着电脑说一句“给我画一个带法兰的六角螺栓”&#xff0c;然后 CAD 界面里就自动长出一个可以旋转、可以导出 STEP 的实体…

作者头像 李华
网站建设 2026/10/25 12:44:17

2022中国AI人才培养白皮书解读:能力模型、学习路径与职业入口

1. 这份白皮书到底讲了什么&#xff1a;从标题拆解到核心价值定位1.1 为什么一份“人才培养白皮书”值得反复翻第一次看到“2022年中国人工智能人才培养白皮书”这个标题&#xff0c;很多人第一反应是“又是一份宏观报告&#xff0c;翻两页就吃灰”。我一开始也这么想&#xff…

作者头像 李华
网站建设 2026/10/25 12:43:22

AI说“不”:内容安全审核与安全对齐的技术逻辑

简介&#xff1a;这套社工库源码资源包是搜云社工库的完整PHP项目&#xff0c;面向网络安全研究者、Web开发者和安全意识提升人群&#xff0c;帮助理解社会工程学数据的收集、索引与检索机制。压缩包体积仅331KB&#xff0c;共27个文件&#xff0c;以PHP后端逻辑、CSS前端样式、…

作者头像 李华
网站建设 2026/10/25 12:42:35

Lombok原理揭秘:Java编译器插件与AST修改机制

简介&#xff1a;本资源深入剖析Lombok在Java开发中的编译期代码生成机制&#xff0c;面向中高级Java开发者、注解处理器学习者及IDE插件原理研究者&#xff0c;解决样板代码冗余、编译时增强实现逻辑不透明等实际痛点。压缩包共40个文件&#xff0c;含9个核心Java源码&#xf…

作者头像 李华