FBank特征提取详解


什么是FBank

FBank(Filter Bank,滤波器组)是语音特征参数提取方法之一,其独特的基于倒谱的提取方式更加符合人类的听觉原理。FBank特征提取相当于MFCC去掉最后一步的离散余弦变换(DCT),因此保留了更多原始语音数据信息。

为什么需要FBank?

在深度学习时代,神经网络具有强大的特征学习能力,能够从更原始的特征中自动学习判别性表示。相比MFCC经过DCT压缩后的特征,FBank具有以下优势:

  • 信息保留更完整:未经过DCT有损压缩,保留更多频谱细节
  • 适合深度模型:为DNN/CNN/RNN等神经网络提供更丰富的输入
  • 更高维度:通常为40维(对应40个滤波器),相比MFCC的12-13维提供更多信息

FBank与MFCC的关系

从提取流程上看:

MFCC = 预加重 → 分帧 → 加窗 → FFT → Mel滤波器组 → 对数 → DCT → 保留2-13系数
FBank = 预加重 → 分帧 → 加窗 → FFT → Mel滤波器组 → 对数

可以看出,FBank = MFCC - DCT,FBank保留了经过Mel滤波器组处理后的所有频带能量信息。

特征 MFCC FBank
维度 12-13维 通常40维
信息量 经过DCT压缩,有损 保留更多原始信息
去相关性 DCT去除相关性 相邻频带有相关性
适用场景 GMM-HMM等传统模型 DNN/CNN/RNN深度模型
计算效率 维度低,计算快 维度高,计算稍慢

FBank特征提取流程

完整的FBank提取包含以下5个步骤:

FBank特征提取流程图

1. 预加重

对原始信号进行高通滤波,增强高频部分:

$$y(n) = x(n) - \alpha \times x(n-1)$$

其中 $\alpha$ 通常取 0.97

预加重的作用:

  • 消除发声过程中声带和嘴唇的效应
  • 补偿被发音系统抑制的高频部分
  • 突出高频共振峰
  • 提高信噪比

原始语音信号波形:

原始语音信号时域波形

预加重后的效果对比:

预加重前后对比

2. 分帧

按固定时间长度分割音频样本。

典型参数:

  • 采样率:16kHz
  • 帧长:25ms(16kHz下为400个采样点)
  • 帧移:10ms(16kHz下为160个采样点)
  • 帧重叠:约62.5%

通常FFT点数 $N$ 取值 512256,涵盖20-30ms的语音段。相邻帧之间的重叠区域 $M$ 一般为 $N$ 的1/2或1/3。

3. 加窗

对每帧施加汉明窗(Hamming Window),增加帧左右端的连续性,减少频谱泄漏。

汉明窗函数:
$$W(n) = 0.54 - 0.46 \times \cos\left(\frac{2\pi n}{N-1}\right), \quad 0 \leq n \leq N-1$$

加窗后的信号:
$$S’(n) = S(n) \times W(n)$$

汉明窗时域波形:

汉明窗函数形状

加窗后的信号效果:

加窗后的信号波形

4. 离散傅里叶变换(DFT)

将时域信号转换为频域能量分布。

DFT公式:
$$s(k) = \sum_{n=0}^{N-1} S(n) \times e^{-j2\pi kn/N}$$

功率谱:
$$p(k) = \frac{1}{N} |s(k)|^2$$

在实际实现中,通常使用快速傅里叶变换(FFT)来高效计算DFT。

频谱到功率谱转换示意图:

频谱与功率谱的关系

DFT变换后的频谱:

DFT频谱结果

5. Mel滤波器组

将线性频谱映射到Mel非线性频谱。在Mel频域内,人对音调的感知度为线性关系,更符合听觉特性。

频率到Mel频率转换:
$$f_{mel} = 2595 \times \log_{10}\left(1 + \frac{f}{700}\right)$$

Mel频率到频率转换:
$$f = 700 \times \left(10^{f_{mel}/2595} - 1\right)$$

滤波器组设计步骤:

  1. 确定频率范围:最低频率(如300Hz)和最高频率(如8000Hz)
  2. 转换到Mel域并等分:将频率范围转到Mel频率,然后线性等分成 $M+2$ 个点($M$ 为滤波器个数,通常为40)
  3. 转回Hz频率:将Mel频率点转换回赫兹频率
  4. 映射到FFT频率索引
    $$f(i) = \left\lfloor \frac{(N+1) \times h(i)}{f_s} \right\rfloor$$
    其中 $N$ 为FFT点数,$f_s$ 为采样率

三角滤波器响应:
$$H_m(k) = \begin{cases}
0 & k < f(m-1) \
\frac{k - f(m-1)}{f(m) - f(m-1)} & f(m-1) \leq k < f(m) \
1 & k = f(m) \
\frac{f(m+1) - k}{f(m+1) - f(m)} & f(m) < k \leq f(m+1) \
0 & k > f(m+1)
\end{cases}$$

滤波器组输出(对数能量):
$$FBank(m) = \log\left(\sum_{k=0}^{N-1} |X(k)|^2 \times H_m(k)\right)$$

其中 $m = 0, 1, …, M-1$,$M$ 通常为 22-2640

Mel滤波器组结构示意图:

Mel滤波器组三角形分布

Mel滤波器组可视化:

Mel滤波器组在频域的分布

FBank特征提取结果:

