简介:这是一份基于YOLOX的音频事件检测模型工程包,面向有深度学习基础、希望将图像检测框架迁移到音频事件识别场景的开发者。项目使用PyTorch实现,以YOLOX无锚框检测为主体,结合Librosa完成音频特征提取,从数据准备、模型训练到推理评估与导出均有覆盖。压缩包共95个文件,大小约564KB,核心以75个Python脚本为主,另有6个Shell脚本、4个TXT说明文件、2个C++扩展文件,并包含配置文件与图像资源,目录结构清晰,便于阅读代码与快速复现。目前已有60人学习/下载。包内提供多组YOLOX Audio配置样例、COCO格式音频标注生成脚本、音频数据混合工具、ONNX与TorchScript导出脚本、评估脚本,以及Docker运行环境脚本,可帮助读者系统理解YOLOX在音频事件检测中的工程化落地方式,适合作为入门学习或二次开发的参考。
1. 为什么用目标检测模型做音频事件检测
音频事件检测往往被当成时间序列分类来解,很多人第一反应就是堆 LSTM、Transformer,但这套思路对事件边界不敏感,尤其是当多个声音在时间上重叠时,序列模型很难给出精确的起止时间。YOLOX_AUDIO 换了一个视角:把音频转成频谱图,事件在图上就是一块有纹理的亮斑,检测任务天然变成图像目标检测。YOLOX 作为无锚框检测器,不依赖预设 anchor,能更好地覆盖长短差异极大的音频事件。这个 repo 基于 PyTorch 实现,整个训练、评估、导出链路完整,适合需要用现成检测框架解决猪只叫声、枪声、设备异响等固定类别事件检测的工程师,也适合想在音频检测上复用图像预训练权重的团队。
2. YOLOX_AUDIO 的模型结构与数据管线
2.1 从 YOLOX 到 YOLOX_AUDIO:Backbone 与 Head 的复用
YOLOX_AUDIO 没有重新发明网络结构,而是把 YOLOX 的 CSPDarknet 骨架和解耦检测头直接搬过来,只把输入从 RGB 图像换成音频频谱图。项目里models/yolox_audio.py定义了音频版检测模型,models/yolo_pafpn.py负责多尺度特征融合,models/yolo_head.py保留了解耦头和 SimOTA 标签分配。之所以选无锚框,是因为音频事件在频谱图上的宽高比极其多变,一个 200ms 的事件在时间轴上可能只有 10 个像素宽,但在频率轴上却占几十个 bin,预设 anchor 很难覆盖完,无锚框直接回归框坐标反而更稳定。
模型规模上,项目提供了 nano、tiny、s、m、l、x 六种配置,分别对应不同的 depth 和 width。以exps/yolox_audio/yolox_s.py为例,核心参数如下:
# exps/yolox_audio/yolox_s.py from yolox.exp import Exp as MyExp class Exp(MyExp): def __init__(self): super().__init__() self.depth = 0.33 self.width = 0.50 self.input_size = (640, 640) # (height, width) self.num_classes = 5 self.data_dir = "datasets/audio_coco"这里depth是网络层数缩放系数,width是通道数缩放系数,YOLOX-S 对应的是 0.33 和 0.50,X 则对应 1.33 和 1.25。input_size是模型输入分辨率,注意它是 (高, 宽) 顺序,音频频谱图的时间轴对应宽,频率轴对应高。我一般先用 s 规模打通流程,确认数据没毛病后再换 x 提精度,直接上大模型如果数据量只有几千条,很容易过拟合。
2.2 音频转图像:librosa 特征提取与多频谱域
音频特征提取是这套模型能否收敛的关键步骤。项目基于 librosa 把 wav 转成 Log-Mel 频谱图,再作为模型的输入。多频谱域的含义是可以叠加多种特征形成多通道输入,例如梅尔谱、MFCC、一阶差分谱等,让模型同时看到静态能量和动态变化。实际代码里最常见的是单通道 Log-Mel,简单且训练稳定。下面这段是特征计算的典型写法:
import librosa import numpy as np def wav_to_mel(path, sr=16000, n_mels=128, hop_length=512): y, _ = librosa.load(path, sr=sr) mel = librosa.feature.melspectrogram( y=y, sr=sr, n_mels=n_mels, hop_length=hop_length ) log_mel = librosa.power_to_db(mel, ref=np.max) return np.expand_dims(log_mel, axis=0).astype(np.float32) # (1, T, F)先加载音频到指定采样率,然后做 STFT 并映射到梅尔刻度,最后转成对数分贝值压缩动态范围。返回的数组是单通道 2D 特征,最终进入网络前会再补一个 batch 维。为什么不直接用原始波形?因为 YOLOX 的卷积核设计前提是输入具备局部空间相关性,梅尔谱在频率轴上相邻 bin 强相关,时间轴上相邻帧也是平滑变化,直接喂波形等于要求卷积核自行学到时频变换,既慢又容易欠拟合。
特征参数直接决定时间分辨率,需要根据事件类型调整,下表是我在项目里默认使用的参数:
| 参数 | 推荐值 | 影响 |
|---|---|---|
| sr | 16000 | 决定最高可用频率 |
| n_mels | 128 | 频率维度大小 |
| hop_length | 512 | 每帧步长,越小时间分辨率越高 |
| fmin / fmax | 50 / 8000 | 过滤无效频段 |
hop_length越小,频谱图越宽,计算量越大。如果检测的是几十毫秒的短促事件,建议把 hop_length 降到 256,否则事件在时间轴上只有一两个像素,检测头很难给出精确边界。
2.3 音频标签转 COCO 格式:json_gen_audio2coco.py 的作用
YOLOX 的训练循环和评估器都依赖 COCO 格式的 JSON 标注,所以项目提供了json_gen_audio2coco.py和json_gen_audio2coco_nia75.py,把音频时间戳标注转换成 COCO 格式。转换的核心是把秒级时间映射到频谱图上的像素坐标:
def time_to_pixel(ts, sr, hop_length, total_frames, input_width): frame = int(ts * sr / hop_length) x = frame / total_frames * input_width return x这段逻辑假设标注的时间轴和特征提取参数一致。total_frames是当前音频的频谱帧总数,input_width是网络输入宽度,换算后得到归一化坐标再乘以宽度。转换完成后一定要做可视化校验,随机挑几张图,把标注框画在频谱图上,看框是否对准事件亮斑。NIA75 后缀的脚本针对另一个数据集,类别列表和名称可能不同,跑之前先确认name_pigcry5.txt里的类别顺序与生成器的classes一致。
2.4 数据增强与混音:mix_audiodata.py
音频数据增强比图像限制多,直接做 pitch shift 可能改变事件语义,所以项目提供了mix_audiodata.py做混音增强:把背景噪声或不同事件片段按随机信噪比叠加,模拟多声源重叠。混音并不是简单把波形相加,还要做能量归一化防止削波。我一般先生成混音后的音频文件存到磁盘,再同步生成对应的 COCO 标注,而不是在线做,这样训练时报错容易排查。混音时控制信噪比在 0~10 dB 之间比较合理,太小的信噪比会直接把事件淹没在噪声里,模型学到的是噪声模式而不是事件本身。
3. 环境配置与依赖安装:yolox环境配置实战
3.1 用 Docker 还是裸环境
项目仓库带了 Dockerfile、run_docker.sh和update_docker.sh,说明作者推荐容器化。用 Docker 最直接的好处是避开 csrc 编译问题,YOLOX 的fast_coco_eval_api.py需要编译 C++ 扩展,不同 CUDA 版本的 ABI 不兼容,重编译很容易卡住。如果自己搭裸环境,建议基于 PyTorch 官方镜像,然后补系统库:
apt-get update && apt-get install -y libsndfile1 ffmpeglibsndfile1是 librosa 底层加载音频的依赖,缺它会在librosa.load时报RuntimeError。ffmpeg用于读取 mp3、ogg 等非 wav 格式,如果用全是 wav 的数据集也可以不装。这一步很多人忽略,网上大量"librosa 安装失败"的提问最后都栽在这里。
3.2 requirements.txt 与 setup.py 安装
进入项目根目录后,先安装 Python 依赖。requirements.txt 里主要包含 torch、torchvision、librosa、opencv-python、pycocotools。注意 torch 和 torchvision 的版本必须匹配,YOLOX 的老代码对 torchvision 的接口比较敏感,建议按 PyTorch 官方对应关系装,不要直接pip install torch拉最新版。安装流程:
pip install -r requirements.txt python setup.py developsetup.py develop是 YOLOX 的常规安装方式,会编译csrc目录下的 nms、Iou 等扩展,生成可 import 的包。安装完做一次冒烟测试:
python -c "from yolox.models import YOLOXAudio; print('ok')"如果这一步报libcuda.so: cannot open shared object file,说明 CUDA 的 ldconfig 配置不对,需要在~/.bashrc里加export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH。如果编译时报g++: fatal error,检查 gcc 版本,老版本 YOLOX 在 gcc 9+ 上编译某些头文件会失败。
3.3 常见环境问题与排查
这套环境配置里最容易出问题的三处,我按踩坑频率排序。第一,librosa 0.10 之后调整了 resample 接口,老代码里调用librosa.resample(y, old_sr, new_sr)的位置可能报参数不匹配,解决办法是固定librosa==0.9.2,或者改代码适配新接口。第二,pycocotools在 Windows 上经常编译失败,但 YOLOX 的评估强依赖它,建议直接用 Linux 容器,不需要在 Windows 上死磕。第三,训练时一换 batch size 就显存不足,这时不要只降 batch,还要看input_size和n_mels。640x640 的输入在 1080Ti 上能跑 batch 8,但如果把梅尔频带调到 256,显存占用直接翻倍,调参时注意这两个是乘积关系。
4. 训练、评估与推理实战
4.1 用 train_yolox_audio_x.sh 启动训练
项目提供train_yolox_audio_x.sh、run_train.sh等脚本,本质都是调train.py。训练前先准备 COCO 格式数据,然后在实验配置里改data_dir和num_classes。启动命令如下:
python train.py \ -expn yolox_audio_s \ -f exps/yolox_audio/yolox_s.py \ -b 8 \ -d 2 \ -c pretrained/yolox_s.pth \ -max_epoch 100-expn是实验名,所有输出日志和权重会放进runs/yolox_audio_s/;-f指向实验配置;-b是总 batch size;-d是 dataloader 的 worker 数,一般按 CPU 核数的一半设置;-c是预训练权重,建议先下载 YOLOX 在 COCO 上的权重做迁移学习。虽然音频频谱图与自然图像差异不小,但深层特征提取能力可以迁移,尤其是前几层的边缘和纹理卷积核。训练过程中观察 loss 曲线,前 5 个 epoch 如果 loss 不下降,优先把初始学习率从默认的 0.01 降到 0.001,小数据集上 0.01 很容易震荡。
训练过程中会在runs/yolox_audio_s/下生成best_ckpt.pth和last_ckpt.pth,逻辑见core/trainer.py。best_ckpt是根据验证集 mAP 保存的,不要只看训练 loss,音频事件重叠较多时 loss 低不代表框质量高。
4.2 评估:eval.py 与 metric_audio.py
评估时可以用项目自带的eval.py或更针对音频的eval_audio.py。eval.py走的是 COCO 评估流程,输出 mAP、AR 等指标;eval_audio.py更偏向音频事件检测,会按时间跨度匹配去计算事件级准确率。如果你想和其他音频事件检测方法对比,建议以eval_audio.py的结果为准,因为 COCO mAP 对音频事件的时间偏移过于敏感,一个框偏移 50ms 可能 IoU 就不达标,但人耳完全听不出差别。
python eval_audio.py \ -f exps/yolox_audio/yolox_s.py \ -expn yolox_audio_s \ -c runs/yolox_audio_s/best_ckpt.pth \ -b 4 \ -d 1评估时脚本会加载验证集,对每条音频生成频谱图,推理得到预测框,再用metric_audio.py里的方法计算指标。注意验证集的特征参数必须与训练一致,比如训练时hop_length=512,验证时却用了 256,框的时间坐标会整体偏移。另一个常踩的坑是 NMS 阈值,YOLOX 默认nms_thr=0.65,音频事件之间重叠比图像目标小,很多事件时间上紧挨着,建议在实验配置里把nms_thr提到 0.7,能减少漏检。
4.3 音频推理:infer_audio.py 与 demo_audio.py
infer_audio.py用于单文件推理,demo_audio.py适合跑实时流或批量文件。推理流程和训练前处理完全一致,核心代码如下:
import torch from yolox.exp import get_exp from yolox.utils import postprocess exp = get_exp("exps/yolox_audio/yolox_s.py") model = exp.get_model() ckpt = torch.load("runs/yolox_audio_s/best_ckpt.pth") model.load_state_dict(ckpt["model"]) model.eval() log_mel = wav_to_mel("test.wav") # (1, T, F) with torch.no_grad(): outputs = model(torch.from_numpy(log_mel).unsqueeze(0))这里outputs是 YOLOX head 的原始输出,需要经过postprocess解码得到预测框和类别。推理结果中的坐标是在模型输入分辨率上的像素值,要映射回真实时间秒数,必须用公式t_second = x * hop_length / sr。这也是新手最容易出 bug 的地方:直接拿 x 当成高频帧索引,或者忘记除以输入缩放比例,导致推理出的时间段与音频实际时间完全对不上。demo_audio.py内部已经处理了这个换算,看代码时重点找这一行。
5. 导出与部署:ONNX、TorchScript、TensorRT 与剪枝
5.1 用 export_onnx.py 导出 ONNX
服务端部署通常需要 ONNX。项目提供export_onnx.py,用法很简单:
python export_onnx.py \ -f exps/yolox_audio/yolox_s.py \ -c runs/yolox_audio_s/best_ckpt.pth导出后先用onnxruntime做一次推理,和 PyTorch 结果对比,最大误差应在 1e-3 以下。如果误差偏大,多半是模型里的 BN 层在 eval 模式下没有冻结,或opset版本太低。注意导出的模型输入 shape 固定为静态值,如果希望支持任意长度的音频频谱图,需要在导出时设置动态时间轴,否则一次只能处理固定时长,对长音频会直接报维度错误。
TensorRT 则用项目里的trt.py,它负责把 ONNX 转成 TensorRT engine。转换时优先开启 FP16,音频检测任务对精度损失容忍度比图像检测高,FP16 通常只掉 0.5 个点 mAP,但推理速度能翻倍。转换后要验证输入输出的 dtype,TensorRT 的输入要求 float32 或 float16 的 contiguous 数组,直接用 numpy 默认的 float64 会报错。
5.2 TorchScript 导出与 C++ 部署
export_torchscript.py导出 TorchScript,方便接入 libtorch 的 C++ 服务端。导出的模型是一个 TorchScript module,C++ 端只要加载.pt文件即可。但要注意频谱图的特征提取仍然依赖 librosa,这部分建议在 C++ 侧用其他库实现,或把它独立成预处理服务。我一般做法是:C++ 端接收 wav 字节流,用librosa更底层的算法重写 Mel 频谱计算,把结果转成 tensor 再喂给 TorchScript 模型,这样推理链路可以完全脱离 Python。
5.3 剪枝与模型压缩:pruning.py
项目带pruning.py,实现了 YOLOX 官方基于 BN 缩放因子的结构化剪枝。剪枝前先正常训练到收敛,然后跑:
python pruning.py \ -f exps/yolox_audio/yolox_s.py \ -c runs/yolox_audio_s/best_ckpt.pth \ -prune_ratio 0.3prune_ratio控制裁剪通道比例。音频频谱图的一大特点是静音频带的通道存在大量冗余,所以剪枝对音频检测尤其有效。剪枝完必须重新微调至少 20 个 epoch,否则 mAP 会断崖式下跌。微调时建议把基础学习率设为原来的十分之一,同时冻结 backbone 前几层,只训练剪枝影响较大的 head 部分。最终模型大小和时间要实测对比,只减参数量但不掉点的剪枝比例一般控制在 0.3 以内,超过 0.5 基本都要付出明显精度代价。
本文还有配套的精品资源,点击获取