Эта статья взята из: [блог InTheWorld] (Добро пожаловать, чтобы оставить сообщение и обменяться)
В прошлом году я какое-то время изучал распознавание речи, но из-за некоторых соображений энергопотребления основное внимание было уделено реализации традиционного метода Spinx. Ограничения метода HMM вполне очевидны: современные передовые технологии распознавания речи в основном основаны на DNN. И RNN очень подходит для обработки последовательности речи. Ранее я наткнулся на проект обучения распознаванию речи на github, который предоставляет некоторые откалиброванные речевые данные, а также реализует некоторые демонстрационные коды. Однако автор этого проекта провел некоторую инкапсуляцию TensorFlow, из-за чего код получился немного извилистым, что на самом деле не способствует обучению новичков. Итак, я хочу использовать собственный API TensorFlow для реализации простой программы распознавания речи.
Честно говоря, у меня нет глубокого понимания RNN, поэтому я не буду здесь углубляться в принцип. С интуитивной точки зрения, структура RNN отражает отношение порядка в последовательности, поэтому RNN обладает хорошей способностью описывать модель последовательности. В книге «Глубокое обучение с тензорным потоком» RNN используется для реализации обучения модели классификации набора данных MNIST. Хотя набор данных MNIST представляет собой набор данных изображения, если мы рассматриваем строку пикселей как входной вектор, эти векторы-строки образуют последовательность по порядку. После экспериментов мы можем обнаружить, что RNN также может очень хорошо завершить классификацию данных MNIST.
1. Извлечение признаков речи
Среди методов выделения признаков речи MFCC (частотный кепстральный коэффициент Mel), вероятно, является наиболее распространенным. Проще говоря, MFCC — это краткосрочная характеристика частотной области. В Python мы можем легко использовать библиотеку librosa для извлечения функций MFCC. Процесс выделения признаков MFCC показан на рисунке ниже: сначала речевой сигнал делится на несколько сегментов по времени, затем каждый сегмент сигнала подвергается быстрому преобразованию Фурье, и после преобразования может быть получена спектрограмма; по энергетической огибающей спектрограммы, для этого Энергетическая огибающая дискретизируется для получения вектора. Этот вектор является вектором MFCC.
2. Обучение модели RNN
Благодаря функциям мы можем использовать TensorFlow для завершения построения и обучения модели. На самом деле модель очень простая, как показано на рисунке ниже, входной слой — это LSTM, а выходной слой — это слой Softmax. Кодирование вывода — однократное кодирование, а вход — набор многомерных векторов, расположенных в хронологическом порядке.
Поскольку эта модель очень проста, я просто вставлю код:
import os
import re
import sys
import wave
import numpy as np
import tensorflow as tf
from tensorflow.contrib import rnn
from random import shuffle
import librosa
path = "data/spoken_numbers_pcm/"
# learning_rate = 0.00001
# training_iters = 300000 #steps
# batch_size = 64
height=20 # mfcc features
width=80 # (max) length of utterance
classes=10 # digits
n_input = 20
n_steps = 80
n_hidden = 128
n_classes = 10
learning_rate = 0.001
training_iters = 100000
batch_size = 50
display_step = 10
x = tf.placeholder("float", [None, n_steps, n_input])
y = tf.placeholder("float", [None, n_classes])
weights = {
'out' : tf.Variable(tf.random_normal([n_hidden, n_classes]))
}
biases = {
'out' : tf.Variable(tf.random_normal([n_classes]))
}
def mfcc_batch_generator(batch_size=10):
# maybe_download(source, DATA_DIR)
batch_features = []
labels = []
files = os.listdir(path)
while True:
# print("loaded batch of %d files" % len(files))
shuffle(files)
for file in files:
if not file.endswith(".wav"): continue
wave, sr = librosa.load(path+file, mono=True)
mfcc = librosa.feature.mfcc(wave, sr)
label = dense_to_one_hot(int(file[0]),10)
labels.append(label)
# print(np.array(mfcc).shape)
mfcc = np.pad(mfcc,((0,0),(0,80-len(mfcc[0]))), mode='constant', constant_values=0)
batch_features.append(np.array(mfcc).T)
if len(batch_features) >= batch_size:
yield np.array(batch_features), np.array(labels)
batch_features = [] # Reset for next batch
labels = []
def dense_to_one_hot(labels_dense, num_classes=10):
return np.eye(num_classes)[labels_dense]
def RNN(x, weights, biases):
x = tf.unstack(x, n_steps, 1)
lstm_cell = rnn.BasicLSTMCell(n_hidden, forget_bias=1.0)
outputs, states = rnn.static_rnn(lstm_cell, x, dtype=tf.float32)
return tf.matmul(outputs[-1], weights['out']) + biases['out']
pred = RNN(x, weights, biases)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
correct_pred = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
step = 1
while step * batch_size < training_iters:
batch = mfcc_batch_generator(batch_size)
batch_x, batch_y = next(batch)
# print(batch_x.shape)
batch_x = batch_x.reshape((batch_size, n_steps, n_input))
sess.run(optimizer, feed_dict={x: batch_x, y: batch_y})
if step % display_step == 0:
acc = sess.run(accuracy, feed_dict={x: batch_x, y: batch_y})
loss = sess.run(cost, feed_dict={x: batch_x, y : batch_y})
print("Iter " + str(step*batch_size) + ", Minibatch Loss = " + \
"{:.6f}".format(loss) + ", Training Accuracy = " + \
"{:.5f}".format(acc))
step += 1
print("Optimization Finished!")
Набор данных можно найти на http://pannous.net/files/ скачать. Для этого примера вы можете просто загрузить файл Speaking_numbers_pcm.tar и извлечь его в каталог ./data/.
Следующие результаты обучения очень смущают, а тренировочный набор составляет всего 80+%. Кроме того, я нашел очень интересную вещь. Сначала я поменял местами размеры признаков MFCC с размерами временных срезов, а все остальное было примерно таким же. Во время обучения было обнаружено, что показатель точности на тренировочном наборе рано утром составлял 100%. Насчет того, почему в "правильном" измерении сходимость замедляется.Подозреваю, что это заполнение горшка временного ряда (недостаточные для n_step данные заполняются нулями). Такое поведение с заполнением нулями серьезно загрязнит данные во временном ряду, но это предположение нуждается в дальнейшей проверке.
Использованная литература:
【2】.Woohoo.speech.В это время.Растения.Количество/15-492/В руке...