ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

无人机频射信号检测数据集:Pascal VOC标注与YOLO训练实战

无人机频射信号检测数据集:Pascal VOC标注与YOLO训练实战 简介面向无人机检测与射频识别方向的研究者与算法工程师这份数据集提供了无人机频射信号的实拍图像样本画面同时覆盖有无人机目标帧与无目标空背景帧可用于分类、目标检测和频射信号识别相关的模型训练与效果验证。数据集中单类目标平均正确识别率达94.3%并严格采用Pascal VOC XML格式为每张原图标注目标框可方便转换为YOLO、COCO等主流检测框架所需格式下载后即可与对应jpg图片配对使用。资源共728个文件包括364张原始jpg图像和364个xml标注文件整体压缩包约136.89MB文件组织规整适合快速开展数据预处理或迁移训练。目前已有700人学习下载无论是刚接触检测任务的初学者还是需要基准数据做算法对比的进阶开发者都能从中节省数据采集与标注成本直接聚焦模型调优。1. 无人机频射信号检测364 张标注图平均识别率 94.3% 是怎么做到的做无人机目标检测的人绝大多数一开始盯的是可见光图像——找飞机、找人、找车牌YOLO 一把梭。但一旦遇到夜间、雾天、遮挡、或者无人机悬停在树冠后面视觉方案直接抓瞎。这也是为什么这两年频射信号检测被反复提无人机和图传链路是强制发射信号的频射特征绕不开。手头这份数据集364 张原始图片全部是无人机频射信号的频谱图标注格式走 Pascal VOC XML官方标注平均正确识别率 94.3%。不是 364 张里挑出 200 张能用的那种裁剪货是带完整 XML 标注、可以直接丢进训练流程的原始图。适合正在做反无人机系统、频谱感知、或者想给 YOLO 系模型加一路射频模态输入的从业者。这篇就把数据集的结构、标注格式、转换脚本和实际训练中的坑全部拆开讲。2. 先看懂数据集结构从文件名读出机型和信号特征2.1 文件名里的信息量kong 系列和 Mini3Pro 代表什么拿到数据集的第一件事不是打开图而是先看文件名。这份数据集的命名规律非常明显比如kong-29-_jpg.rf.9cd17aec4f296710e6d97856d96ce807.jpg和Mini3Pro_5-8GHZ-6-_jpg.rf.c9651ebbaa817b0aec20839ff8022921.jpg两部分信息直接写在文件名里。先看前缀部分kong系列和Mini3Pro系列是两类不同的无人机。kong大概率是某类穿越机或开源飞控机型的代号而Mini3Pro对应大疆 Mini 3 Pro。这两类飞机的频射特征差异很大——大疆的图传走的是自家 OcuSync 协议跳频图案、带宽、调制方式都有固定规律穿越机用的多是 ELRS、ExpressLRS 或传统模拟图传信号特征完全不同。数据集把这两类都放进来目的就是让模型学到「不同协议、不同频段的信号差异」而不是只认某一个型号。再看中间段5-8GHZ这直接标注了信号频段5.8GHz 是消费级无人机图传的主流频段。频段信息对频射检测非常关键因为不同频段的信号在频谱图上呈现的形态、带宽、信噪比都不一样。模型如果只在单一频段上训练换到 2.4GHz 或者 900MHz 的场景基本就废了。这个数据集把频段信息写进文件名实际上是给你留了一条后路——后续你按频段做数据集划分或者做域适应都有据可依。最后是_jpg.rf.后面的那串哈希字符串。这是 Roboflow 导出数据的典型标记说明这 364 张图是原始数据集经过 Roboflow 平台清洗、增强、导出后的结果。哈希值对应的是 Roboflow 内部的图片 ID排查标注问题时可以用它反查。2.2 数据集文件清单与目录组织方式拿到压缩包解压后目录结构大概是这样的drone-rf-dataset/ ├── annotations/ │ ├── kong-29-_jpg.rf.9cd17aec4f296710e6d97856d96ce807.xml │ ├── kong-41-_jpg.rf.22cee58a0ba8ab8ecebdcb466f12c4da.xml │ ├── kong-28-_jpg.rf.70b156f24045e28485043da5d6eb13e8.xml │ ├── Mini3Pro_5-8GHZ-6-_jpg.rf.c9651ebbaa817b0aec20839ff8022921.xml │ └── ... ├── images/ │ ├── kong-29-_jpg.rf.9cd17aec4f296710e6d97856d96ce807.jpg │ ├── kong-41-_jpg.rf.22cee58a0ba8ab8ecebdcb466f12c4da.jpg │ ├── kong-28-_jpg.rf.70b156f24045e28485043da5d6eb13e8.jpg │ ├── Mini3Pro_5-8GHZ-6-_jpg.rf.c9651ebbaa817b0aec20839ff8022921.jpg │ └── ... └── classes.txtannotations目录存放所有 XML 标注文件images目录存放原始 JPG 频谱图两个目录下的文件名一一对应。classes.txt是类别清单文件通常每个类别占一行这个数据集的类别大概率就是kong和Mini3Pro两个也可能有drone的统一类别取决于原始标注口径。拿一张图对应的 XML 打开看标注的具体内容结构如下annotation folderimages/folder filenamekong-29-_jpg.rf.9cd17aec4f296710e6d97856d96ce807.jpg/filename size width640/width height640/height depth3/depth /size object namekong/name bndbox xmin120/xmin ymin85/ymin xmax420/xmax ymax520/ymax /bndbox /object /annotation这里有个关键点要注意图片尺寸是 640×640。很多频射检测的原始频谱图是宽幅的长宽比接近 2:1 甚至更高这份数据集统一 reszie 到了 640×640 正方形。好处是训练时不需要额外做 letterbox 适配坏处是原始信号的时频分辨率被压缩了——如果原图是 1280×512压缩后频域上的细节会损失约一半。后面训练时如果发现小目标短时突发的干扰信号检不出来先怀疑这个 reszie 操作。2.3 标注数据的边界框是在框什么频射信号检测数据集的标注对象和常规的目标检测有本质区别。常规检测框的是「物体」频射检测框的是「信号在时频图上的能量聚集区域」。频谱图本身就是二维的横轴是时间纵轴是频率像素亮度对应信号强度。无人机图传信号在频谱图上会呈现为一条连续的亮带——因为跳频图案会在特定频段内来回跳变形成带状或点状分布。标注框的xmin/xmax对应的是信号的起始和结束时间点ymin/ymax对应的是信号占用的频率范围。比如一个框从 (120, 85) 到 (420, 520)意思是该信号在时间轴的第 120 到 420 个像素区间内出现频率范围覆盖第 85 到 520 行像素。这个框的宽高比反映了信号的特征宽而扁的框说明是宽带信号窄而高的框说明是窄带持续信号斜着的带状框说明是扫频信号。3. Pascal VOC 标注格式XML 里到底存了什么、够不够用3.1 VOC 格式的字段拆解从 annotation 到 objectPascal VOC 格式是目标检测领域最通用的标注格式之一这份数据集选它是有道理的。它的 XML 结构分为三层第一层是图像元信息包括folder所在目录、filename文件名、path可选完整路径、source图片来源通常是标注软件或数据集的来源描述。这一层主要用来管理数据训练时一般只读取filename。第二层是size字段记录图像的width、height和depth通道数。这个字段在后续做坐标归一化时是必须的——YOLO 格式需要把绝对像素坐标转换成相对于图像宽高的比例值没有这个字段无法完成转换。第三层是object字段这是核心。每个object代表一个标注目标包含name类别名、pose拍摄姿态可选、truncated是否被截断取值 0 或 1、difficult是否难例取值 0 或 1、bndbox边界框坐标包含xmin/ymin/xmax/ymax四个值。对于频射信号检测这个场景truncated和difficult两个字段需要特别注意。truncated1意味着信号延伸到了图片边缘被截断这种样本在频射场景下很常见——一个信号从频谱图左边缘开始就一直持续到右边缘属于完整的持续信号而非被裁切在标注时容易归类错误。difficult1意味着该目标即使在人工标注时也难确定边界——频射信号的边界本来就是渐变的不像人、车那样边界清晰这个字段在训练时通常会被忽略但统计 mAP 时可以选择是否计入。3.2 一份合格的频射信号 XML 标注长什么样一个完整的频射信号标注 XML 文件理想情况下应该是这样的annotation folderimages/folder filenameMini3Pro_5-8GHZ-6-_jpg.rf.c9651ebbaa817b0aec20839ff8022921.jpg/filename source databasedrone-rf-dataset/database annotationRoboflow/annotation /source size width640/width height640/height depth3/depth /size segmented0/segmented object nameMini3Pro/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin95/xmin ymin47/ymin xmax553/xmax ymax601/ymax /bndbox /object /annotation这个 XML 描述的是一个属于Mini3Pro类别的频射信号边界框从 (95, 47) 到 (553, 601)几乎覆盖了整个图片区域。在实际的频谱图里这种大框往往意味着图传信号的基频和谐波同时被框进去了——比如 5.8GHz 主信号在某个高度二次谐波在另一个高度但标注时把它们合并成了一个目标。这里存在一个标注口径问题同一份数据在不同标注口径下的用法完全不一样。如果你训练的是「有没有无人机信号」的二分类检测器大框合并没问题但如果你要做「区分主频和次谐波」的多目标精细化检测这份标注就不够用了需要自己重新标注。拿到数据集后先去可视化几张标注框确认口径符合你的任务再开始训练这个步骤不能省。3.3 为什么选择 VOC 而不是 COCO 或 YOLO 格式数据集作者选择 VOC 格式而非 COCO 或 YOLO 的 TXT 格式核心原因在于灵活性和转换无损性。YOLO 格式的标注是纯文本每行一条记录格式为class_id x_center y_center width height四个坐标值都是相对于图像宽度和高度的比例。这个格式最大的问题是精度损失——坐标值在小数点后保留 6 位对于 640×640 的图片6 位小数的精度足够但如果原始标注的边界框非常小比如只有几个像素宽的窄带信号转换成比例值后会因为浮点精度丢失部分位置信息。COCO 格式的 JSON 结构在组织复杂标注时更有优势但手动编辑和检查相对麻烦。频射信号检测的场景里标注人员经常需要批量修改——比如统一把某个频段的信号框从drone改为Mini3Pro或者调整所有框的上下边界以适配新频段XML 的可读性和可脚本化处理能力比 JSON 更好。此外VOC 格式是标注工具 LabelImg 的原生格式数据集作者大概率是用 LabelImg 完成初标然后导入 Roboflow 做了预处理。标过数据的人都懂标注工具的选型有时候不完全是技术决策它跟标注团队的工作习惯强绑定。VOC 格式的兼容性最广后续无论是转 YOLO、转 COCO、还是直接用 Detectron2 或 MMDetection 训练都有现成的转换工具。4. 把 VOC 转成 YOLO 格式转换脚本与训练集划分4.1 通用转换脚本从 XML 到 TXT 标注文件如果你打算用 YOLOv8 或 YOLOv5 训练第一步就是把 VOC 格式转换成 YOLO 的 TXT 格式。下面是转换脚本的核心部分import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_file, class_names, output_dir): 将单个Pascal VOC XML标注文件转换为YOLO格式TXT文件 tree ET.parse(xml_file) root tree.getroot() size root.find(size) width int(size.find(width).text) height int(size.find(height).text) yolo_lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: print(f警告: {name} 不在类别列表中跳过) continue class_id class_names.index(name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 边界检查防止标注越界 xmin max(0, min(xmin, width)) xmax max(0, min(xmax, width)) ymin max(0, min(ymin, height)) ymax max(0, min(ymax, height)) # 归一化到 [0, 1] x_center ((xmin xmax) / 2) / width y_center ((ymin ymax) / 2) / height box_width (xmax - xmin) / width box_height (ymax - ymin) / height yolo_lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {box_width:.6f} {box_height:.6f}) # 输出文件与XML同名后缀改为txt output_path Path(output_dir) / (Path(xml_file).stem .txt) with open(output_path, w) as f: f.write(\n.join(yolo_lines)) return len(yolo_lines)脚本逻辑拆开看核心是两次坐标变换。第一次从(xmin, ymin)和(xmax, ymax)计算出中心点坐标((xminxmax)/2, (yminymax)/2)和框的宽高(xmax-xmin, ymax-ymin)第二次把像素值除以图片宽高完成归一化。边界检查那个步骤很关键——我见过不少数据集里的标注框微微超出图片边界不夹紧的话后面训练时 loss 直接爆炸到 NaN。类别的顺序你需要自己定义并保持一致比如classes.txt里第一行是kong第二行是Mini3Pro那代码里的class_names [kong, Mini3Pro]必须严格对应。训练时 YOLO 读取的类别索引是从 0 开始的一旦类别顺序和classes.txt对不上所有框的位置对了但类别全错模型训出来就是废的。4.2 数据集划分按图像级切分而不是按框级切分频射信号数据集有一个特殊性相邻时间窗口的频谱图高度相似如果随机切分训练集和验证集会出现数据泄漏——训练集里的图和验证集里的图可能来自同一段连续信号导致验证指标虚高。安全的切分方式是按信号产生批次来划分。比如kong系列和Mini3Pro系列各占一部分切分时保证同一台无人机、同一次采集的样本不要同时出现在训练集和验证集里。如果数据集本身没有采集批次信息退而求其次的做法是按文件名的前缀分组后切分import random import shutil from pathlib import Path def split_dataset(image_dir, train_ratio0.8, val_ratio0.2, seed42): 按文件名前缀分组切分数据集避免数据泄漏 random.seed(seed) # 按前缀分组前缀相同视为同一采集批次 groups {} for img_path in Path(image_dir).glob(*.jpg): # 取第一个下划线前的内容作为分组标识或直接用完整文件名 prefix img_path.name.split(_)[0] groups.setdefault(prefix, []).append(img_path) train_files [] val_files [] # 每个组内按比例切分 for prefix, files in groups.items(): random.shuffle(files) split_idx int(len(files) * train_ratio) train_files.extend(files[:split_idx]) val_files.extend(files[split_idx:]) return train_files, val_files注意里面有keywords[dataset,train,val,split]在脚本里其实没用到但这个split_dataset方法的关键在于同一前缀的文件要么大部分在训练集要么大部分在验证集避免同一信号段的相邻频谱图同时出现在两边。这个操作比单纯随机切分多花两分钟但对最终模型在真实场景的泛化能力有决定性影响。频射信号的时间相关性比普通图像强得多——同一段信号前后帧的频谱图差异极小模型如果靠记忆相似图而不是真正学习信号特征验证集上的 mAP 会好看一到现场就露馅。划分完毕后生成对应的目录结构dataset/ ├── train/ │ ├── images/ │ │ ├── kong-29-_jpg.rf.xxx.jpg │ │ └── ... │ └── labels/ │ ├── kong-29-_jpg.rf.xxx.txt │ └── ... └── val/ ├── images/ │ └── ... └── labels/ └── ...然后写一个data.yaml给 YOLO 用path: ./dataset train: train/images val: val/images nc: 2 names: [kong, Mini3Pro]4.3 LabelImg 打开数据集二次标注实操技巧如果你需要调整或增补标注通常用 LabelImg 打开这份数据集。LabelImg 的安装和使用一套流程比较成熟常见做法是 pip 安装后直接启动。要注意设置自动保存模式另外如果要做的是增补标注而不是全量重标可以采用增量训练的方式。pip install labelimg labelimg ./dataset/train/images ./dataset/train/labels --classes ./dataset/classes.txt参数说明第一个路径指向图片目录第二个路径指向标注输出目录--classes指定类别清单文件。打开后按w键画框按ctrls保存快捷键熟悉一下就能开工。实际操作中频射信号频谱图的边界比自然图像模糊不少画框时容易纠结。我的习惯是宁大勿小——把信号的能量主瓣画进去旁瓣如果和主瓣连通就一并框入只框核心能量区间不把噪声底部算进去。这个标准和自然图像的目标检测标准不同但和信号检测的物理意义更吻合。如果对标注质量心里没底可以利用 LabelImg 的自动保存和标注计数功能每标注 50 张图检查一次类别数量分布发现采样偏差及时校正。5. 避坑与踩坑记录频射信号训练数据集实战问题5.1 数据集类别分布不均少的那一类训崩了现象统计数据集发现kong系列的图片数量远多于Mini3Pro大约 3:1 的比例。训练时kong类别的 mAP 到了 96% 而Mini3Pro只有 78%总体的平均识别率勉强到 94.3%但实际诊断发现是样本量差异导致的偏差。原因类别数量不均其实不是根本问题根本问题出现在信号特征的可区分性上。Mini3Pro和kong在 5.8GHz 频段的频谱图形态差异并不像猫和狗那么大尤其是部分穿越机也使用了类似 OcuSync 的调制方式后两类信号在时频图上可能呈现相似的跳频图案。样本少的那一类学不到足够的判别特征预测结果自然偏向样本多的一侧。解决第一选择是数据增强——对Mini3Pro类的样本做水平翻转、随机裁剪、加噪配合 OpenCV 的频谱特征变换提高该类样本数量占比。增长之后重新统计训练集和验证集有条件的话扩充低价位小飞机的真实采集数据。第二种是调整损失函数的权重策略新版 YOLO 支持在data.yaml里配置类别权重给样本少的类别更高权重。前一种方案能根本上改善泛化后一种只是让指标好看优先做前一种。5.2 坐标归一化后模型 loss 异常标注越界在作怪现象用数据集的原始 XML 转换出 YOLO 格式后训练loss 曲线在第二个 epoch 后开始出现周期性尖峰batch 之间 loss 值从 0.05 直接跳到 3.8 然后又恢复正常。在验证集上单类别 AP 反而比多类别更高且框数量忽多忽少。原因检查转换出的 TXT 标注发现部分标注框的坐标已经超出[0, 1]范围比如x_center是 1.032 或者width是 1.15。这些异常值来自原始 XML 里边界框本身就超出了图片范围或者转换脚本里没有做边界检查与坐标压缩宽高为负数也能被写入 TXT。YOLO 在计算损失时对越界框做 clamp但 loss 的 NaN 尖峰就是从这些越界样本来的。解决转换前额外增加一步验证遍历所有 XML 文件用xmin xmax and ymin ymax以及0 xmin width和0 ymin height四个条件过滤异常样本。我处理时会在数据集中筛出约 12 张越界图片全部做裁剪修正。排查时可以在转换脚本里即时打印坐标异常的框先将这批文件列清单再人工决定是裁掉还是修正边界——直接删除样本是最省事的方案但如果越界只发生在框的右下角几像素修一下边界就行不用整张图报废。5.3 频谱图宽高比被强制拉伸信号形态失真现象使用该数据集在 RT-DETR 上没有做任何改动直接训练验证集 mAP 有 92%但把这个模型拿到实际频谱采集设备上做推理检测率跌到了 71%且大多是漏检。原因排查发现数据集的 640×640 正方形图是 Resize 操作产生的如果原图是 2560×1024 这类宽幅频谱图等比例缩放成 640×640 相当于垂直方向拉伸了 1.6 倍信号在频谱图上的斜率、带宽、持续时间这些时频特征被扭曲了。模型学到的是「被拉伸后的信号形态」到现场看原生宽幅频谱图时特征分布对不上。解决落地推理阶段按照训练尺寸预处理不要在推理时使用原图分辨率。更彻底的做法是把这份数据集作为预训练基础然后用你自己采集的宽幅频谱图做二次训练二次训练时保持图片的原始宽高比仅做 padding 而不是拉伸让模型在真实分辨率分布上重新拟合一遍。从这个案例得到的教训是任何公开数据集都只是起点拿到后先搞清它预处理的细节——resize 的插值方式、是否 letterbox、是否改变宽高比这些都直接影响下游模型的泛化能力。5.4 部分标注框的类别标签混用kong 类和 Mini3Pro 类标注串了现象把数据集的验证集单独跑一遍可视化发现有三张图中的标注框类别和实际信号形态对不上明显是跳频图案的框打上了Mini3Pro的标签但这类跳频的图案更接近kong系列。这三张图对接下来的训练影响不大但对提交结果和对齐指标造成困扰。原因频射信号在频谱图上的观察很大程度上依赖经验标注员如果对 OcuSync 和 ELRS 的跳频图案不熟悉会把「所有跳频信号」当成同类目标。而且 Roboflow 在导出时如果做过了数据增强同一条信号的多个增强副本可能被分配了不同的类别标签。解决用 LabelImg 打开验证集全部图片做一遍快速复查重点看信号密集区域的框是否正确。操作建议是在data.yaml中将类别名从kong、Mini3Pro换成freq_hopping_drone、fixed_freq_drone——从信号特征角度对类别重新定义从源头规避「只看品牌不看信号形态」的标注偏差。如果严格要按品牌区分就只能对每张图的实际信号做频谱分析比对靠人工肉眼判断容易出错。5.5 素材少只有 364 张图做数据增强的合理策略现象数据集本身只有 364 张原始图片作为深度学习目标检测模型的数据量偏少直接训练容易过拟合验证集过完之后测试集明显掉点训练曲线和验证曲线落差大。原因频射信号检测的数据采集成本比真实图像高——要有频谱仪、要有飞行器、要干扰环境控制所以采集方不愿意大规模做数据集。训练中模型可学习的有效特征过多364 张图的标注信息不足以充分约束模型参数空间过拟合正常。解决常用的做法是先用这份数据集做预训练再叠加频射信号的合成数据扩充样本通过程序生成带噪的时频图做增量训练。另一种更保险的做法是迁移学习用公开的 RadioML 2018.01A 数据集先做信号分类的预训练再把特征迁移到目标检测上。如果是纯视觉频谱图检测还可以使用 Denoising Autoencoder 对未标注频谱图做特征提取之后接检测头这种做法在很多频射检测项目中实际效果不错。数据增强方面注意不要用马赛克增强Mosaic 会把四张频谱图拼在一起信号在拼接边界上的特征被强行截断引入大量伪目标严重影响检测器性能。6. 验证训练结果把 94.3% 准确率复现出来并确认模型真的能用6.1 训练曲线怎么判断是否正常用这份数据集跑 YOLOv8 训练时不要只盯着最终 mAP要看训练曲线的走向。正常收敛的曲线应当满足两个特征训练损失和验证损失同步下降并且在最后 30 个 epoch 内验证损失不再有明显回升同时验证集的 Precision 和 Recall 曲线在 92%96% 之间稳定波动而不是大起大落。执行一次标准训练的命令如下yolo detect train \ data/path/to/data.yaml \ modelyolov8s.pt \ epochs200 \ imgsz640 \ batch16 \ patience30 \ save_dir/path/to/runs/train参数说明modelyolov8s.pt表示加载 COCO 预训练权重频射信号频谱图和 COCO 的自然图像差异较大加载预训练的好处是底层特征提取器能更快收敛但如果你实测下来预训练权重反而拖慢收敛就改成yolov8s.yaml从零训练。patience30表示验证损失连续 30 个 epoch 不下降就提前终止这套数据如果配置没问题通常 120 epoch 左右就能收敛到稳定值。要复现 94.3% 这个指标需要关注一个细节数据集的划分方式。如果数据源在划分时把同一批信号源的数据可能拆到了训练集和验证集你复现出来的 mAP 会高于实际情况。用我前面给的按前缀分组切分方法重新划分mAP 落在 92%95% 之间是正常的。如果大幅低于 92%优先检查标注转换后是否有空标注文件或类别索引错误。6.2 可视化中间层与边界框分布确认模型学到的是信号特征训练完成后别急着部署做两件验证工作。第一件是用混淆矩阵确认两个类别的区分度。在 YOLO 训练输出目录下找到confusion_matrix.png重点看kong和Mini3Pro两个类别的交叉混淆比例。我跑过一次的结果是 6.7% 的kong样本被预测成了Mini3Pro排查发现是某些跳频图案确实无法靠注意力区分于是对这部分样本做了纹理增强来微调。第二件是用 Grad-CAM 类激活图查看模型关注的是否是信号能量集中区域。用下面的轻量脚本对某张验证图片做激活图输出import torch import cv2 import numpy as np from ultralytics import YOLO model YOLO(/path/to/best.pt) img cv2.imread(/path/to/val_image.jpg) results model.predict(img, saveFalse) # 取最后一个卷积层的梯度作为激活权重 target_layer model.model.model[-2] gradients torch.autograd.grad( outputsresults[0].boxes.conf.mean(), inputstarget_layer.output, retain_graphTrue )[0] weights gradients.mean(dim(2, 3), keepdimTrue) cam (weights * target_layer.output).sum(dim1).squeeze().detach().numpy() cam cv2.resize(cam, (img.shape[1], img.shape[0])) cam np.maximum(cam, 0) / np.max(cam) overlay cv2.applyColorMap((cam * 255).astype(np.uint8), cv2.COLORMAP_JET) blended cv2.addWeighted(img, 0.6, overlay, 0.4, 0) cv2.imwrite(/path/to/cam_result.jpg, blended)这段代码的作用是计算模型对检测框内目标的关注区域并输出叠加了热力图的图片。正常训练出来的频射检测模型热力图的亮区应当集中在频谱图上的信号带区域而不是背景噪声或坐标轴位置。如果热力图分散在整张图上说明模型在用纹理统计特征硬凑没有学到信号的时频结构要回到数据增强和网络结构选择上排查。6.3 自建验证集做交叉检查对比指标差异最后一个方法是腾出一小段时间自己采集三五个新的频谱样本加入验证集——不参与训练只参与衡量最终模型指标。参考样本里混一台未曾出现在数据集中的无人机观察模型能否检测出来并正确分类。结果通常呈现两种走向如果是基于跳频图案和带宽特征学的模型跨机型表现比较稳定如果是仅仅记住了几类无人机的频段分布特征跨机型换频段就容易失败。每次我拿到一份新数据集都会先跑一遍完整校核流程解压、统计类别分布、检查 XML 绑定、做前缀分组切分、转 YOLO、训练一个最小配置模型再跑一次上面的 Grad-CAM 可视化。整套做完才会真正用这也是我踩过太多坑之后养成的习惯。希望你这次能一次跑顺。本文还有配套的精品资源点击获取
返回列表