3、特征提取入门:MFCC特征提取全流程

好,咱们进入语音唤醒里最核心的一步——特征提取。说白了,就是把声音信号变成机器能懂的数学特征。我刚开始做嵌入式语音时,总觉得这步是玄学,后来踩了不少坑才明白,特征提得好不好,直接决定了唤醒率能到95%还是50%。

3.1 MFCC特征提取全流程

MFCC,全称是梅尔频率倒谱系数。名字听着唬人,其实流程很清晰。我习惯把它拆成四个步骤:预加重→分帧加窗→FFT→Mel滤波器组→DCT。嗯,严格来说是五步,但咱们把FFT和Mel滤波器组合并讲。

3.1.1 预加重

声音信号有个特点:高频能量通常比低频弱。预加重就是为了补偿高频,让信号更均衡。公式很简单:

y[n] = x[n] - α * x[n-1]

α一般取0.97。我在项目里试过0.95到0.99,说实话差别不大,但0.97是业界默认值,咱们就跟着走。

3.1.2 分帧加窗

语音信号是非平稳的,但短时间(20-40ms)内可以看作平稳。所以我们把它切成小段,每段叫一帧。帧长一般25ms,帧移10ms。为什么是10ms?因为这样相邻帧有重叠,信息不会丢失。

加窗是为了减少频谱泄露。我常用汉明窗:

w[n] = 0.54 - 0.46 * cos(2πn/(N-1))

你想想看,如果不加窗,直接截断信号,FFT后会出现很多虚假频率成分。嗯,这里要注意,窗函数选错了,后面全白搭。

3.1.3 FFT与Mel滤波器组

对每一帧做FFT,得到频谱。然后通过Mel滤波器组,把线性频率映射到梅尔刻度。梅尔刻度模拟了人耳的听觉特性——对低频敏感,对高频不敏感。

映射公式:

Mel(f) = 2595 * log10(1 + f/700)

滤波器组通常用40个三角滤波器。我在项目中遇到过一个问题:滤波器数量太少,特征分辨率不够;太多,计算量上去了但效果没提升。40是个平衡点。

3.1.4 DCT(离散余弦变换)

最后一步,对Mel滤波器输出的对数能量做DCT。目的是去相关,把能量集中到前几个系数上。一般取13个系数就够了。

重要:MFCC的维度不是越高越好。我见过有人取39维(13维+一阶差分+二阶差分),但在唤醒词任务中,13维基础MFCC往往就够了。多了反而容易过拟合。

3.2 Fbank特征与MFCC的对比

Fbank,全称是Filter Bank,就是MFCC去掉最后一步DCT的结果。说白了,Fbank是MFCC的“半成品”。

对比项 Fbank MFCC
维度 40维(常用) 13维(常用)
相关性 特征间有相关性 去相关
计算量 小(少一步DCT) 稍大
适用场景 深度学习模型 传统GMM模型

我个人习惯:如果用的是DNN/CNN这类模型,直接用Fbank。因为神经网络自己会处理特征间的相关性,不需要DCT帮忙。如果是GMM-HMM这类传统模型,用MFCC更合适。

经验之谈:在嵌入式设备上,我建议优先用Fbank。少一步DCT,省下的算力可以留给模型推理。我曾经在Cortex-M4上对比过,Fbank比MFCC快约15%。

3.3 特征归一化技巧

特征提取完了,直接扔给模型?不行。不同人说话音量不同,不同环境噪声不同,特征值的分布差异很大。归一化就是把这些差异抹平。

3.3.1 均值归一化

最常用的方法:对每个特征维度,减去均值,除以标准差。

feature_norm = (feature - mean) / std

我在项目中遇到过一个问题:如果测试环境安静,训练环境嘈杂,均值归一化后特征分布还是对不上。后来我改用在线归一化——实时计算当前语音段的均值和方差,而不是用全局统计量。

3.3.2 CMVN(倒谱均值方差归一化)

CMVN是语音领域的标配。它对每个 utterance(一段语音)独立做归一化。公式和上面一样,但均值和方差是从当前语音段算的。

避坑指南:我曾经在唤醒词任务中直接用了全局CMVN,结果发现不同麦克风录制的语音特征分布差异很大。后来改成按设备单独计算CMVN参数,唤醒率从82%提升到了91%。

3.3.3 能量归一化

这个简单:把每帧的能量缩放到0-1之间。目的是消除音量差异。但要注意,如果语音中有静音段,能量归一化会把噪声也放大。我建议先做VAD(语音活动检测),只对有效语音段做能量归一化。

3.3.4 我的归一化策略

在嵌入式语音唤醒中,我通常用这套组合拳:

  1. 先做VAD,去掉静音帧
  2. 对有效语音段做能量归一化
  3. 做CMVN(按utterance独立计算)
  4. 最后做全局均值归一化(可选)

你想想看,这套流程下来,特征对音量、环境噪声、设备差异的鲁棒性都提高了。嗯,当然,具体用哪几步,还得看你的场景。如果算力紧张,只做CMVN也够用。

总结:MFCC和Fbank没有绝对的好坏,关键看模型和场景。归一化是容易被忽视但极其重要的一步。我见过太多项目,模型结构调了半天没效果,最后发现是特征没归一化。记住:特征工程决定了模型性能的上限。