传统算法提取音频特征
在训练模型时,我们通常先用卷积网络从音频中提取特征。在数据充足的场景下,它的效果一般优于传统方法,但计算和存储开销也更大。本文探讨如何用传统信号处理算法替代这一步,从而降低资源消耗。本文主要是借鉴RNNoise来做介绍。
音频特征
Bark 临界频带能量
人耳对频率的分辨并不是线性的,Zwicker(1961)就曾提出,听觉系统可以近似为一组带通滤波器,每个滤波器覆盖一个临界频带,落在同一个临界频带内的频率会被听觉系统合并处理,这一现象也被称为Bark尺度。
他把0-15.5kHz划分为24个临界频带。常用的频率到Bark值的转换如下:
z ( f ) = 26.81 f 1960 + f − 0.53 [ Bark ] z(f)=\frac{26.81\, f}{1960 + f} - 0.53 \quad [\text{Bark}]z(f)=1960+f26.81f−0.53[Bark]
其中f ff为频率(Hz),z zz为对应的Bark值。它在低频接近线性、高频趋于对数,与mel尺度相似,他们的核心都是掩蔽效应,对频率分辨率做感知非线性弯折。
当然这里我们就不详细计算了,通常通过列表的形式使用。可以看bark 表
Bark差分特征
其差分特征包括Δ B a r k \Delta BarkΔBark和Δ Δ B a r k \Delta \Delta BarkΔΔBark,Bark的临界频带能量描述的是当前帧的静态频谱,我们有时还是需要用到动态时序。这个可以类比于速度和加速度,当前仅仅是举一个例子说明而已。(声音渐强or渐弱?)
基频
基频是一个周期信号中频率最低的那个分量,也可以直接理解为声带的振动频率。一个周期为T TT的信号,其基频f 0 = 1 / T f_0 = 1/Tf0=1/T。它可以用来区分浊音与清音:浊音由声带振动产生,有明确基频;清音(如
/s/、/f/)没有。此外,男性基频通常较低,女性较高。
工程上常用自相关法测基频:在一段范围内寻找使信号与自身延迟版本最相似的延迟τ \tauτ,该处的自相关峰值位置即基频周期,峰值高度则反映音高的稳定程度。本项目在 50–400Hz
范围内搜索,输出"基频周期"和"相关度"两维。这一维是整组特征里最有"先验"色彩的:风扇、白噪声这类噪声没有周期性声带振动,基频相关度天然很低,与元音一眼可分。
非平稳度
非平稳度衡量当前帧频谱相较于历史帧的突变程度。做法是对频带能量做指数平滑,再计算当前帧与平滑值的偏差:
S t = α S t − 1 + ( 1 − α ) E t , nonstat t = 1 B ∑ b ∣ E t , b − S t , b ∣ S_t = \alpha S_{t-1} + (1-\alpha)E_t, \qquad \text{nonstat}t = \frac{1}{B}\sum_b |E{t,b} - S_{t,b}|St=αSt−1+(1−α)Et,nonstatt=B1b∑∣Et,b−St,b∣
平滑常数α \alphaα越大,记忆越长、反应越慢。本项目用四个不同的α \alphaα(0.98 / 0.95 / 0.9 /
0.8)同时观察快变与慢变,再对其中最快和最慢两个尺度求差分。语音在元音段相对平稳,而键盘敲击、关门声等突发噪声高度非平稳。因此非平稳度对 VAD 区分"语音的自然演变"与"瞬时噪声冲击"至关重要。
特征汇总
| 特征 | 维度 | 捕捉什么 | 为什么对 VAD 有用 |
|---|---|---|---|
| Bark 频带能量 | 22 | 各频段的能量分布 | 人声能量集中在特定频段,与噪声的能量分布差异明显 |
| ΔBark、ΔΔBark | 2+2 | 能量的一阶/二阶变化 | 语音有丰富动态起伏,静音或稳态噪声则平坦 |
| 基频周期 + 相关度 | 1+1 | 有无稳定的声带振动 | 浊音有明确基频和高自相关,多数噪声没有 |
| 频谱非平稳度 | 4 | 频谱突变的程度(4种时间尺度) | 区分钟声等瞬时噪声冲击与语音的自然演变 |
| Δ非平稳度 | 2 | 非平稳度本身的变化率 | 精准捕捉语音的起始和结束瞬态 |
| 总计 | 34 |
为什么使用DSP前端替代卷积神经网络呢?
回到之前的话题,我们常用的蒸馏或者训练一个模型就是将原始波形送进去,然后让神经网络学习语音的特征(针对不同的任务)。通常来说,我们蒸馏会使用一个相同的架构的,但是更小的模型(学生模型)来学习教师能力。但是这里我们也可以用传统方法来提取特征,这一个地方其实是有借鉴RNNnoise的意思。完全放弃了卷积,改用手工特征。理由如下:
一、卷积前端很贵。 卷积层要占用大量参数和算力。若学生也用卷积,"小"就无从谈起(更何况silero vad模型已经很小了)。手工 DSP 特征的提取是固定数学公式(FFT、取能量、做差分、自相关),零参数、不占模型体积,省下的预算全给后面的神经网络。
二、为嵌入式落地铺路。 仙子我们更加希望可以将模型可以部署到嵌入式端,而不是仅限于上位机。神经网络前端在 C 里实现既慢又要处理卷积的各种边界;而 FFT、自相关、指数平滑都是经典信号处理算法,C 实现成熟到不能再成熟。选 DSP前端,本质是选了一条能走到底的落地路线。
三、手工特征自带先验。 如前所述,这 34 维把"人声有基频、频谱在动、能量有起伏"这些知识直接编码进了输入。学生不必从零学这些,相当于站在几十年语音信号研究的肩膀上。
学生模型与蒸馏
本处采用的例子是一个简单的例子,当然大的模型也用不上这种方法。
16kHz 波形 → 34维 DSP 特征(手工计算,零参数)→ GRU(h=32, 2层)→ sigmoid
训练时,先用教师 Silero VAD 对音频逐帧打出概率作为软标签,学生则以 DSP 特征为输入去拟合这些软标签。整个可学习部分只有那两层 GRU,共 12,897 个参数,INT8 量化后模型体积 15.3KB。
评测与边界
在与教师及另一个开源模型 TEN VAD 的对比中:
表一:抗噪鲁棒性(不同 SNR 下的帧准确率 %)
| SNR | rnvad | Silero VAD v4 | TEN VAD |
|---|---|---|---|
| clean(干净) | 97.6 | 100.0(教师基准) | 94.2 |
| 20 dB | 97.4 | 97.4 | 91.9 |
| 10 dB | 95.8 | 95.1 | 89.1 |
| 5 dB | 96.2 | 93.7 | 87.3 |
| 0 dB | 93.6 | 91.9 | 87.4 |
| -5 dB | 90.7 | 84.8 | 83.2 |
表二:综合对比(补上速度、内存、感受野)
| 指标 | rnvad | Silero VAD v4 | TEN VAD |
|---|---|---|---|
| 架构 | 34 DSP 特征 + GRU(h32,l2) | STFT+Conv+LSTM | SepConv2D+2×LSTM |
| 参数量 | 12,897 | 155,908(12×) | 75,516(6×) |
| 体积(ONNX) | 52.8 KB | 628.8 KB | 308.1 KB |
| 量化后体积 | 15.3 KB | — | — |
| 运行时内存 | 常驻 ~25 KB(纯 C99) | ONNX Runtime(数 MB,框架开销) | ONNX Runtime(数 MB,框架开销) |
| 英文帧准确率 | 97.6% | 100%(教师基准) | 94.3% |
| 中文对话 F1 | 0.892 | 0.908 | 0.909 |
| -5dB 准确率 | 90.7% | 84.8% | 83.2% |
| 运行依赖 | 无(纯 C99) | ONNX Runtime | ONNX Runtime |
总结
- 干净场景:15KB 的学生 F1(0.892)已逼近十几倍大的教师(0.908),证明"小"没牺牲基本盘;
- 抗噪反超:随 SNR 下降,学生从追平到反超,-5dB 领先教师 5.9 个点——这是全文最有冲击力的结论;
- 诚实归因:这个反超是"DSP 先验更鲁棒"+“教师训练分布没覆盖强噪声"两者叠加,不是"手工特征天生打败卷积”。再补一句边界:数据/算力充足时卷积也能学到这些先验,本文结论只在"受限 + 硬部署约束"下成立。
把这个案例拔到可举一反三的高度:蒸馏迁移的是"判断"不是"架构";先验既能从数据端(软标签)注入、也能从表示端(手工特征)注入;部署约束会反向决定架构。一句话收:当强领域先验遇上硬部署约束,"缩小教师"未必最优。
关于这个例子的具体详细数据可以参考:rnvad:把 VAD 压到 15KB 能用吗?与 Silero、TEN VAD 的实测对比