滤波器组输出的对数能量

关键参数总结

参数 典型值 说明
预加重系数 0.97 高通滤波
采样率 16kHz 语音采样频率
帧长 25ms (400点) 短时平稳假设
帧移 10ms (160点) 帧间重叠
FFT点数 512 频谱分辨率
最低频率 300Hz Mel滤波器下限
最高频率 8000Hz Mel滤波器上限
Mel滤波器数 40 FBank特征维度

Python实现

使用Librosa库(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import librosa
import numpy as np

y, sr = librosa.load('audio.wav', sr=16000)
fbank = librosa.feature.melspectrogram(
y=y,
sr=sr,
n_fft=512,
hop_length=160,
win_length=400,
n_mels=40
)

fbank_db = librosa.power_to_db(fbank, ref=np.max)

print(f"FBank shape: {fbank_db.shape}")

手动实现核心步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import numpy as np
import scipy.io.wavfile
from scipy.fftpack import fft

sample_rate, signal = scipy.io.wavfile.read('audio.wav')

pre_emphasis = 0.97
emphasized_signal = np.append(signal[0], signal[1:] - pre_emphasis * signal[:-1])

frame_size = 0.025
frame_stride = 0.01
frame_length = int(round(frame_size * sample_rate))
frame_step = int(round(frame_stride * sample_rate))

signal_length = len(emphasized_signal)
num_frames = int(np.ceil(float(np.abs(signal_length - frame_length)) / frame_step))

pad_signal_length = num_frames * frame_step + frame_length
z = np.zeros((pad_signal_length - signal_length))
pad_signal = np.append(emphasized_signal, z)

indices = np.tile(np.arange(0, frame_length), (num_frames, 1)) + \
np.tile(np.arange(0, num_frames * frame_step, frame_step), (frame_length, 1)).T
frames = pad_signal[indices.astype(np.int32, copy=False)]

frames *= np.hamming(frame_length)

NFFT = 512
mag_frames = np.absolute(np.fft.rfft(frames, NFFT))
pow_frames = ((1.0 / NFFT) * (mag_frames ** 2))

nfilt = 40
low_freq_mel = 0
high_freq_mel = 2595 * np.log10(1 + (sample_rate / 2) / 700)
mel_points = np.linspace(low_freq_mel, high_freq_mel, nfilt + 2)
hz_points = 700 * (10 ** (mel_points / 2595) - 1)
bin_points = np.floor((NFFT + 1) * hz_points / sample_rate)

fbank = np.zeros((nfilt, int(np.floor(NFFT / 2 + 1))))
for m in range(1, nfilt + 1):
f_m_minus = int(bin_points[m - 1])
f_m = int(bin_points[m])
f_m_plus = int(bin_points[m + 1])

for k in range(f_m_minus, f_m):
fbank[m - 1, k] = (k - bin_points[m - 1]) / (bin_points[m] - bin_points[m - 1])
for k in range(f_m, f_m_plus):
fbank[m - 1, k] = (bin_points[m + 1] - k) / (bin_points[m + 1] - bin_points[m])

filter_banks = np.dot(pow_frames, fbank.T)
filter_banks = np.where(filter_banks == 0, np.finfo(float).eps, filter_banks)
filter_banks = 20 * np.log10(filter_banks)

print(f"FBank shape: {filter_banks.shape}")

从FBank到MFCC

如果需要从FBank继续计算MFCC,只需添加DCT变换:

1
2
3
4
5
6
7
8
from scipy.fftpack import dct

num_ceps = 12
mfcc = dct(filter_banks, type=2, axis=1, norm='ortho')[:, 1:(num_ceps + 1)]

mfcc -= (np.mean(mfcc, axis=0) + 1e-8)

print(f"MFCC shape: {mfcc.shape}")

FBank的应用场景

  1. 深度学习语音识别:作为DNN/CNN/LSTM等模型的输入特征
  2. 端到端语音识别:在Transformer/Conformer等架构中广泛使用
  3. 说话人识别:提供丰富的频谱信息用于说话人建模
  4. 语音合成:用于声学特征建模
  5. 音频分类:环境声音识别、音乐分类等

为什么深度学习更青睐FBank?

在深度学习时代,FBank相比MFCC更受欢迎,原因包括:

  1. 信息保留更完整:DCT变换会丢失部分信息,而神经网络可以从更原始的特征中学习
  2. 相关性由网络处理:MFCC通过DCT去相关性是为了GMM等传统模型,但神经网络可以自己学习处理相关性
  3. 更高维度提供更多细节:40维FBank比12维MFCC提供更丰富的频谱细节
  4. 卷积友好:FBank的频带结构更适合CNN学习局部频谱模式

总结

FBank是一种符合人耳听觉特性的语音特征提取方法,其核心优势在于:

  1. 符合人耳感知:基于Mel刻度,模拟人类听觉系统的非线性频率感知
  2. 信息丰富:相比MFCC保留更多原始频谱信息
  3. 适合深度学习:为神经网络提供更充分的学习材料
  4. 实现简单:比MFCC少一步DCT变换

在现代语音处理系统中,特别是基于深度学习的端到端模型中,FBank已经成为比MFCC更常用的特征表示。它为模型提供了更丰富的输入信息,让神经网络有更大的学习空间来发现最优的特征表示。

参考资料


文章作者: 2356
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 2356 !