ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

无人机频射信号数据集实战:YOLOv5训练与94.3%识别率复现

无人机频射信号数据集实战:YOLOv5训练与94.3%识别率复现 简介这份资源面向从事无人机侦测、频谱感知与目标识别方向的研究者与工程人员提供了一套可直接用于模型训练的无人机频射信号检测数据集帮助解决信号样本采集难、标注成本高的问题。压缩包共729个文件约136.82MB其中364张jpg原始图像与364个同名txt标注文件一一对应另含1个yaml配置文件用于定义数据集路径与类别信息标注格式兼容yolov5可直接接入主流检测框架训练。数据覆盖多类无人机频射信号场景图像命名中可见kong、Mini3Pro等不同机型与频段标识便于按类别划分训练集与验证集。据描述基于该数据集的平均正确识别率可达94.3%已有452人学习下载说明其在同类任务中具备一定参考价值。读者可据此快速复现检测流程、验证算法改进效果或作为频射信号视觉化识别研究的基线数据使用。1. 364 张图、94.3% 识别率这份无人机频射信号数据集到底能不能直接开训拿到一份标注好的无人机频射信号数据集第一反应通常不是兴奋而是怀疑——364 张原始图片平均正确识别率标称 94.3%支持 YOLOv5 格式标注这几个数字放在一起到底是真能跑通还是又一个看着很美、训起来翻车的坑我拆过不少信号检测类数据集说实话大部分公开资源要么标注格式对不上要么样本分布极度偏斜要么图片本身质量参差到模型根本学不到东西。这份数据集的价值在于它把频射信号检测这个相对小众的任务直接落到了 YOLOv5 能吃的格式上省掉了从信号频谱图到目标检测标注之间最耗时的转换环节。它适合两类人一是做无人机侦测、频谱监测方向的研究生和工程师需要快速验证检测方案二是想拿一个真实信号数据集练手 YOLOv5 完整流程的开发者。文件名里能看到 kong 系列和 Mini3Pro 5-8GHZ 这样的标识说明数据覆盖了不同机型、不同频段的信号样本不是单一来源凑数。2. 频射信号检测任务拆解从频谱图到 YOLOv5 标注框2.1 频射信号为什么能当目标检测来做频射信号检测的本质是从无线电频谱中判断有没有无人机信号、在哪个频点、占多宽带宽。传统做法是能量阈值法或者循环平稳特征检测但这些方法在低信噪比、多信号混叠的场景下误报率很高。把频谱数据转成时频图spectrogram之后信号在图上就变成了有形状、有位置的目标——这跟 YOLOv5 擅长的在图像里找目标并画框逻辑完全一致。具体来说一段射频采样经过短时傅里叶变换STFT后横轴是时间、纵轴是频率、像素亮度是功率谱密度。无人机图传信号在这张图上通常表现为几条平行的亮带或者跳频图案YOLOv5 要学的就是把这些亮带的位置和范围框出来。这份数据集里的 364 张原始图片大概率就是已经做好的时频图文件名中的.rf.标识也印证了这一点。关键参数在于 STFT 的窗口长度和重叠率。窗口太长时间分辨率不够跳频信号会被糊成一片窗口太短频率分辨率下降窄带信号会散开。常见做法是窗口取 1024 点、重叠 75%这样在 5-8GHz 频段下既能分辨跳频图案又不会丢失窄带细节。数据集已经帮你做好了这一步但如果你要自己补充数据这个参数必须调对。2.2 YOLOv5 标注格式的字段含义与校验方法YOLOv5 用的是 YOLO 格式标注每张图对应一个.txt文件每行一个目标格式是class_id x_center y_center width height其中坐标全部是归一化到 0-1 的值相对于图片宽高。这份数据集如果标注正确每个.txt文件的行数应该和图片里实际信号数量一致。拿到数据后第一件事不是直接开训而是校验标注。import os import cv2 img_dir images/train label_dir labels/train issues [] for fname in os.listdir(img_dir): if not fname.endswith(.jpg): continue img_path os.path.join(img_dir, fname) label_path os.path.join(label_dir, fname.replace(.jpg, .txt)) img cv2.imread(img_path) if img is None: issues.append(f{fname}: 图片读取失败) continue h, w img.shape[:2] if not os.path.exists(label_path): issues.append(f{fname}: 缺少标注文件) continue with open(label_path) as f: lines f.readlines() if len(lines) 0: issues.append(f{fname}: 标注文件为空) continue for i, line in enumerate(lines): parts line.strip().split() if len(parts) ! 5: issues.append(f{fname} 第{i1}行: 字段数不对 ({len(parts)})) continue cls_id, xc, yc, bw, bh parts vals [float(xc), float(yc), float(bw), float(bh)] if any(v 0 or v 1 for v in vals): issues.append(f{fname} 第{i1}行: 坐标越界 {vals}) if float(bw) 0 or float(bh) 0: issues.append(f{fname} 第{i1}行: 宽高非正 {bw}, {bh}) print(f共发现 {len(issues)} 个问题) for issue in issues[:20]: print(issue)这段脚本做四件事检查图片能否正常读取、标注文件是否存在、每行字段数是否为 5、归一化坐标是否在 0-1 范围内且宽高为正。跑完如果问题数超过总图片数的 5%说明标注质量堪忧需要人工复核。364 张图的规模全量校验也就几秒钟的事别省这一步。2.3 数据集划分与 data.yaml 配置YOLOv5 训练需要一份data.yaml指定训练集、验证集路径和类别信息。364 张图按 8:1:1 划分训练集约 291 张、验证集 36 张、测试集 37 张。如果类别只有无人机信号一类配置很简单# data.yaml path: ./drone_rf_dataset train: images/train val: images/val test: images/test nc: 1 names: [drone_signal]如果数据集里区分了不同机型或不同频段从文件名看 kong 和 Mini3Pro 可能是不同类别nc和names要对应调整。类别数不对是训练报错最常见的原因之一names列表长度必须等于nc且类别 id 从 0 开始连续编号。提示划分时注意同一架次、同一时段的信号图片不要同时出现在训练集和验证集里否则验证指标会虚高。按文件名前缀分组划分比随机划分更靠谱。3. YOLOv5 训练全流程从环境搭到第一轮推理3.1 环境准备与依赖版本锁定YOLOv5 对 PyTorch 和 CUDA 版本比较敏感版本不匹配轻则报错、重则训练中途 loss 变 NaN。我一般用 conda 建独立环境锁定以下组合conda create -n drone_rf python3.9 -y conda activate drone_rf # 安装 PyTorch以 CUDA 11.8 为例按自己显卡驱动调整 pip install torch2.0.1 torchvision0.15.2 --index-url https://download.pytorch.org/whl/cu118 # 克隆 YOLOv5 并安装依赖 git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txttorch和torchvision版本必须配套2.0.1 对应 0.15.2差一个小版本就可能出问题。CUDA 版本用nvidia-smi查驱动支持的最高版本不要超过它。装完之后跑一句python -c import torch; print(torch.cuda.is_available())返回 True 才算环境通了。3.2 训练命令与关键超参数设置364 张图属于小数据集直接用默认的 YOLOv5s 预训练权重做迁移学习不要从头训。命令如下python train.py \ --img 640 \ --batch 16 \ --epochs 150 \ --data data.yaml \ --weights yolov5s.pt \ --cfg models/yolov5s.yaml \ --hyp data/hyps/hyp.scratch-low.yaml \ --project runs/train \ --name drone_rf_exp1 \ --cache逐项说明--img 640是输入分辨率时频图如果长宽比差异大可以改成--img 640 --rect做矩形推理--batch 16在 8GB 显存下比较稳显存不够降到 8--epochs 150对小数据集够用配合早停机制--patience 30防止过拟合--weights yolov5s.pt加载 COCO 预训练权重即使任务差异大底层特征提取器仍然有用--hyp选 low 增强配置因为时频图不像自然图像那样需要大幅色彩抖动过度增强反而会破坏信号结构。训练过程中重点盯三个指标box_loss是否稳定下降、mAP0.5是否在 50 个 epoch 后开始收敛、val/box_loss和train/box_loss的差距是否持续扩大。如果验证 loss 早早开始上升说明过拟合了减 epoch 或者加 dropout。3.3 推理验证与识别率复现训练完成后用detect.py跑推理验证标称的 94.3% 识别率python detect.py \ --weights runs/train/drone_rf_exp1/weights/best.pt \ --source ./drone_rf_dataset/images/test \ --img 640 \ --conf 0.25 \ --iou 0.45 \ --save-txt \ --project runs/detect \ --name test_result--conf 0.25是置信度阈值低于这个值的检测框被丢弃--iou 0.45是 NMS 的 IoU 阈值控制重叠框合并。这两个参数直接影响召回率和误报率的平衡。如果发现漏检多降--conf到 0.15如果误报多升到 0.4。--save-txt会把检测结果存成 YOLO 格式方便和标注文件做对比算指标。要复现 94.3% 这个数字需要明确它指的是什么指标——是 mAP0.5、还是 top-1 分类准确率、还是某种自定义的识别率。如果是 mAP0.5直接看训练日志最后一轮的输出如果是分类准确率需要把检测结果按图片级别做投票。不同定义下数字差异可能很大别被单一数字带偏。4. 避坑与排查小数据集训练频射信号检测的五个血泪教训4.1 现象训练 loss 正常下降但 mAP 始终为 0原因通常是类别 id 不匹配。YOLOv5 要求标注文件里的 class_id 从 0 开始且必须小于data.yaml里的nc。如果标注文件里出现了 class_id 为 1 但nc设成了 1只有类别 0所有该类目标会被忽略mAP 自然为 0。解决跑一遍校验脚本统计所有出现过的 class_id确保最大值小于nc且names列表覆盖所有 id。4.2 现象验证集指标远高于训练集指标这是小数据集的典型反直觉现象。原因通常是验证集太小36 张且和训练集分布过于接近导致指标虚高。另一个可能是验证集里目标数量少少数几个简单样本拉高了平均值。解决用 k 折交叉验证代替单次划分或者把验证集比例提高到 20%。同时检查验证集里是否包含训练集里没有的信号类型。4.3 现象推理时同一信号被反复框出多个框NMS 的 IoU 阈值设太高了。频射信号的时频图里同一个信号可能因为功率波动被检测成多个相邻框如果--iou设成 0.7这些框不会被合并。解决把--iou降到 0.3-0.45 之间或者在训练时调整hyp里的box损失权重让模型学到更紧凑的框。4.4 现象训练到一半 loss 突然变 NaN学习率太高或者 batch 里有异常样本。频射信号数据集里如果混入了全黑或全白的时频图梯度会爆炸。解决先把学习率降到 0.001默认是 0.01加--cos-lr用余弦退火。同时用校验脚本筛掉像素均值接近 0 或 255 的图片。4.5 现象换一台机器推理结果不一致PyTorch 版本不同导致 NMS 实现有差异或者图片预处理归一化参数不一致。YOLOv5 默认用 ImageNet 的均值和方差做归一化如果推理时用了不同的预处理结果会偏。解决锁定推理环境的 torch 版本和 YOLOv5 commit推理脚本直接用仓库自带的detect.py不要自己重写预处理。5. 进阶技巧用 TTA 和模型集成把识别率再往上推当你把基础训练跑通、确认数据标注没问题之后如果 94.3% 还不够用有两个性价比最高的提升手段测试时增强TTA和轻量模型集成。TTA 的思路是在推理时对同一张图做多种变换水平翻转、多尺度缩放把多次推理结果合并。YOLOv5 的detect.py自带--augment参数python detect.py \ --weights runs/train/drone_rf_exp1/weights/best.pt \ --source ./drone_rf_dataset/images/test \ --img 640 \ --augment \ --conf 0.25 \ --iou 0.45--augment会同时跑原图、翻转图、缩放图然后做加权框融合WBF。代价是推理速度降到原来的 1/3 左右但 mAP 通常能涨 1-3 个百分点。对于 364 张图的测试集多花几秒完全值得。模型集成则是训练两个不同配置的模型比如 YOLOv5s 和 YOLOv5m或者不同随机种子的 YOLOv5s推理时把两组检测框用 WBF 合并。我一般会这样做from ensemble_boxes import weighted_boxes_fusion # 假设 boxes_list 和 scores_list 来自两个模型的推理结果 # labels_list 对应类别 id iou_thr 0.45 skip_box_thr 0.25 boxes, scores, labels weighted_boxes_fusion( boxes_list, scores_list, labels_list, weights[1, 1], iou_thriou_thr, skip_box_thrskip_box_thr )weights控制每个模型的投票权重如果某个模型在验证集上明显更好可以给它 1.5 的权重。iou_thr和单模型 NMS 含义一致skip_box_thr是最终输出的置信度门槛。还有一个容易被忽略的点频射信号检测的评估不能只看 mAP。实际部署时更关心的是在固定虚警率下的检测概率或者单位时间内的误报次数。建议在测试集上画一条 ROC 曲线看看在虚警率 1% 时召回率能到多少。这个数字比 mAP 更能反映实战表现。从那以后我每次拿到新的信号数据集都会先跑一遍标注校验、再画一张类别分布直方图、最后用 10% 的数据做一次快速过拟合测试——如果模型连 30 张图都过拟合不了那一定是数据或配置有问题不用浪费时间跑完整训练。希望这份拆解能帮你少走几个弯路。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进