2. 语音识别基础
各位同学好,我是你们这堂课的主讲。今天咱们聊聊语音识别里最基础、也最容易被忽视的一环——声学预处理。
很多人一上来就调模型、改网络结构,结果识别率死活上不去。我见过太多这样的案例了。其实啊,很多时候问题出在入口——你的音频信号还没进模型,就已经“脏”了。
这一章,我会带你走一遍完整的信号预处理流水线。从麦克风采集到的模拟信号,到最终能喂给模型的梅尔频谱特征,每一步我都会讲清楚“为什么这么做”以及“我踩过的坑”。
2.1 语音信号数字化:从连续到离散
麦克风采集到的是连续变化的电压信号,也就是模拟信号。但计算机只认0和1。所以第一步,就是把这个连续信号变成离散的数字序列。
这个过程包含两个关键动作:采样和量化。
- 采样:每隔固定时间取一个值。时间间隔越短,采样率越高。
- 量化:把采样得到的电压值,用有限个二进制数表示。位数越多,精度越高。
这里有个经典问题:采样率设多高才够?
答案是遵循奈奎斯特采样定理:采样率必须大于信号最高频率的两倍。人声的主要能量集中在300Hz~3400Hz,所以电话系统用8kHz采样率。但为了保留更多细节,语音识别系统通常用16kHz。
| 应用场景 | 采样率 | 量化位数 | 说明 |
|---|---|---|---|
| 电话语音 | 8 kHz | 8 bit | 窄带,仅保留语音主要频段 |
| 普通语音识别 | 16 kHz | 16 bit | 宽带,保留更多细节 |
| 高保真音频 | 44.1 kHz | 16/24 bit | 音乐级,语音识别很少用 |
2.2 预加重:补偿高频能量
你有没有发现,人说话时低频能量大,高频能量小?这是声带和口腔的物理特性决定的。但高频部分恰恰包含了很多辅音信息,比如“s”、“sh”、“f”。如果直接处理,高频细节很容易被低频淹没。
预加重就是为了解决这个问题。它本质上是一个高通滤波器,提升高频部分的能量。
公式很简单:
y[n] = x[n] - α * x[n-1]
其中α通常取0.97或0.95。我个人习惯用0.97,效果比较稳定。
为什么是0.97?不是0.9也不是0.99?
α越接近1,高频提升越猛。但太猛了会放大噪声。0.97是个经验值,在大多数场景下表现都不错。你可以根据实际数据微调,但别偏离太远。
2.3 分帧加窗:把长信号切成短片段
语音信号是非平稳的——它的统计特性随时间变化。但如果我们只取很短的一段(比如20~30毫秒),在这段时间内信号可以近似认为是平稳的。这就是短时平稳假设。
基于这个假设,我们把长信号切成一个个短帧。帧长通常取25ms,帧移取10ms。也就是说,相邻帧之间有15ms的重叠。
为什么要重叠?
因为加窗后,帧边缘的信号会被削弱。重叠可以保证信息不丢失,让帧与帧之间平滑过渡。
切完帧之后,还要对每一帧加窗。常用的窗函数有:
- 汉明窗(Hamming Window):最常用,旁瓣衰减适中,频率分辨率好。
- 汉宁窗(Hann Window):旁瓣衰减更快,但主瓣稍宽。
- 矩形窗:简单粗暴,但频谱泄露严重,基本不用。
我个人几乎只用汉明窗。原因很简单:它在频率分辨率和旁瓣抑制之间取得了很好的平衡。你想想看,如果旁瓣太大,一个频率的能量会“泄露”到其他频率上,造成频谱模糊。这对后续的梅尔频谱提取非常不利。
- 帧长:25ms(对应16kHz采样率就是400个采样点)
- 帧移:10ms(160个采样点)
- 窗函数:汉明窗
2.4 短时傅里叶变换(STFT):看穿时间的频谱
分帧之后,我们得到了很多短时平稳的信号片段。接下来要做的,就是分析每个片段的频率成分。这就是短时傅里叶变换(STFT)的用武之地。
STFT说白了就是:对每一帧做一次快速傅里叶变换(FFT),得到该帧的频谱。把所有帧的频谱按时间排列,就得到了一个二维的时频谱图(spectrogram)。
横轴是时间,纵轴是频率,颜色深浅代表能量大小。这张图,就是语音信号的“指纹”。
这里有个参数需要你注意:FFT点数。通常取512或1024。点数越多,频率分辨率越高,但计算量也越大。对于16kHz的语音,512点FFT已经够用了。
# Python示例:STFT计算
import numpy as np
from scipy import signal
# 参数设置
fs = 16000 # 采样率
frame_len = 0.025 # 帧长25ms
hop_len = 0.010 # 帧移10ms
nfft = 512 # FFT点数
# 计算STFT
f, t, Zxx = signal.stft(
audio,
fs=fs,
nperseg=int(frame_len * fs),
noverlap=int((frame_len - hop_len) * fs),
nfft=nfft
)
# Zxx的shape: (频率点数, 时间帧数)
# 取幅度谱
magnitude = np.abs(Zxx)
2.5 梅尔频谱:模拟人耳的听觉特性
STFT得到的线性频谱,频率轴是均匀分布的。但人耳不是这样工作的。人耳对低频更敏感,对高频的分辨能力则逐渐下降。换句话说,人耳对频率的感知是非线性的。
梅尔刻度(Mel Scale)就是用来模拟这种非线性感知的。它把物理频率映射到人耳感知频率上。转换公式如下:
Mel(f) = 2595 * log10(1 + f / 700)
从公式可以看出:低频段,梅尔频率随物理频率线性增长;高频段,增长变缓。这正好符合人耳的听觉特性。
具体做法是:在梅尔刻度上均匀放置一组三角滤波器(通常40个),然后用这些滤波器去加权求和STFT的幅度谱。每个滤波器输出一个能量值,最终得到40维的梅尔频谱特征。
为什么是40维?
这是经验值。太少会丢失信息,太多会增加计算量。40维在大多数语音识别任务中表现都不错。如果你做的是细粒度任务(比如说话人识别),可以试试64维或80维。
2.6 完整流程总结
好了,我们把整个预处理流水线串起来,看看它长什么样:
整个流程走下来,你从一段原始的音频文件,得到了一个40维的梅尔频谱特征序列。这个序列就是后续声学模型的输入。
每一步都有它的道理:数字化让信号能被计算机处理,预加重补偿了高频损失,分帧加窗满足了短时平稳假设,STFT揭示了时频结构,梅尔滤波器则模拟了人耳的听觉特性。
嗯,这里要注意:预处理不是一成不变的。如果你做的是远场语音识别,可能需要额外的去混响处理;如果是噪声环境,可能还要加VAD(语音活动检测)。但今天讲的这五步,是绝大多数语音识别系统的“标配”。