随着tensorflow,keras,tflearn,mxnet这种深度学习库的完善,深度学习的门槛降低,很多之前很难的领域都开始对小白开放,比如语音领域,在深度学习火起来之前,语音识别和图像识别这种领域,没有很深的基本功和领域知识,根本不可能踏足,但是时代已经变了…
所以,我在某个项目中遇到了这样一个问题:给出一些电话录音,一方是客服人员,另一方是消费者,想要知道哪句话是谁说的,并且想要知道客服的态度怎么样。这属于那种看似简单,但是实际上很蛋疼的问题,今天我们集中探讨第一个问题,哪句话是谁说的。
由于项目中所有的电话录音都是没有经过标注的,所以我只好在开源数据集上进行实验,选用了清华30小时语料进行研究性训练。
清华大学的30小时数据集包含了25个不同中国人的1万条左右的语音,可以用来进行语音-文字转换和speaker recognization 的研究,在这期间也看了一些论文的实现,为了确定效果,我首先提取了语音的13阶mfcc特征,用一个1d卷积网络训练了一个男-女分类器,结果在测试集上效果奇好,达到了99%的准确率,但是这部分代码已经丢失了,就不贴出来了~
但是当我将在清华大学数据集上训练的男-女分类模型应用在项目里的电话数据上时,却发现效果很差,于是猜想是否分类器仅仅成功学习了那几个人的声音特征,于是,我开始构思如何搞一个针对不同人的声音特征分类器,首先,载入所有文件名
import os# 训练样本路径wav_path = 'wav/train'# 获得训练用的wav文件路径列表def get_wav_files(wav_path=wav_path):wav_files = []for (dirpath, dirnames, filenames) in os.walk(wav_path):for filename in filenames:if filename.endswith('.wav') or filename.endswith('.WAV'):filename_path = os.sep.join([dirpath, filename])if os.stat(filename_path).st_size < 240000: # 剔除掉一些小文件continuewav_files.append(filename_path)return wav_fileswav_files = get_wav_files()
文件名的形式是
wav_files[4].split("\\")
['wav/train', 'A11', 'A11_101.WAV']
A11就是编号A11的人说的话了
然后需要抽取这些语音的mfcc特征,这里借助一个python_speech_features的库来取,根据某一篇论文的描述,我不光抽取了13阶mfcc特征,还抽取了这13阶特征的一阶差值和二阶差值,一共是39维特征:
import sysimport osimport timeimport librosaimport numpy as npimport python_speech_featuresimport scipy.io.wavfile as wavfrom python_speech_features import mfcc#train_x = []train_y = []begin_time = time.time()for i,onewav in enumerate(wav_files):if i % 5 == 4:gaptime = time.time() - begin_timepercent = float(i) * 100 / len(wav_files)eta_time = gaptime * 100 / (percent + 0.01) - gaptimestrprogress = "[" + "=" * int(percent // 2) + ">" + "-" * int(50 - percent // 2) + "]"str_log = ("%.2f %% %s %s/%s \t used:%ds eta:%d s" % (percent,strprogress,i,len(train_y),gaptime,eta_time))sys.stdout.write('\r' + str_log)label = onewav.split("\\")[1](rate,sig) = wav.read(onewav)mfcc_feat = mfcc(scipy.signal.resample(sig,len(sig) // 2),rate // 2)mfcc_feat_div = np.concatenate((mfcc_feat[[0]],mfcc_feat[:-1]))mfcc_feat_div_div = mfcc_feat_div - np.concatenate((mfcc_feat_div[[0]],mfcc_feat_div[:-1]))finalfeature = np.concatenate((mfcc_feat,mfcc_feat_div,mfcc_feat_div_div),axis=1)train_x.append(finalfeature)train_y.append(label[1:])
然后把输入和输出分别处理成矩阵的形式,并且统一输入的长度:
yy = LabelBinarizer().fit_transform(train_y)train_x = [ np.concatenate((i,np.zeros((1561-i.shape[0],39)))) for i in train_x]import numpy as nptrain_x = np.asarray(train_x)train_y = np.asarray(yy)print(train_x.shape,train_y.shape)
上面的代码会输出
((9709, 1561, 39), (9709, 25))
分别是训练集和测试集的形状
把训练集和测试集分开:
from sklearn.cross_validation import train_test_splitX_train, X_test, y_train, y_test = train_test_split(train_x, train_y, test_size=0.3, random_state=0)print(X_train.shape,X_test.shape,y_train.shape,y_test.shape)
上面的代码会输出:
((6796, 1561, 39), (2913, 1561, 39), (6796, 50), (2913, 50))
所以训练集和测试集分别有6796和2913条数据,然使用keras构建一个1d卷积模型:
from keras.models import Sequentialfrom keras.layers import LSTM,Dense,Activation,SimpleRNN,Conv1D,MaxPool1D,Flatten,Reshapefrom keras.callbacks import EarlyStoppingfrom keras.metrics import categorical_accuracyfrom keras.optimizers import RMSpropmodel = Sequential()model.add(Conv1D(32,4,input_shape=(( 1561,39))))model.add(MaxPool1D(4))model.add(Conv1D(64,4))model.add(MaxPool1D(4))model.add(Flatten())model.add(Dense(32,activation='relu'))model.add(Dense(25,activation='softmax'))model.compile(loss="categorical_crossentropy",optimizer=RMSprop(lr=0.001),metrics=[categorical_accuracy])
然后训练这个模型:
early_stopping=EarlyStopping(monitor='val_loss',patience=5)model.fit(X_train[:,200:500,:],y_train,validation_data=(X_test[:,200:500,:],y_test),callbacks=[early_stopping],batch_size=16,epochs=1000)
在几轮训练之后,得到了75%的准确率,鉴于机器需要在25个人中选出一个声音的来源,这个准确率还算不错,由于在清华数据集上的训练仅仅是为了验证方法的合理性,而实验已经证明mfcc特征+神经网络可以很好的捕获到这种特征,所以我也没有继续努力提升模型在清华数据集上的准确度,而是转而开始准备标注电话录音的数据:
然后我们用类似上面的方法抽取特征,并且构建了一个类似的模型来区分接线员和客户:
classifymodel = Sequential()classifymodel.add(Conv1D(32,4,input_shape=(( 300,39))))classifymodel.add(MaxPool1D(4))classifymodel.add(Conv1D(64,4))classifymodel.add(MaxPool1D(4))classifymodel.add(Flatten())classifymodel.add(Dense(32,activation='relu'))classifymodel.add(Dense(1,activation='sigmoid'))
在几轮之后这个模型给出了91%的准确率
Train on 2060 samples, validate on 375 samplesEpoch 1/42060/2060 [==============================] - 5s - loss: 0.3681 - binary_accuracy: 0.8413 - val_loss: 0.3157 - val_binary_accuracy: 0.8773Epoch 2/42060/2060 [==============================] - 1s - loss: 0.2744 - binary_accuracy: 0.9005 - val_loss: 0.2615 - val_binary_accuracy: 0.9147Epoch 3/42060/2060 [==============================] - 1s - loss: 0.2103 - binary_accuracy: 0.9228 - val_loss: 0.2895 - val_binary_accuracy: 0.9120Epoch 4/42060/2060 [==============================] - 1s - loss: 0.2020 - binary_accuracy: 0.9325 - val_loss: 0.2734 - val_binary_accuracy: 0.9173
为了确定深度学习的确有效果,我分别用logistic regression 和 random forest 训练了两个baseline, logistic regression 训练出的模型准确率为85% ,random forest 也差不多。
之后我又尝试了很多很多的方法,许多方法不work,有些效果很差,但是也有好的,比如LSTM,LSTM是RNN的一种,这里不展开,模型定义是这样的:
from keras.layers import TimeDistributed, Bidirectionallstmmodel_1 = Sequential()lstmmodel_1.add(Bidirectional(LSTM(128, dropout=0.2, recurrent_dropout=0.2,input_shape=(300,39),return_sequences=True),input_shape=(300,39)))lstmmodel_1.add(Bidirectional(LSTM(128, dropout=0.2, recurrent_dropout=0.2,input_shape=(300,39),return_sequences=True)))lstmmodel_1.add(Flatten())lstmmodel_1.add(Dense(32))lstmmodel_1.add(Dense(1, activation='sigmoid'))
这个模型在经过一个小时的训练(6轮)之后得到了96%的准确率,也就是说,机器终于能以很高的准确率判断一段声音的来源了:
Epoch 8/102048/2060 [============================>.] - ETA: 2s - loss: 0.1121 - binary_accuracy: 0.9585Epoch 00007: val_loss did not improve2060/2060 [==============================] - 506s - loss: 0.1116 - binary_accuracy: 0.9587 - val_loss: 0.2130 - val_binary_accuracy: 0.9387Epoch 9/102048/2060 [============================>.] - ETA: 2s - loss: 0.1009 - binary_accuracy: 0.9668Epoch 00008: val_loss did not improve2060/2060 [==============================] - 494s - loss: 0.1012 - binary_accuracy: 0.9665 - val_loss: 0.3132 - val_binary_accuracy: 0.9093Epoch 10/102048/2060 [============================>.] - ETA: 2s - loss: 0.0790 - binary_accuracy: 0.9692Epoch 00009: val_loss improved from 0.16473 to 0.15963, saving model to model_save/lstm_model_12060/2060 [==============================] - 506s - loss: 0.0799 - binary_accuracy: 0.9689 - val_loss: 0.1596 - val_binary_accuracy: 0.9627
本文介绍了一种利用深度学习技术识别电话录音中说话人的方法。通过提取MFCC特征并使用1D卷积网络和LSTM模型,实现了较高准确率的说话人识别。


4506





