我正在尝试使用 Keras 创建语音情感识别模型,我已经完成了所有代码并训练了模型。它的验证率约为 50%,并且过度拟合。
当我将 model.predict() 与未见过的数据结合使用时,似乎很难区分“中性”、“平静”、“高兴”和“惊讶”,但似乎能够在大多数情况下正确预测“愤怒”——我认为这是因为音调或其他方面存在明显差异。
我想可能是我没有从这些情绪中获得足够的特征,这将有助于模型区分它们。
目前我正在使用 Librosa 并将音频转换为 MFCC。有没有其他方法,即使使用 Librosa,我也可以提取模型的特征,以帮助它更好地区分“中性”、“平静”、“快乐”、“惊讶”等?
一些特征提取代码:
wav_clip, sample_rate = librosa.load(file_path, duration=3, mono=True, sr=None) mfcc = librosa.feature.mfcc(wav_clip, sample_rate)
此外,这是有 1400 个样本的。
在语音情感识别中,仅仅依赖 MFCC 特征可能不足以区分一些情感(如“中性”、“平静”、“快乐”和“惊讶”),因为它们的区别可能涉及更复杂的特征,比如音量变化、语速、音高等。以下是改进特征提取和模型性能的一些建议:
除了 MFCC,尝试提取以下特征:
音高(Pitch):情感通常与音高变化相关,特别是“高兴”和“惊讶”。 py pitch, _ = librosa.piptrack(y=wav_clip, sr=sample_rate)
py pitch, _ = librosa.piptrack(y=wav_clip, sr=sample_rate)
基频(Fundamental Frequency, F0):可以使用 librosa.pyin 提取基频。 py f0 = librosa.pyin(wav_clip, fmin=librosa.note_to_hz('C2'), fmax=librosa.note_to_hz('C7'))
librosa.pyin
py f0 = librosa.pyin(wav_clip, fmin=librosa.note_to_hz('C2'), fmax=librosa.note_to_hz('C7'))
短时能量(Short-Time Energy, STE):捕捉语音强度变化。 py energy = librosa.feature.rms(y=wav_clip)
py energy = librosa.feature.rms(y=wav_clip)
过零率(Zero-Crossing Rate, ZCR):可以反映语音信号的变化率。 py zcr = librosa.feature.zero_crossing_rate(y=wav_clip)
py zcr = librosa.feature.zero_crossing_rate(y=wav_clip)
py intervals = librosa.effects.split(y=wav_clip, top_db=20) speech_duration = sum((end - start) for start, end in intervals) / sample_rate
光谱质心(Spectral Centroid):表示频率分布的“重心”。 py spectral_centroid = librosa.feature.spectral_centroid(y=wav_clip, sr=sample_rate)
py spectral_centroid = librosa.feature.spectral_centroid(y=wav_clip, sr=sample_rate)
光谱带宽(Spectral Bandwidth):表示频谱的宽度。 py spectral_bandwidth = librosa.feature.spectral_bandwidth(y=wav_clip, sr=sample_rate)
py spectral_bandwidth = librosa.feature.spectral_bandwidth(y=wav_clip, sr=sample_rate)
梅尔频谱(Mel Spectrogram):比 MFCC 捕获更多频谱信息。 py mel_spec = librosa.feature.melspectrogram(y=wav_clip, sr=sample_rate)
py mel_spec = librosa.feature.melspectrogram(y=wav_clip, sr=sample_rate)
通过数据增强扩展你的数据集,尤其是对于类别不平衡的数据。可以尝试以下方法:
时间拉伸(Time Stretching): py stretched = librosa.effects.time_stretch(wav_clip, rate=1.1)
py stretched = librosa.effects.time_stretch(wav_clip, rate=1.1)
音高偏移(Pitch Shift): py shifted = librosa.effects.pitch_shift(wav_clip, sr=sample_rate, n_steps=4)
py shifted = librosa.effects.pitch_shift(wav_clip, sr=sample_rate, n_steps=4)
添加背景噪声: py noise = np.random.normal(0, 0.005, wav_clip.shape) wav_clip_noisy = wav_clip + noise
py noise = np.random.normal(0, 0.005, wav_clip.shape) wav_clip_noisy = wav_clip + noise
动态范围变化(Dynamic Range Compression)。
若模型过拟合,可能是模型容量过大或数据不足。尝试以下方法:
py model.add(Dropout(0.5)) model.add(Dense(128, kernel_regularizer=keras.regularizers.l2(0.01)))
对特征进行归一化或标准化,确保输入特征在同一范围。
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() features = scaler.fit_transform(features)
将特征转换为时间-频率图(如梅尔频谱图或 MFCC 图),并输入 CNN 模型。
mel_spec = librosa.feature.melspectrogram(y=wav_clip, sr=sample_rate) mel_db = librosa.power_to_db(mel_spec, ref=np.max)
验证模型性能时,可以观察混淆矩阵和分类报告:
from sklearn.metrics import classification_report, confusion_matrix y_pred = model.predict(X_test) y_pred_classes = np.argmax(y_pred, axis=1) print(classification_report(y_test, y_pred_classes))
关注哪些类别最容易混淆,可能需要调整数据分布或特征。
考虑使用预训练的音频特征提取模型(如 OpenL3 或 Wav2Vec),从更复杂的特征中获益。
通过这些改进,你的模型应该能更好地区分相似情绪。如果有更多问题或实验结果,可以进一步讨论!