使用keras训练一个区分不同人声音的模型

随着tensorflow,keras,tflearn,mxnet这种深度学习库的完善,深度学习的门槛降低,很多之前很难的领域都开始对小白开放,比如语音领域,在深度学习火起来之前,语音识别和图像识别这种领域,没有很深的基本功和领域知识,根本不可能踏足,但是时代已经变了…

所以,我在某个项目中遇到了这样一个问题:给出一些电话录音,一方是客服人员,另一方是消费者,想要知道哪句话是谁说的,并且想要知道客服的态度怎么样。这属于那种看似简单,但是实际上很蛋疼的问题,今天我们集中探讨第一个问题,哪句话是谁说的。

由于项目中所有的电话录音都是没有经过标注的,所以我只好在开源数据集上进行实验,选用了清华30小时语料进行研究性训练。

清华大学的30小时数据集包含了25个不同中国人的1万条左右的语音,可以用来进行语音-文字转换和speaker recognization 的研究,在这期间也看了一些论文的实现,为了确定效果,我首先提取了语音的13阶mfcc特征,用一个1d卷积网络训练了一个男-女分类器,结果在测试集上效果奇好,达到了99%的准确率,但是这部分代码已经丢失了,就不贴出来了~

但是当我将在清华大学数据集上训练的男-女分类模型应用在项目里的电话数据上时,却发现效果很差,于是猜想是否分类器仅仅成功学习了那几个人的声音特征,于是,我开始构思如何搞一个针对不同人的声音特征分类器,首先,载入所有文件名

  1. import os
  2. # 训练样本路径
  3. wav_path = 'wav/train'
  4. # 获得训练用的wav文件路径列表
  5. def get_wav_files(wav_path=wav_path):
  6. wav_files = []
  7. for (dirpath, dirnames, filenames) in os.walk(wav_path):
  8. for filename in filenames:
  9. if filename.endswith('.wav') or filename.endswith('.WAV'):
  10. filename_path = os.sep.join([dirpath, filename])
  11. if os.stat(filename_path).st_size < 240000: # 剔除掉一些小文件
  12. continue
  13. wav_files.append(filename_path)
  14. return wav_files
  15. wav_files = get_wav_files()

文件名的形式是

 
  1. wav_files[4].split("\\")
  1. ['wav/train', 'A11', 'A11_101.WAV']

A11就是编号A11的人说的话了

