恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
FunASR 实战:一条 SOND 数据预处理流水线,从原始波形到说话人分离特征
首页
资讯中心
/
FunASR 实战:一条 SOND 数据预处理流水线,从原始波形到说话人分离特征
FunASR 实战:一条 SOND 数据预处理流水线,从原始波形到说话人分离特征
发布时间:2026/9/7 23:25:33
FunASR 实战一条 SOND 数据预处理流水线从原始波形到说话人分离特征【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASR在 FunASR 中SONDSpeaker Overlapping Noise Detection模型要在多人抢话、环境嘈杂的音频上输出谁在什么时候说话。本文跟随一段原始音频走完它的预处理流水线16kHz 重采样、80 维梅尔频谱提取、SpecAugment 增强、utterance 级归一化与 VAD 定位并给出可直接套用的训练/推理配置建议。三种难缠的声音会议录音里发生了什么想象一场真实会议两个人同时开口背景空调低频轰鸣录音设备还是三个月前用旧手机拍的底噪比新设备高出不止一点。这段音频丢进任何 ASR 前端都会同时撞上三类问题。先说重叠。两人同时发声时波形是两条语音的直接叠加能量、基频互相干扰——模型不能只学听清一个声音还得学会把混在一起的声音拆开、分清归属。再说噪声。空调嗡鸣、键盘敲击在频谱上是一片连续的暗纹覆盖几乎所有频带特征稍有不慎就会被噪声主导。最后是设备差异采样率、音量、底噪各不相同同一段内容换台设备录特征分布就漂了一大截。SOND 的定位就是专治这三件事重叠感知 噪声容忍 跨设备鲁棒。而它的第一块基石是数据预处理。全景图一段音频要闯哪些关卡FunASR 把 SOND 的预处理拆成了五道关卡训练和推理在第三关分叉——这是最容易配错的地方下面按关卡顺序展开每个环节回答为什么这么做、参数怎么定。关卡 1怎么把不同设备的音频拉进同一套坐标系清单驱动加载。训练数据用 Kaldi 风格的wav.scp管理每行一条utterance ID 音频路径仓库里就有现成样例可看data/list/train_wav.scp。# wav.scp 每行一条utterance ID 空格 音频路径 # 例如meeting_0001 /data/audio/meeting_0001.wav with open(wav.scp, r, encodingutf-8) as f: for line in f: utt_id, wav_path line.strip().split(maxsplit1) # 加载并转成单声道 float 张量得到 (1, samples) wav, sr torchaudio.load(wav_path)采样率统一。前端的一切频域计算都按 16kHz 标定44.1kHz 的音乐录音或 8kHz 的电话音进来后必须先重采样否则梅尔滤波器组的频率边界整体错位from torchaudio.sox import ApplyEffect # 或 torchaudio.transforms.Resample target_sr 16000 # SOND 前端标定的采样率 resampler torchaudio.transforms.Resample(orig_freqsr, new_freqtarget_sr) wav resampler(wav) # 输出与训练集同坐标系响度拉齐。不同设备增益差异能差出好几个数量级峰值归一化把每条音频拉到同一响度让模型别把设备增益当成说话人特征def peak_normalize(wav, eps1e-6): 把振幅峰值压到 ±1消除设备/距离造成的响度差异 peak wav.abs().max() return wav / peak.clamp(mineps)关卡 2波形如何变成模型能看懂的图一维波形对人直观对模型是黑箱。第一步是 STFT——把波形切成重叠的短帧、逐帧做傅里叶变换得到时间 × 频率的二维图。三组关键参数import torch wav wav.float() stft torch.stft( wav, n_fft512, # FFT 点数决定频率分辨率 win_length400, # 窗长 25ms兼顾瞬态细节与频率稳定 hop_length160, # 窗移 10ms时间轴约每秒 100 帧 return_complexTrue, ) mag stft.abs() # 取幅度谱为什么是 25ms/10ms/51225ms 一帧足够短能跟上辅音的快变化10ms 的窗移保证相邻帧高度重叠不丢细节512 点 FFT 在 16kHz 下给出 31ms 的等效窗宽频率轴分辨率落在 31Hz 一档是语音频段的经典折中。第二步是梅尔滤波器组。把等间距的频率轴换成梅尔刻度——人耳对低频敏感、对高频迟钝——再用 80 个三角滤波器把对数能量压成 80 维。可以理解为给频谱换了个人耳视角模型学到的就是人真正在听的结构。SOND 这条流水线实际走的是 Kaldi 风格的 fbank 前端内部已含加窗、STFT、梅尔网格、取对数由 funasr/frontends/wav_frontend.py 实现若你的模型更需要原始频谱信息仓库里另有 STFT 版前端可选funasr/frontends/default.py。关卡 3怎样让模型不怕变特征层面做数据增强是性价比最高的抗干扰手段。SpecAugment 的思路很直白在梅尔图上做随机变换逼模型学会缺了点什么还能认出来。SOND 训练时启用的是 funasr/models/specaug/specaug.py 里的SpecAug模块三种手段各模拟一类真实干扰时间扭曲对时间轴做插值弯曲模拟说话快慢、节奏变化频率掩码随机涂抹几条频带模拟某些频率被噪声吃掉时间掩码随机抹掉几段时间模拟信号缺失或被打断。时间掩码的核心实现不到十行import numpy as np def time_mask(feat, num_mask2, width_ratio0.2): 随机抹掉 num_mask 段时间模拟信号缺失 t, d feat.shape width max(1, int(t * width_ratio)) # 按帧数比例决定掩码宽度 for _ in range(num_mask): start np.random.randint(0, max(1, t - width)) feat[start : start width, :] 0 return feat频率/时间掩码的默认参数频带掩码宽度 0~20 帧、各 2 条时间掩码 2 段都写在SpecAug的构造参数里调参时改配置即可无需碰代码。关键纪律训练开、推理关——增强是训练手段不是信号处理推理时开着只会让结果随机漂移。关卡 4不同录制条件的特征分布怎么抹平就算重采样、拉齐响度不同房间的底噪仍会让特征均值方差整体平移。utterance 级 MVN 的做法对每条样本自己的特征图减去它的时间均值、除以时间标准差def utterance_mvn(feat): utterance 级归一化每条样本独立拉成零均值、单位方差 mean feat.mean(dim0, keepdimTrue) std feat.std(dim0, keepdimTrue) return (feat - mean) / (std 1e-8)好处是模型不用再适应环境收敛更快代价是绝对电平信息被抹掉——对谁在说话这类任务恰好无所谓。FunASR 还支持另一条路线全局 CMVN即在WavFrontend里传cmvn_file用训练集统计的全局均值/方差做归一化两条路线二选一即可别混用。关卡 5噪声底上怎么先找到有人说话的地方长音频里大量时间其实没人说话。VADVoice Activity Detection语音活动检测的作用就是逐帧判断这里是语音还是静音把计算集中到有效片段上。FunASR 里的 FSMN-VAD 就是这个角色它输出语音段的起止时间戳前端后续只对语音段提特征——长音频场景下这一步能省掉大量无效计算。VAD 解决哪里有语音重叠分割解决这段里是谁。SOND 的主模型在 funasr/models/sond/e2e_diar_sond.py 中编码器在重叠段上输出每帧的说话人激活向量每个说话人一个通道相当于把混合信号拆成几条干净通道再配合 CI/CD 打分模块判断各说话人段的先后关系最后由解码器输出时序标签。VAD 段是它的地基——段切歪了后面的归属再准也是错的。一站式调用WavFrontend 如何串起整条线上述环节最终收敛成一次forward。WavFrontend内部按 fbank 提取 → LFR 低帧率拼接 → 可选 CMVN 的顺序执行并自动把 batch 内不等长的特征 pad 对齐from funasr.frontends.wav_frontend import WavFrontend frontend WavFrontend( fs16000, # 采样率 n_mels80, # 梅尔维数 frame_length25, # 帧长ms frame_shift10, # 帧移ms cmvn_fileNone, # 全局归一化统计文件None 则跳过 ) feats, feats_lens frontend(waveform, waveform_lengths) # 一次调用出全部特征训练时它输出的特征会继续进入 SpecAug 分支做增强推理时直接用返回值。切换模式不改代码只改配置。流式场景还有WavFrontendOnline同一文件里的在线版本按帧流式出特征、内部自带缓存。常见疑问为什么统一是 16kHz8kHz 丢掉高频辅音细节s、sh、f这类区分度直接归零44.1kHz 对 ASR 是纯浪费帧数翻三倍、频域还得重新标定。16kHz 覆盖 0~8kHz是电话/会议语音的事实标准。梅尔维数为什么是 800~8kHz 范围里80 个三角滤波器是分辨率与特征宽度之间的经典平衡点也是绝大多数公开语音模型的默认配置。想加大时间方向的信息量FunASR 的惯用手段是 LFR 拼接lfr_m/lfr_n而不是盲目堆梅尔维数。推理时还能开增强吗不能。增强改变的是模型见什么不是信号本身。推理一开同一段音频两次结果就会不一致线上排查问题时你会恨上这个开关。为什么先重采样再归一化重采样是线性过程顺序无所谓但峰值归一化依赖采样后波形反过来先归一化再重采样插值会引入微小幅度波动峰值位置可能漂移。参数速查与实战建议参数默认值说明fs16000采样率全管线统一frame_length / frame_shift25 / 10 ms帧长 / 帧移决定时间轴约 100 帧/秒n_mels80梅尔维数lfr_m / lfr_n1 / 1低帧率拼接默认关闭cmvn_fileNone全局归一化统计与 utterance 级 MVN 二选一SpecAugment训练开 / 推理关三变换各 2 次默认宽度见 specaug.py 清单式建议训练期全开时间扭曲 双掩码让模型见多识广推理期关增强特征必须所见即所得长音频务必 VAD 前置只对语音段提特征远场麦克风场景在进入前端前补一道 AEC 回声消除 / 降噪前端只负责翻译不负责打扫重采样一定放在峰值归一化之前换新数据集时全局 CMVN 统计要重新计算别拿旧统计文件硬套。延伸阅读官方中文教程docs/tutorial/README_zh.md前端源码目录含 WavFrontend 与 CMVN 加载funasr/frontends/SpecAugment 实现时间扭曲、频/时掩码funasr/models/specaug/训练与推理示例examples/industrial_data_pretraining/paraformer/数据清单格式参考data/list/train_wav.scp【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASR创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考