基于Wav2Vec 2.0+CNN的语音情感识别模型准确率停滞问题求助
语音情感识别模型准确率停滞问题排查与解决
我尝试用Wav2Vec 2.0结合全连接网络(注:代码中为SimpleNN全连接结构,你提到的CNN可能是笔误)做4类语音情感识别,类别为OAF_Fear、OAF_angry、OAF_happy、OAF_neutral。所有音频已按Wav2Vec 2.0要求完成预处理(截断/填充、重采样),模型定义如下:
import torch import torch.nn as nn import torch.optim as optim from transformers import Wav2Vec2Tokenizer, Wav2Vec2Model class SimpleNN(nn.Module): def __init__(self, input_size, hidden_size, output_size): super(SimpleNN, self).__init__() self.fc1 = nn.Linear(input_size, hidden_size) self.fc2 = nn.Linear(hidden_size, output_size) self.relu = nn.ReLU() self.softmax = nn.Softmax(dim=1) def forward(self, x): x = self.fc1(x) x = self.relu(x) x = self.fc2(x) x = self.softmax(x) return x tokenizer = Wav2Vec2Tokenizer.from_pretrained("facebook/wav2vec2-base-960h") model = Wav2Vec2Model.from_pretrained("facebook/wav2vec2-base-960h") # Modify the last layer to match the number of output classes label_mapping = {'OAF_Fear': 0, 'OAF_angry': 1, 'OAF_happy': 2, 'OAF_neutral': 3} num_classes = len(label_mapping) model.lm_head = nn.Linear(in_features=model.config.hidden_size, out_features=num_classes, bias=True) for param in model.parameters(): param.requires_grad = False for param in model.lm_head.parameters(): param.requires_grad = True input_size = 768 # Size of features extracted from pre-trained model hidden_size = 256 output_size = num_classes # Number of emotion classes learning_rate = 0.001 num_epochs = 50 batch_size = 32 root_dir = "/content/drive/MyDrive/BTP_hanan_dataset/Dataset/TESS" class FullModel(nn.Module): def __init__(self, wav2vec_model, simple_nn_model): super(FullModel, self).__init__() self.wav2vec_model = wav2vec_model self.simple_nn_model = simple_nn_model def forward(self, x): # Get hidden states from pre-trained model hidden_states = self.wav2vec_model(x)[0] # Aggregate hidden states (e.g., by averaging or max-pooling) aggregated_hidden_state = torch.mean(hidden_states, dim=1) # Example: averaging # Pass through simple neural network output = self.simple_nn_model(aggregated_hidden_state) return output simple_nn = SimpleNN(input_size, hidden_size, output_size) for param in simple_nn.parameters(): param.requires_grad = True # Combine pre-trained model and simple neural network into a single model full_model = FullModel(model, simple_nn) # Loss function and optimizer criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(full_model.parameters(), lr=learning_rate)
已尝试训练预训练模型的最后一层,并将其输出传入简单全连接网络,但模型准确率始终停滞在35%,更换两个不同数据集后仍无改善,早停机制(patience=5)在7-10轮后触发,请问问题出在哪里?
核心问题排查与修复方案
1. 重复分类头导致的特征冲突
你同时修改了Wav2Vec2的lm_head为分类头,又额外加了SimpleNN做二次分类,属于冗余设计:
- Wav2Vec2的
lm_head参数虽开启梯度,但实际损失只监督SimpleNN的输出,等于白训练了这个头,还会干扰特征传递。 - 修复:二选一即可——要么删掉修改
lm_head的代码,只用SimpleNN做分类;要么去掉SimpleNN,直接用修改后的lm_head输出结果。
2. 特征聚合方式丢失时序信息
语音情感的关键特征(语调起伏、语速变化)都藏在时序维度里,单纯用torch.mean(hidden_states, dim=1)平均会抹平这些信息,导致模型无法捕捉情感差异。
- 优化方案:
- 改用多池化拼接:同时保留平均和最大池化结果,提升特征丰富度:
avg_pool = torch.mean(hidden_states, dim=1) max_pool = torch.max(hidden_states, dim=1)[0] aggregated = torch.cat([avg_pool, max_pool], dim=1) - 或者用注意力池化:让模型自动聚焦对情感更重要的时序片段:
attention_weights = torch.nn.functional.softmax(torch.sum(hidden_states, dim=-1), dim=1).unsqueeze(-1) aggregated = torch.sum(hidden_states * attention_weights, dim=1)
- 改用多池化拼接:同时保留平均和最大池化结果,提升特征丰富度:
3. 预训练模型冻结过度
Wav2Vec2是针对语音识别预训练的,和情感识别的特征分布差异很大,完全冻结所有参数会导致提取的特征适配性差。
- 修复:解冻最后3-5层编码器,让模型微调适配情感任务:
# 先冻结所有参数 for param in model.parameters(): param.requires_grad = False # 解冻最后3层编码器 for layer in model.encoder.layers[-3:]: for param in layer.parameters(): param.requires_grad = True
4. 输出层与损失函数冲突
CrossEntropyLoss内部已经包含了Softmax计算,你在SimpleNN末尾再加Softmax会导致数值不稳定,模型收敛困难。
- 修复:删掉SimpleNN中的
self.softmax = nn.Softmax(dim=1)以及forward里的x = self.softmax(x),直接输出fc2的结果。
5. 学习率设置不合理
0.001的学习率对微调预训练模型来说偏大,容易导致震荡;同时训练多个模块时,没有针对性的分层学习率也会影响效果。
- 优化方案:用分层学习率,预训练解冻层用小学习率,分类头用大学习率:
optimizer = optim.Adam([ {'params': model.encoder.layers[-3:].parameters(), 'lr': 1e-5}, {'params': simple_nn.parameters(), 'lr': 1e-3} ])
6. 数据集验证环节的潜在问题
换数据集仍无改善,要确认:
- 类别分布是否均衡?如果某类占比过高,模型会偏向多数类,准确率会卡在略高于随机水平(4类随机是25%)。
- 验证集划分是否合理?有没有出现训练/验证数据重叠的情况?
- 预处理是否正确?Wav2Vec2要求输入是原始音频波形,而非梅尔谱,要确认输入维度和格式是否符合要求。
内容的提问来源于stack exchange,提问作者Fathima Hanan Parakkot
相关产品推荐
相关产品推荐