然后需要抽取这些语音的mfcc特征,这里借助一个python_speech_features的库来取,根据某一篇论文的描述,我不光抽取了13阶mfcc特征,还抽取了这13阶特征的一阶差值和二阶差值,一共是39维特征:

 
  1. import sys
  2. import os
  3. import time
  4. import librosa
  5. import numpy as np
  6. import python_speech_features
  7. import scipy.io.wavfile as wav
  8. from python_speech_features import mfcc
  9. #train_x = []
  10. train_y = []
  11. begin_time = time.time()
  12. for i,onewav in enumerate(wav_files):
  13. if i % 5 == 4:
  14. gaptime = time.time() - begin_time
  15. percent = float(i) * 100 / len(wav_files)
  16. eta_time = gaptime * 100 / (percent + 0.01) - gaptime
  17. strprogress = "[" + "=" * int(percent // 2) + ">" + "-" * int(50 - percent // 2) + "]"
  18. str_log = ("%.2f %% %s %s/%s \t used:%ds eta:%d s" % (percent,strprogress,i,len(train_y),gaptime,eta_time))
  19. sys.stdout.write('\r' + str_log)
  20. label = onewav.split("\\")[1]
  21. (rate,sig) = wav.read(onewav)
  22. mfcc_feat = mfcc(scipy.signal.resample(sig,len(sig) // 2),rate // 2)
  23. mfcc_feat_div = np.concatenate((mfcc_feat[[0]],mfcc_feat[:-1]))
  24. mfcc_feat_div_div = mfcc_feat_div - np.concatenate((mfcc_feat_div[[0]],mfcc_feat_div[:-1]))
  25. finalfeature = np.concatenate((mfcc_feat,mfcc_feat_div,mfcc_feat_div_div),axis=1)
  26. train_x.append(finalfeature)
  27. train_y.append(label[1:])

然后把输入和输出分别处理成矩阵的形式,并且统一输入的长度:

  1. yy = LabelBinarizer().fit_transform(train_y)
  2. train_x = [ np.concatenate((i,np.zeros((1561-i.shape[0],39)))) for i in train_x]
  3. import numpy as np
  4. train_x = np.asarray(train_x)
  5. train_y = np.asarray(yy)
  6. print(train_x.shape,train_y.shape)

上面的代码会输出

  1. ((9709, 1561, 39), (9709, 25))

分别是训练集和测试集的形状

把训练集和测试集分开:

  1. from sklearn.cross_validation import train_test_split
  2. X_train, X_test, y_train, y_test = train_test_split(train_x, train_y, test_size=0.3, random_state=0)
  3. print(X_train.shape,X_test.shape,y_train.shape,y_test.shape)

上面的代码会输出:

  1. ((6796, 1561, 39), (2913, 1561, 39), (6796, 50), (2913, 50))

所以训练集和测试集分别有6796和2913条数据,然使用keras构建一个1d卷积模型:

  1. from keras.models import Sequential
  2. from keras.layers import LSTM,Dense,Activation,SimpleRNN,Conv1D,MaxPool1D,Flatten,Reshape
  3. from keras.callbacks import EarlyStopping
  4. from keras.metrics import categorical_accuracy
  5. from keras.optimizers import RMSprop
  6. model = Sequential()
  7. model.add(Conv1D(32,4,input_shape=(( 1561,39))))
  8. model.add(MaxPool1D(4))
  9. model.add(Conv1D(64,4))
  10. model.add(MaxPool1D(4))
  11. model.add(Flatten())
  12. model.add(Dense(32,activation='relu'))
  13. model.add(Dense(25,activation='softmax'))
  14. model.compile(loss="categorical_crossentropy",optimizer=RMSprop(lr=0.001),metrics=[categorical_accuracy])

然后训练这个模型:

  1. early_stopping=EarlyStopping(monitor='val_loss',patience=5)
  2. 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特征+神经网络可以很好的捕获到这种特征,所以我也没有继续努力提升模型在清华数据集上的准确度,而是转而开始准备标注电话录音的数据:

然后我们用类似上面的方法抽取特征,并且构建了一个类似的模型来区分接线员和客户:

  1. classifymodel = Sequential()
  2. classifymodel.add(Conv1D(32,4,input_shape=(( 300,39))))
  3. classifymodel.add(MaxPool1D(4))
  4. classifymodel.add(Conv1D(64,4))
  5. classifymodel.add(MaxPool1D(4))
  6. classifymodel.add(Flatten())
  7. classifymodel.add(Dense(32,activation='relu'))
  8. classifymodel.add(Dense(1,activation='sigmoid'))

在几轮之后这个模型给出了91%的准确率

  1. Train on 2060 samples, validate on 375 samples
  2. Epoch 1/4
  3. 2060/2060 [==============================] - 5s - loss: 0.3681 - binary_accuracy: 0.8413 - val_loss: 0.3157 - val_binary_accuracy: 0.8773
  4. Epoch 2/4
  5. 2060/2060 [==============================] - 1s - loss: 0.2744 - binary_accuracy: 0.9005 - val_loss: 0.2615 - val_binary_accuracy: 0.9147
  6. Epoch 3/4
  7. 2060/2060 [==============================] - 1s - loss: 0.2103 - binary_accuracy: 0.9228 - val_loss: 0.2895 - val_binary_accuracy: 0.9120
  8. Epoch 4/4
  9. 2060/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的一种,这里不展开,模型定义是这样的:

  1. from keras.layers import TimeDistributed, Bidirectional
  2. lstmmodel_1 = Sequential()
  3. lstmmodel_1.add(Bidirectional(LSTM(128, dropout=0.2, recurrent_dropout=0.2,input_shape=(300,39),return_sequences=True),input_shape=(300,39)))
  4. lstmmodel_1.add(Bidirectional(LSTM(128, dropout=0.2, recurrent_dropout=0.2,input_shape=(300,39),return_sequences=True)))
  5. lstmmodel_1.add(Flatten())
  6. lstmmodel_1.add(Dense(32))
  7. lstmmodel_1.add(Dense(1, activation='sigmoid'))

这个模型在经过一个小时的训练(6轮)之后得到了96%的准确率,也就是说,机器终于能以很高的准确率判断一段声音的来源了:

  1. Epoch 8/10
  2. 2048/2060 [============================>.] - ETA: 2s - loss: 0.1121 - binary_accuracy: 0.9585Epoch 00007: val_loss did not improve
  3. 2060/2060 [==============================] - 506s - loss: 0.1116 - binary_accuracy: 0.9587 - val_loss: 0.2130 - val_binary_accuracy: 0.9387
  4. Epoch 9/10
  5. 2048/2060 [============================>.] - ETA: 2s - loss: 0.1009 - binary_accuracy: 0.9668Epoch 00008: val_loss did not improve
  6. 2060/2060 [==============================] - 494s - loss: 0.1012 - binary_accuracy: 0.9665 - val_loss: 0.3132 - val_binary_accuracy: 0.9093
  7. Epoch 10/10
  8. 2048/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_1
  9. 2060/2060 [==============================] - 506s - loss: 0.0799 - binary_accuracy: 0.9689 - val_loss: 0.1596 - val_binary_accuracy: 0.9627
  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
生成奖杯的模型通常是一个生成对抗网络(GAN)。GAN由一个生成器和一个判别器组成,生成器试图生成逼真的奖杯图像,而判别器则尝试区分生成器生成的图像与真实奖杯图像。以下是一个基于TensorFlow的简单实现: 1. 导入必要的库 ``` import tensorflow as tf from tensorflow.keras import layers import numpy as np import matplotlib.pyplot as plt ``` 2. 定义生成器模型 生成器模型通常由多个转置卷积层(或反卷积层)组成,用于将低维的随机噪声(latent noise)转换为高维的图像。以下是一个简单的生成器模型: ``` def make_generator_model(): model = tf.keras.Sequential() model.add(layers.Dense(7*7*256, use_bias=False, input_shape=(100,))) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Reshape((7, 7, 256))) assert model.output_shape == (None, 7, 7, 256) model.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False)) assert model.output_shape == (None, 7, 7, 128) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False)) assert model.output_shape == (None, 14, 14, 64) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh')) assert model.output_shape == (None, 28, 28, 1) return model ``` 3. 定义判别器模型 判别器模型通常由多个卷积层组成,用于对图像进行分类。以下是一个简单的判别器模型: ``` def make_discriminator_model(): model = tf.keras.Sequential() model.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[28, 28, 1])) model.add(layers.LeakyReLU()) model.add(layers.Dropout(0.3)) model.add(layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same')) model.add(layers.LeakyReLU()) model.add(layers.Dropout(0.3)) model.add(layers.Flatten()) model.add(layers.Dense(1)) return model ``` 4. 定义损失函数 生成器和判别器的损失函数通常是对抗的。生成器试图最小化生成的图像与真实图像之间的差异,而判别器试图最大化生成器生成的图像与真实图像之间的差异。以下是对抗损失函数: ``` cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True) def discriminator_loss(real_output, fake_output): real_loss = cross_entropy(tf.ones_like(real_output), real_output) fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output) total_loss = real_loss + fake_loss return total_loss def generator_loss(fake_output): return cross_entropy(tf.ones_like(fake_output), fake_output) ``` 5. 定义优化器 生成器和判别器都需要使用优化器进行训练。以下是Adam优化器: ``` generator_optimizer = tf.keras.optimizers.Adam(1e-4) discriminator_optimizer = tf.keras.optimizers.Adam(1e-4) ``` 6. 定义训练循环 在训练循环中,我们将随机噪声喂给生成器,生成器生成伪造的奖杯图像,判别器将真实奖杯图像与伪造的奖杯图像进行分类。然后,我们计算生成器和判别器的损失,优化器将用于更新生成器和判别器的参数。以下是一个简单的训练循环: ``` @tf.function def train_step(images): noise = tf.random.normal([BATCH_SIZE, 100]) with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape: generated_images = generator(noise, training=True) real_output = discriminator(images, training=True) fake_output = discriminator(generated_images, training=True) gen_loss = generator_loss(fake_output) disc_loss = discriminator_loss(real_output, fake_output) gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables) gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables) generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables)) discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables)) ``` 7. 训练模型 最后,我们可以使用MNIST数据集训练我们的生成器和判别器模型。以下是一个简单的训练过程: ``` (train_images, train_labels), (_, _) = tf.keras.datasets.mnist.load_data() train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32') train_images = (train_images - 127.5) / 127.5 BUFFER_SIZE = 60000 BATCH_SIZE = 256 train_dataset = tf.data.Dataset.from_tensor_slices(train_images).shuffle(BUFFER_SIZE).batch(BATCH_SIZE) generator = make_generator_model() discriminator = make_discriminator_model() EPOCHS = 50 for epoch in range(EPOCHS): for image_batch in train_dataset: train_step(image_batch) if epoch % 10 == 0: print(f'Epoch {epoch}') generate_and_save_images(generator, epoch + 1, seed) ``` 在训练过程中,我们可以保存生成器生成的图像以进行可视化。生成器可以使用以下代码生成图像: ``` def generate_and_save_images(model, epoch, test_input): predictions = model(test_input, training=False) fig = plt.figure(figsize=(4, 4)) for i in range(predictions.shape[0]): plt.subplot(4, 4, i+1) plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5, cmap='gray') plt.axis('off') plt.savefig('image_at_epoch_{:04d}.png'.format(epoch)) plt.show() ``` 这是一个简单的生成奖杯的模型,可以根据需求进行改进。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值