摘要
语音情感自动识别是近几年来人机交互领域的研究热点。 然而,由于缺乏对语音波形特点及时间特点的研究,目前的识别精度有待提高。为了充分利用时间特征里情绪饱和度的差异,提出了一种利用帧级语音特征结合基于注意力机制的长期短时记忆(LSTM)递归神经网络模型进行语音识别的方法。从语音波形中提取帧级语音特征,取代传统的统计特征,通过帧的序列来保持原始语音中的时序关系。本项目提出了一种基于LSTM的语音识别及语音情感识别方法,使用该模型的根本原因是它能够获得更好的结果。 实验结果表明,该方法比其他方法更有效。
技术背景
在当今世界,语音识别,特别是语音情感识别正在得到越来越多的综合研究项目,这些项目交叉应用于心理学、模式识别、语音信号处理和人工智能。序列预测问题已经存在很长时间了。 它们被认为是数据科学行业最难解决的问题之一。 这些问题包括各种各样的问题;从预测销售到在股市数据中找到模式,从理解电影情节到识别你的说话方式,从语言翻译到预测你手机键盘上的下一个单词。随着数据科学最近的突破,人们发现,对于几乎所有这些序列预测问题,长期短期记忆网络(LSTMS)被观察到是最有效的解决方案。LSTM在许多方面都优于传统的前馈神经网络和RNN。 这是因为它们有选择地记住长时间的模式。 本文的目的是解释LSTM,并使您能够在现实生活中使用它。
实验步骤
为了完成我们的项目,需要采取一些重要的步骤。
首先,需要收集数据集。 对于这个项目,使用CASIA情感语音语料库。 这个语料库包含两个小时的自发情感片段,从219名从事电影,电视剧和脱口秀的人员中截取。 语料库的说话者数量使该数据库成为现有情感数据库的宝贵补充。 总共有24种非典型的情绪状态被三位母语为汉语的人标记。 与其他可用的情绪数据库相比,我们提供了多情绪标签和假/抑制情绪标签。 据我们所知,这个数据库是第一个处理多模态和自然情感的大型中国自然情感语料库。 然而,CASIA情感言语语料库是付费的。因此我们寻找了类似的情感语料库,其包含:愤怒、厌恶、恐惧、幸福、悲伤还有惊喜。基于此,我们增加了中性,以提供7种情绪类别的记录。
获取MFCC音频特征代码:
import numpy as np
import os
import sys
import scipy.io.wavfile as wav #reading wav files
from speechpy.feature import mfcc
from typing import Tuple
mean_signal_length = 32000
def gettingfeaturevectorfromMFCC(file_path: str, flatten: bool, mfcc_len: int = 39) -> np.ndarray:
fs, signal = wav.read(file_path)
s_len = len(signal)
if s_len < mean_signal_length:
pad_len = mean_signal_length - s_len
pad_rem = pad_len % 2
pad_len //= 2
signal = np.pad(signal, (pad_len, pad_len + pad_rem), 'constant', constant_values=0)
else:
pad_len = s_len - mean_signal_length
pad_len //= 2
signal = signal[pad_len:pad_len + mean_signal_length]
mel_coefficients = mfcc(signal, fs, num_cepstral=mfcc_len)
if flatten:
# Flatten the data
mel_coefficients = np.ravel(mel_coefficients)
return mel_coefficients
def get_data(data_path: str, flatten: bool = True, mfcc_len: int = 39,
class_labels: Tuple = ("Angry", "Disgust", "Fear", "Happy", "Neutral", "Sad", "Surprise")) -> \
Tuple[np.ndarray, np.ndarray]:
data = []
labels = []
names = []
cur_dir = os.getcwd()
sys.stderr.write('curdir: %s\n' % cur_dir)
os.chdir(data_path)
for i, directory in enumerate(class_labels):
sys.stderr.write("started reading folder %s\n" % directory)
os.chdir(directory)
for filename in os.listdir('.'):
filepath = os.getcwd() + '/' + filename
feature_vector = gettingfeaturevectorfromMFCC(file_path=filepath,
mfcc_len=mfcc_len,
flatten=flatten)
data.append(feature_vector)
labels.append(i)
names.append(filename)
sys.stderr.write("ended reading folder %s\n" % directory)
os.chdir('..')
os.chdir(cur_dir)
return np.array(data), np.array(labels)
模型代码实现:
inputs = Input(shape=(1, 6)) # 输入特征接收维度
lstm1=Bidirectional(LSTM(100, return_sequences=True))(inputs)
# lstm1=Bidirectional(LSTM(lstm_output_size))(max)
attlayer=Attention_layer()(lstm1)
dense_1 = Dense(100, activation='tanh')(attlayer)
output = Dense(1, activation='linear')(dense_1) # 输出类别概率
model = Model(inputs=inputs, outputs=output) # 初始命名训练的模型为model
model.summary()
主函数:
from keras.utils import np_utils
from codes.common import dataextraction
from recognitionpart.dnn import LSTM
from recognitionpart.utilities import gettingfeaturevectorfromMFCC
from keras.callbacks import EarlyStopping
#for speech recognition
import speech_recognition as sr
import pyttsx3
def speak(text):
engine = pyttsx3.init()
rate = engine.getProperty('rate')
engine.setProperty('rate', rate - 50)
engine.say(text)
#engine.save_to_file('test.wav')
engine.runAndWait()
def get_audio():
r = sr.Recognizer()
with sr.Microphone() as source:
audio = r.listen(source)
with open('speech.wav', 'wb') as f:
f.write(audio.get_wav_data())
said = ""
try:
said = r.recognize_google(audio)
print(said)
except Exception as e:
speak("Sorry, I could not understand what you said.")
return said
def lstm_example():
to_flatten = False
x_train, x_test, y_train, y_test, num_labels = dataextraction(
flatten=to_flatten)
y_train = np_utils.to_categorical(y_train)
y_test_train = np_utils.to_categorical(y_test)
print('Starting ATTLSTM')
model = LSTM(input_shape=x_train[0].shape,
num_classes=num_labels)
model.train(x_train, y_train, x_test, y_test_train, n_epochs=10)
evaluate = model.evaluate(x_test, y_test)
#speech recognition - take input from microphone
#after that save file in wav format and
#filename = to that file
user_speech= get_audio()
filename = 'speech.wav'
#filename = '../dataset/Neutral/n03.wav' #used in prediction
print('prediction', model.predict_one(
gettingfeaturevectorfromMFCC(filename, flatten=to_flatten)))
earlystop = EarlyStopping(monitor='val_acc', mode='max', patience=75, restore_best_weights=True)
# evaluate model, test data may differ from validation data
if __name__ == '__main__':
lstm_example()
实验结果:
由于模型实验很简单,最重要的部分是检查结果,看看模型有多准确。 如上所述,我们已经实现了双向LSTM(长期短期内存),以检查我们的算法在我们下载的数据集的准确性。 在sklearn库的帮助下,我们使用了confusion_matrix和准确性来检查我们的算法执行得有多好。 由于我们的数据集的培训和测试,我们在我们的项目中获得了超过90%的准确性。 正如您可能从图中看到的,我们得到了99%的训练数据集和0.95的测试数据集的准确性。 我们还通过拟合数据历史记录来检查数据集的丢失,正如您可能在我们得到的数字中看到的那样0.12对于测试数据集和0.07的训练数据集,这对我们的项目来说是足够好的。
结论
本文对基于注意力机制的LSTM在语音情感识别中的实现进行了详细的研究,并在进行特征提取后计算了模型的准确性。 在实验中,我们设计的模型准确率达到90%以上,使得算法工作良好。 然而,在未来的工作中,我们将试图找到提高算法精度的方法。
参考文献
1.Feature Extraction by DeepAI
2.SAVEE Database
3.A Gentle Introduction to Long Short-Term Memory Networks by the Experts
4.How to Develop a Bidirectional LSTM For Sequence Classification in Python with Keras