第四章:语音情绪特征提取

各位同学,今天我们来聊聊语音情绪识别中最关键的一环——特征提取。说实话,我在这个领域摸爬滚打了七八年,踩过的坑比走过的路还多。语音信号不像文本那样规整,它是个连续的时间序列,情绪信息就藏在那些细微的声学变化里。

我个人习惯把语音情绪特征分成三大类:声学特征、韵律特征,以及深度学习自动提取的特征。咱们一个一个来看。

4.1 声学特征:MFCC、基频、能量

声学特征是最基础、也是最常用的。你想想看,人耳听到一段语音,能判断出对方是高兴还是生气,靠的就是这些底层声学参数。

4.1.1 MFCC(梅尔频率倒谱系数)

MFCC 可以说是语音情绪识别里的"万金油"。它模拟了人耳对频率的非线性感知——低频分辨得细,高频分辨得粗。我在项目中遇到过一个问题:直接用 13 维 MFCC 做分类,准确率总上不去。后来我加了 delta 和 delta-delta 系数,把维度扩展到 39 维,效果立马好了不少。

核心要点: MFCC 提取流程——预加重、分帧、加窗、FFT、Mel 滤波器组、对数运算、DCT。每一步都有讲究,比如窗函数我习惯用汉明窗,旁瓣衰减好。
# 这是我常用的 MFCC 提取代码片段
import librosa

def extract_mfcc(audio_path):
    y, sr = librosa.load(audio_path, sr=16000)
    mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13,
                                n_fft=512, hop_length=160)
    # 加一阶和二阶差分
    delta = librosa.feature.delta(mfcc)
    delta2 = librosa.feature.delta(mfcc, order=2)
    return np.vstack([mfcc, delta, delta2])

4.1.2 基频(F0)

基频就是声带振动的频率。生气时基频会升高,悲伤时基频会降低。嗯,这里要注意:基频提取很容易受噪声干扰。我曾经在工厂环境采集数据,背景机器轰鸣,基频轨迹全是毛刺。后来我用了中值滤波平滑,才勉强能用。

避坑指南: 我曾经用 pyworld 提取基频,发现女声的基频范围比男声高很多。做跨性别情绪识别时,一定要做归一化处理,否则模型会学到性别特征而不是情绪特征。

4.1.3 能量与短时能量

能量特征反映的是语音的响度。愤怒时能量大,平静时能量小。我一般会提取帧级别的短时能量,然后统计它的均值、方差、最大值等统计量。

特征 维度 情绪相关性
MFCC 13-39 音色特征,区分度高
基频 F0 1 生气↑ 悲伤↓
短时能量 1 愤怒↑ 平静↓

4.2 韵律特征:语速、停顿、节奏

韵律特征说白了就是"说话的方式"。同样一句话,说得快还是慢,停顿多还是少,传递的情绪完全不同。

我建议重点关注这几个韵律参数:

  • 语速: 每秒音节数。兴奋时语速快,沮丧时语速慢。
  • 停顿时长: 句间停顿和句内停顿。犹豫、悲伤时停顿变长。
  • 基频动态范围: 最高基频与最低基频的差值。惊讶时动态范围大,平淡时小。
我的经验: 韵律特征对"高唤醒度"情绪(愤怒、高兴)特别敏感。但要注意,不同语言、不同文化背景的人,韵律模式差异很大。做中文语音情绪识别时,我习惯把声调信息也考虑进去。

4.3 深度学习模型:CNN 与 LSTM

传统特征提取需要大量人工设计,而且容易丢失高阶信息。深度学习模型可以自动从原始波形或频谱图中学习特征。我个人觉得,这是目前最主流的方向。

4.3.1 CNN 在语音情绪识别中的应用

CNN 擅长捕捉局部模式。把语谱图当成图像来处理,CNN 可以学到频率轴和时间轴上的局部纹理特征。

# 一个简单的 CNN 模型结构
model = Sequential([
    Conv2D(32, (3,3), activation='relu', input_shape=(128, 128, 1)),
    MaxPooling2D((2,2)),
    Conv2D(64, (3,3), activation='relu'),
    MaxPooling2D((2,2)),
    Flatten(),
    Dense(64, activation='relu'),
    Dropout(0.5),
    Dense(7, activation='softmax')  # 7种情绪
])

为什么 CNN 有效?因为愤怒的语谱图往往能量集中在高频区域,而悲伤的语谱图能量分布比较均匀。CNN 的卷积核能自动捕捉这些差异。

4.3.2 LSTM 处理时序依赖

语音是时序信号,情绪的表达有一个"起承转合"的过程。LSTM 的优势就在于它能记住前面的信息,捕捉长时依赖。

我记得有一次做"从平静到愤怒"的渐变情绪识别,CNN 效果很差,因为 CNN 只看局部帧,看不到情绪的变化趋势。换成 LSTM 后,准确率提升了 15%。

关键点: LSTM 的输入是时间步序列。每个时间步可以是一帧的 MFCC 特征向量。我习惯用双向 LSTM,因为未来的语音信息对当前情绪判断也有帮助。
# 双向 LSTM 示例
model = Sequential([
    Bidirectional(LSTM(128, return_sequences=True), 
                  input_shape=(timesteps, n_features)),
    Bidirectional(LSTM(64)),
    Dense(32, activation='relu'),
    Dense(7, activation='softmax')
])

4.3.3 CNN + LSTM 混合模型

在实际项目中,我很少单独用 CNN 或 LSTM。更常见的做法是:先用 CNN 提取局部频谱特征,再用 LSTM 建模时序依赖。这种混合结构在 IEMOCAP 等公开数据集上,准确率能到 75% 以上。

CNN + LSTM 混合模型结构 原始语音 语谱图 CNN 特征提取 LSTM 时序建模 情绪 CNN 负责提取局部频谱模式(愤怒的高频能量、悲伤的均匀分布) LSTM 负责捕捉情绪随时间的变化趋势(从平静到愤怒的渐变) 常用参数配置 • CNN: 3层卷积,32-64-128 通道,3x3 卷积核 • LSTM: 2层双向,每层 128 单元,dropout=0.3

4.4 特征融合策略

单一特征往往不够鲁棒。我建议把声学特征、韵律特征和深度学习特征融合起来。常用的融合方式有三种:

  1. 早期融合: 在输入层就把特征拼接起来。简单直接,但维度爆炸。
  2. 中期融合: 不同特征分别经过子网络,在中间层融合。我比较推荐这种方式。
  3. 晚期融合: 每个特征单独训练一个分类器,最后投票或加权平均。
我的建议: 如果你刚开始做语音情绪识别,先从 MFCC + 基频 + 能量 入手,用 SVM 或随机森林做分类。等基线建立好了,再上深度学习模型。这样你能清楚每一步改进带来的收益。

好了,这一章的内容就到这里。特征提取是语音情绪识别的基石,选对特征、用好模型,你的系统就成功了一半。下一章我们会聊多模态融合,到时候把语音和文本、视觉信息结合起来,效果会更上一层楼。


公众号:蓝海资料掘金营,微信deep3321