DeEAR开源模型教程:从零开始复现DeEAR训练流程(含wav2vec2微调脚本)
DeEAR开源模型教程:从零开始复现DeEAR训练流程(含wav2vec2微调脚本)
1. 引言:为什么需要语音情感识别?
你有没有想过,为什么有时候听一段语音,即使不看说话人的表情,也能感受到他的情绪?是开心、愤怒、悲伤还是平静?这背后就是语音中蕴含的情感信息在起作用。对于机器来说,理解语音中的情感一直是个难题,但DeEAR(Deep Emotional Expressiveness Recognition)这个开源项目,为我们提供了一个强大的工具。
简单来说,DeEAR是一个基于wav2vec2模型的深度语音情感表达分析系统。它能从一段语音中,分析出三个关键的情感维度:唤醒度(激动还是平静)、自然度(听起来自不自然)、韵律(说话的节奏感)。这有什么用呢?想象一下,智能客服能根据你的语气调整回复策略,在线教育平台能判断学生听课时的情绪状态,甚至心理辅导应用能通过语音分析用户的情绪变化。
本教程将手把手带你从零开始,复现DeEAR的完整训练流程。我会提供详细的wav2vec2微调脚本,并解释每一步背后的原理。即使你之前没有接触过语音情感识别,也能跟着这篇教程,搭建起自己的语音情感分析模型。
2. 环境准备与数据获取
2.1 搭建基础开发环境
工欲善其事,必先利其器。我们先来准备好运行DeEAR所需的环境。推荐使用Python 3.8及以上版本,并创建一个独立的虚拟环境,避免包版本冲突。
# 创建并激活虚拟环境(以conda为例)
conda create -n deear_env python=3.11
conda activate deear_env
# 安装PyTorch(请根据你的CUDA版本选择对应命令)
# 例如,CUDA 11.8版本
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
# 安装核心依赖库
pip install transformers==4.36.0
pip install datasets==2.16.0
pip install evaluate==0.4.1
pip install accelerate==0.25.0
pip install librosa==0.10.1
pip install scikit-learn==1.3.2
pip install gradio==4.13.0 # 用于后续的可视化界面
如果你使用的是预配置的镜像环境(比如CSDN星图镜像),通常这些依赖已经安装好了,可以直接通过启动脚本运行。
# 在镜像环境中快速启动DeEAR服务
/root/DeEAR_Base/start.sh
# 或者直接运行
python /root/DeEAR_Base/app.py
服务启动后,在浏览器中访问 http://localhost:7860 就能看到DeEAR的交互界面了。
2.2 获取情感语音数据集
模型训练离不开数据。对于语音情感识别,有几个公开可用的经典数据集:
- CREMA-D:包含7,442条由91位演员录制的语音片段,标注了6种基本情绪(高兴、悲伤、愤怒、恐惧、厌恶、中性)以及情感强度。
- RAVDESS:包含24位专业演员的语音和视频,涵盖8种情绪(平静、高兴、悲伤、愤怒、恐惧、惊讶、厌恶)。
- IEMOCAP:一个多模态数据集,包含视频、语音和文本,情感标注更为细致。
- EmoDB:德语情感语音数据库,包含7种情绪。
本教程以CREMA-D数据集为例,因为它规模适中、标注清晰,且易于获取。你可以从官方渠道申请下载,或者在一些开源数据平台找到它。
下载后,数据集的结构通常如下:
CREMA-D/
├── AudioWAV/ # 存放所有WAV格式的音频文件
│ ├── 1001_DFA_ANG_XX.wav
│ ├── 1001_DFA_DIS_XX.wav
│ └── ...
├── VideoFlash/ # 视频文件(本教程用不到)
└── processedResults/ # 可能包含一些处理结果
我们需要重点关注的是音频文件(.wav)和它们对应的情感标签。CREMA-D的文件名就包含了标签信息,例如1001_DFA_ANG_XX.wav:
1001: 说话人IDDFA: 句子内容代码ANG: 情感标签(ANG=愤怒)XX: 情感强度(HI=高,LO=低,MD=中,XX=未指定/中性)
3. 理解DeEAR的核心:wav2vec2模型
在开始写代码之前,我们需要先搞明白DeEAR的“大脑”是什么。它基于一个叫做wav2vec2的模型,这是Facebook AI(现Meta AI)在2020年提出的一个里程碑式的工作。
3.1 wav2vec2是如何“听”声音的?
你可以把wav2vec2想象成一个非常聪明的“听觉学徒”。它的学习过程分为两步:
-
无监督预训练(自学阶段):模型被扔进海量的、没有标注的语音数据里。它的任务是玩一个“填空游戏”:随机把一段连续语音中的某些小片段(比如0.01秒)盖住,然后尝试根据上下文猜出被盖住的部分是什么。通过这个游戏,它学会了语音中最基本的构成单元(称为“语音单元”或“声学特征”),比如不同的音素、音调变化等。这就像小孩在学会认字前,先大量听大人说话,潜移默化地掌握了语言的发音规律。
-
有监督微调(专项培训):有了强大的“听觉基础”后,我们再给它一个有标注的任务,比如情感分类。我们在预训练好的模型后面加一个简单的分类头(可以理解为一个答题卡),然后用CREMA-D这样标注了“高兴”、“悲伤”的数据集去训练它。这时,模型会调整参数,学会把之前学到的通用语音特征,映射到具体的情感标签上。
为什么用wav2vec2做情感识别?
- 能力强:它在语音识别等任务上已经证明了其强大的特征提取能力,这些特征同样适用于捕捉情感相关的声学线索(如音高、语速、能量)。
- 效率高:相比于训练一个模型从零开始识别情感,基于预训练的wav2vec2进行微调,所需的数据量更少,训练时间更短,效果通常更好。
- 通用性好:同一个预训练模型,可以通过微调适应不同的下游任务(如语音识别、语音情感识别、说话人识别等)。
3.2 DeEAR的三维情感分析
DeEAR没有简单地做“高兴/悲伤”这样的单一分类,而是采用了更细腻的三维分析法:
| 维度 | 它关心的是什么? | 举个例子 |
|---|---|---|
| 唤醒度 (Arousal) | 语音的“能量”水平,激动程度。 | 体育解说(高唤醒) vs 睡前故事(低唤醒) |
| 自然度 (Nature) | 语音听起来是否自然、流畅,像真人日常说话。 | 自然对话(自然) vs 机器人朗读或极度紧张的发言(不自然) |
| 韵律 (Prosody) | 语音的节奏、重音和语调变化。 | 朗诵诗歌(富有韵律) vs 平淡地念说明书(平淡) |
这种分析方法的好处是,它能更全面、更连续地描述情感状态,而不是非此即彼的标签。例如,一段语音可能“高度唤醒但不自然”(比如激动的结巴),或者“自然但缺乏韵律”(比如平淡的叙述)。
4. 从零开始:数据预处理与特征提取
现在,我们开始动手。第一步是把原始的音频文件,处理成模型能“吃”的格式。
4.1 加载并解析数据集
我们需要写一个脚本来读取CREMA-D的音频文件,并根据文件名解析出情感标签,同时为DeEAR任务构造三维标签。
import os
import pandas as pd
import librosa
import torchaudio
from pathlib import Path
# 情感标签映射字典 (根据CREMA-D文件名)
EMOTION_MAP = {
'ANG': 'anger',
'DIS': 'disgust',
'FEA': 'fear',
'HAP': 'happy',
'NEU': 'neutral',
'SAD': 'sadness'
}
# 为DeEAR任务构造三维标签的简单规则(示例,实际应根据你的标注或启发式规则)
def construct_deear_labels(emotion, intensity):
"""
根据基本情感和强度,构造唤醒度、自然度、韵律的伪标签。
这是一个简化示例,真实项目需要更精细的规则或人工标注。
"""
label_map = {
'arousal': 0.0, # 0-1之间的值,表示低到高
'nature': 0.0, # 0-1之间的值,表示不自然到自然
'prosody': 0.0 # 0-1之间的值,表示平淡到富有韵律
}
# 示例规则:愤怒、高兴、恐惧通常唤醒度高
if emotion in ['anger', 'happy', 'fear']:
label_map['arousal'] = 0.8
elif emotion == 'neutral':
label_map['arousal'] = 0.3
else:
label_map['arousal'] = 0.5
# 示例规则:中性、高兴的语音通常更自然
if emotion in ['neutral', 'happy']:
label_map['nature'] = 0.9
elif emotion in ['disgust', 'fear']: # 厌恶、恐惧可能不自然
label_map['nature'] = 0.4
else:
label_map['nature'] = 0.7
# 示例规则:悲伤、愤怒的语音可能更有韵律变化
if emotion in ['sadness', 'anger']:
label_map['prosody'] = 0.8
else:
label_map['prosody'] = 0.6
# 根据强度微调
if intensity == 'HI':
label_map['arousal'] = min(1.0, label_map['arousal'] + 0.15)
elif intensity == 'LO':
label_map['arousal'] = max(0.0, label_map['arousal'] - 0.15)
return label_map
def load_cremad_dataset(data_dir):
"""
加载CREMA-D数据集,并构建DataFrame。
"""
audio_dir = Path(data_dir) / "AudioWAV"
data = []
for audio_path in audio_dir.glob("*.wav"):
filename = audio_path.stem
parts = filename.split('_')
if len(parts) >= 4:
speaker_id = parts[0]
sentence_code = parts[1]
emotion_code = parts[2]
intensity_code = parts[3]
emotion = EMOTION_MAP.get(emotion_code, 'unknown')
# 构造DeEAR三维标签(这里用启发式规则,实际应用需调整)
deear_labels = construct_deear_labels(emotion, intensity_code)
data.append({
'file_path': str(audio_path),
'speaker_id': speaker_id,
'emotion': emotion,
'intensity': intensity_code,
'arousal': deear_labels['arousal'],
'nature': deear_labels['nature'],
'prosody': deear_labels['prosody']
})
df = pd.DataFrame(data)
print(f"成功加载 {len(df)} 条音频样本。")
print(df[['emotion', 'arousal', 'nature', 'prosody']].head())
return df
# 使用示例
data_dir = "/path/to/your/CREMA-D" # 替换为你的数据集路径
df = load_cremad_dataset(data_dir)
4.2 音频预处理与特征标准化
wav2vec2模型对输入音频有特定的要求:单声道、16kHz采样率。我们需要将音频统一处理成这个格式。
from transformers import Wav2Vec2FeatureExtractor
import torch
from datasets import Dataset, Audio
# 加载wav2vec2的特征提取器(与预训练模型配套)
model_name = "facebook/wav2vec2-base-960h" # 也可以使用其他变体,如"facebook/wav2vec2-large-960h-lv60"
feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained(model_name)
def preprocess_function(examples):
"""
批处理函数:加载音频并提取特征。
"""
# 使用datasets库的Audio功能加载并重采样音频
audio_arrays = [x["array"] for x in examples["audio"]]
# 特征提取器会自动处理padding和转换为模型需要的格式
inputs = feature_extractor(
audio_arrays,
sampling_rate=feature_extractor.sampling_rate,
padding=True,
return_tensors="pt",
max_length=16000 * 10, # 假设最长10秒,可根据数据调整
truncation=True
)
# 添加标签
inputs["labels_arousal"] = examples["arousal"]
inputs["labels_nature"] = examples["nature"]
inputs["labels_prosody"] = examples["prosody"]
return inputs
# 将Pandas DataFrame转换为Hugging Face Dataset格式
from datasets import Dataset
hf_dataset = Dataset.from_pandas(df)
# 添加音频列(datasets库会自动加载和缓存)
hf_dataset = hf_dataset.cast_column("file_path", Audio(sampling_rate=16000))
# 应用预处理函数
encoded_dataset = hf_dataset.map(
preprocess_function,
remove_columns=hf_dataset.column_names, # 移除原始列,只保留处理后的特征
batched=True,
batch_size=32
)
print(encoded_dataset[0]) # 查看一条处理后的样本
5. 核心实战:wav2vec2模型微调脚本
这是本教程最核心的部分。我们将编写一个完整的脚本,来微调wav2vec2模型,使其能够预测唤醒度、自然度和韵律这三个维度。
5.1 定义多任务回归模型
DeEAR需要同时预测三个连续值(回归任务),所以我们将在wav2vec2的基座模型上,添加一个自定义的回归头。
import torch
import torch.nn as nn
from transformers import Wav2Vec2Model, Wav2Vec2PreTrainedModel
from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss
class Wav2Vec2ForMultiTaskRegression(Wav2Vec2PreTrainedModel):
"""
自定义模型:基于wav2vec2,输出三个回归值(唤醒度、自然度、韵律)。
"""
def __init__(self, config):
super().__init__(config)
self.wav2vec2 = Wav2Vec2Model(config)
# 回归头:将wav2vec2的输出映射到三个维度
# wav2vec2-base的隐藏层大小是768
self.regressor = nn.Sequential(
nn.Dropout(config.final_dropout if hasattr(config, 'final_dropout') else 0.1),
nn.Linear(config.hidden_size, config.hidden_size),
nn.GELU(), # 激活函数
nn.Dropout(0.1),
nn.Linear(config.hidden_size, 3) # 输出3个值
)
# 初始化权重
self.post_init()
def forward(self, input_values, attention_mask=None, labels_arousal=None, labels_nature=None, labels_prosody=None):
# 1. 通过wav2vec2基座模型提取特征
outputs = self.wav2vec2(input_values, attention_mask=attention_mask)
# 取最后一层隐藏状态的平均值作为整个语音片段的表示
hidden_states = outputs.last_hidden_state # [batch_size, seq_len, hidden_size]
# 2. 应用注意力掩码,并计算有效部分的均值
if attention_mask is not None:
input_lengths = attention_mask.sum(-1) # 每个样本的有效长度
# 将padding部分置零
hidden_states = hidden_states * attention_mask.unsqueeze(-1).float()
# 对非padding部分求平均
pooled_output = hidden_states.sum(dim=1) / input_lengths.unsqueeze(-1).float()
else:
# 如果没有掩码,直接求全局平均
pooled_output = hidden_states.mean(dim=1)
# 3. 通过回归头得到预测值
logits = self.regressor(pooled_output) # [batch_size, 3]
arousal_pred, nature_pred, prosody_pred = logits[:, 0], logits[:, 1], logits[:, 2]
loss = None
# 4. 如果有标签,计算损失(均方误差损失,适用于回归任务)
if labels_arousal is not None and labels_nature is not None and labels_prosody is not None:
loss_fct = MSELoss()
loss_arousal = loss_fct(arousal_pred.squeeze(), labels_arousal.float())
loss_nature = loss_fct(nature_pred.squeeze(), labels_nature.float())
loss_prosody = loss_fct(prosody_pred.squeeze(), labels_prosody.float())
# 总损失为三个任务损失的加权和,这里简单相加
loss = loss_arousal + loss_nature + loss_prosody
# 返回结果
return {
'loss': loss,
'logits': logits,
'arousal_pred': arousal_pred,
'nature_pred': nature_pred,
'prosody_pred': prosody_pred,
'hidden_states': outputs.hidden_states,
'attentions': outputs.attentions
}
5.2 完整的训练脚本
现在,我们将数据加载、模型定义、训练循环整合在一起。
#!/usr/bin/env python3
"""
DeEAR模型训练脚本:微调wav2vec2进行三维语音情感回归。
"""
import os
import torch
import numpy as np
from datasets import Dataset, load_from_disk
from transformers import (
Wav2Vec2FeatureExtractor,
TrainingArguments,
Trainer,
EarlyStoppingCallback
)
from sklearn.model_selection import train_test_split
import evaluate
# 1. 加载预处理好的数据集
print("加载数据集...")
# 假设你已经运行了第4步的预处理,并保存了数据集
# encoded_dataset = load_from_disk("/path/to/your/processed_dataset")
# 这里我们创建一个模拟数据集用于演示(实际使用时请替换为真实数据)
def create_dummy_dataset(num_samples=1000):
data = {
'input_values': [np.random.randn(16000).astype(np.float32) for _ in range(num_samples)], # 模拟1秒音频
'attention_mask': [np.ones(16000, dtype=np.int64) for _ in range(num_samples)],
'labels_arousal': np.random.rand(num_samples).astype(np.float32),
'labels_nature': np.random.rand(num_samples).astype(np.float32),
'labels_prosody': np.random.rand(num_samples).astype(np.float32)
}
return Dataset.from_dict(data)
encoded_dataset = create_dummy_dataset(200)
# 划分训练集和验证集
train_testvalid = encoded_dataset.train_test_split(test_size=0.2, seed=42)
train_dataset = train_testvalid['train']
eval_dataset = train_testvalid['test']
print(f"训练集大小: {len(train_dataset)}")
print(f"验证集大小: {len(eval_dataset)}")
# 2. 加载特征提取器和模型
print("加载模型和特征提取器...")
model_name = "facebook/wav2vec2-base-960h"
feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained(model_name)
# 加载我们自定义的模型
from transformers import Wav2Vec2Config
config = Wav2Vec2Config.from_pretrained(model_name)
# 可以在这里修改配置,例如增加dropout防止过拟合
config.hidden_dropout = 0.1
config.attention_dropout = 0.1
config.final_dropout = 0.1
model = Wav2Vec2ForMultiTaskRegression.from_pretrained(
model_name,
config=config,
ignore_mismatched_sizes=True # 忽略回归头尺寸不匹配的警告
)
# 3. 定义评估指标(回归任务常用均方根误差RMSE和皮尔逊相关系数)
def compute_metrics(eval_pred):
predictions, labels = eval_pred
# predictions是模型输出,labels是真实标签
arousal_pred, nature_pred, prosody_pred = predictions[:, 0], predictions[:, 1], predictions[:, 2]
arousal_true, nature_true, prosody_true = labels[:, 0], labels[:, 1], labels[:, 2]
metrics = {}
from scipy.stats import pearsonr
import numpy as np
for name, pred, true in [('arousal', arousal_pred, arousal_true),
('nature', nature_pred, nature_true),
('prosody', prosody_pred, prosody_true)]:
# 计算均方误差 (MSE) 和均方根误差 (RMSE)
mse = np.mean((pred - true) ** 2)
rmse = np.sqrt(mse)
metrics[f'{name}_mse'] = float(mse)
metrics[f'{name}_rmse'] = float(rmse)
# 计算皮尔逊相关系数
if len(pred) > 1: # 需要至少两个点计算相关系数
corr, _ = pearsonr(pred, true)
metrics[f'{name}_pearsonr'] = float(corr)
else:
metrics[f'{name}_pearsonr'] = 0.0
# 计算平均绝对误差 (MAE)
mae = np.mean(np.abs(pred - true))
metrics[f'{name}_mae'] = float(mae)
# 三个维度的平均RMSE
avg_rmse = (metrics['arousal_rmse'] + metrics['nature_rmse'] + metrics['prosody_rmse']) / 3
metrics['avg_rmse'] = float(avg_rmse)
return metrics
# 4. 配置训练参数
training_args = TrainingArguments(
output_dir="./deear_wav2vec2_checkpoints", # 模型保存路径
evaluation_strategy="epoch", # 每个epoch后在验证集上评估
save_strategy="epoch", # 每个epoch后保存模型
learning_rate=1e-4, # 学习率,微调通常较小
per_device_train_batch_size=8, # 每个GPU的批次大小
per_device_eval_batch_size=8,
num_train_epochs=20, # 训练轮数
weight_decay=0.01, # 权重衰减,防止过拟合
logging_dir="./logs", # 日志目录
logging_steps=50,
load_best_model_at_end=True, # 训练结束后加载最佳模型
metric_for_best_model="avg_rmse", # 根据平均RMSE选择最佳模型
greater_is_better=False, # RMSE越小越好
report_to="tensorboard", # 可选:使用TensorBoard记录
push_to_hub=False, # 是否上传到Hugging Face Hub
seed=42,
)
# 5. 创建Trainer并开始训练
print("开始训练...")
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
compute_metrics=compute_metrics,
callbacks=[EarlyStoppingCallback(early_stopping_patience=3)], # 早停,防止过拟合
)
train_result = trainer.train()
# 6. 保存最终模型
print("训练完成,保存模型...")
trainer.save_model("./deear_wav2vec2_final")
feature_extractor.save_pretrained("./deear_wav2vec2_final")
print("模型已保存至 ./deear_wav2vec2_final")
# 7. 在测试集上评估最终性能(如果有独立的测试集)
# eval_results = trainer.evaluate(test_dataset)
# print(f"测试集性能: {eval_results}")
5.3 关键训练技巧与参数解读
- 学习率:微调预训练模型时,学习率通常设置得比较小(如1e-5到1e-4),以免破坏预训练阶段学到的宝贵知识。
- 批次大小:受限于GPU内存,语音模型的批次大小通常较小。可以尝试梯度累积来模拟更大的批次。
- 早停(Early Stopping):当验证集指标在连续几个epoch不再提升时,自动停止训练,这是防止过拟合的有效手段。
- 损失函数:对于回归任务,我们使用均方误差(MSE)。你也可以尝试平滑L1损失(Smooth L1 Loss),它对异常值不那么敏感。
- 评估指标:我们同时使用了RMSE(衡量预测误差大小)和皮尔逊相关系数(衡量预测趋势与真实值的一致性)。一个好的模型应该两者都表现良好。
6. 模型使用与结果解读
训练完成后,我们就可以用这个模型来分析新的语音了。
6.1 加载模型并进行预测
import torch
import librosa
import numpy as np
from transformers import Wav2Vec2FeatureExtractor
# 加载训练好的模型和特征提取器
model_path = "./deear_wav2vec2_final"
feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained(model_path)
model = Wav2Vec2ForMultiTaskRegression.from_pretrained(model_path)
model.eval() # 设置为评估模式
def predict_emotion(audio_path):
"""
对单条语音进行三维情感预测。
"""
# 1. 加载和预处理音频
speech, sr = librosa.load(audio_path, sr=16000, mono=True)
# 2. 提取特征
inputs = feature_extractor(
speech,
sampling_rate=16000,
return_tensors="pt",
padding=True,
max_length=16000 * 15, # 最长15秒
truncation=True
)
# 3. 模型预测
with torch.no_grad():
outputs = model(**inputs)
# 4. 获取预测结果并后处理
arousal = outputs.arousal_pred.item()
nature = outputs.nature_pred.item()
prosody = outputs.prosody_pred.item()
# 将输出限制在[0,1]范围内(假设你的标签也在0-1之间)
arousal = max(0.0, min(1.0, arousal))
nature = max(0.0, min(1.0, nature))
prosody = max(0.0, min(1.0, prosody))
# 5. 将连续值转换为类别描述(可选,更易理解)
def get_category(value, threshold=0.5):
return "高" if value > threshold else "低"
arousal_cat = get_category(arousal, 0.5)
nature_cat = get_category(nature, 0.5)
prosody_cat = get_category(prosody, 0.5)
results = {
'arousal': {'value': round(arousal, 3), 'category': arousal_cat},
'nature': {'value': round(nature, 3), 'category': nature_cat},
'prosody': {'value': round(prosody, 3), 'category': prosody_cat},
'interpretation': f"这段语音听起来{arousal_cat}唤醒、{nature_cat}自然、韵律{prosody_cat}。"
}
return results
# 使用示例
audio_file = "path/to/your/test_audio.wav"
result = predict_emotion(audio_file)
print("预测结果:")
for dim, info in result.items():
if dim != 'interpretation':
print(f" {dim}: {info['value']} ({info['category']})")
print(result['interpretation'])
6.2 结果可视化与解释
为了让结果更直观,我们可以用简单的图表来展示:
import matplotlib.pyplot as plt
def plot_deear_results(results_dict, title="DeEAR情感分析结果"):
"""
绘制三维情感分析雷达图。
"""
dimensions = ['唤醒度', '自然度', '韵律']
values = [results_dict['arousal']['value'],
results_dict['nature']['value'],
results_dict['prosody']['value']]
# 使雷达图闭合
values += values[:1]
angles = np.linspace(0, 2 * np.pi, len(dimensions), endpoint=False).tolist()
angles += angles[:1]
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(projection='polar'))
ax.plot(angles, values, 'o-', linewidth=2)
ax.fill(angles, values, alpha=0.25)
ax.set_xticks(angles[:-1])
ax.set_xticklabels(dimensions)
ax.set_ylim(0, 1)
ax.set_title(title, size=16, y=1.1)
# 添加网格和值标签
ax.grid(True)
for angle, value in zip(angles[:-1], values[:-1]):
ax.text(angle, value+0.05, f'{value:.2f}', ha='center')
plt.tight_layout()
plt.show()
# 使用示例
plot_deear_results(result, title="测试语音情感分析")
这个雷达图能直观展示一段语音在三个维度上的“情感轮廓”。例如,一段激昂的演讲可能在“唤醒度”和“韵律”上得分很高,但在“自然度”上得分较低。
7. 总结与进阶方向
通过这篇教程,我们完成了DeEAR语音情感识别模型从零开始的复现。我们学习了如何:
- 准备环境与数据:搭建Python环境,获取并预处理CREMA-D等情感语音数据集。
- 理解核心模型:了解了wav2vec2的工作原理及其在情感识别任务中的优势。
- 处理数据:将原始音频转换为模型输入,并构造三维情感标签。
- 构建与训练模型:编写了自定义的wav2vec2多任务回归模型,并完成了完整的训练流程。
- 使用与解读模型:加载训练好的模型进行预测,并可视化分析结果。
如果你想进一步探索,这里有一些进阶方向:
- 使用更高质量的数据集:尝试IEMOCAP等包含更丰富上下文和更细致标注的数据集。
- 改进标签构造:本教程使用了启发式规则构造三维标签。更可靠的方法是进行人工标注,或使用其他已标注了维度情感的数据集(如MSP-Podcast)。
- 尝试不同的模型架构:除了在wav2vec2后加简单回归头,可以尝试更复杂的结构,如LSTM、注意力机制来建模时序信息。
- 多模态融合:结合文本转写内容(可用wav2vec2的语音识别能力)或面部表情(如果有多模态数据),进行多模态情感分析。
- 部署与优化:将模型转换为ONNX或使用TorchScript进行优化,以便在移动端或边缘设备上高效运行。
语音情感识别是一个充满挑战和机遇的领域。DeEAR项目为我们提供了一个优秀的起点。希望这篇教程能帮助你快速上手,并在此基础上构建出更强大、更实用的语音情感分析应用。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐
所有评论(0)