使用Python和Keras創建簡單語音識別引擎

不靠譜的貓 發佈 2020-02-20T13:10:44+00:00

test,test_rate = librosa.load#converting voice commands to text


語音識別是機器或程序識別口語中的單詞和短語並將其轉換為機器可讀格式的能力。通常,這些算法的簡單實現有一個有限的詞彙表,它可能只識別單詞/短語。但是,更複雜的算法(例如Cloud Speech-to-Text和Amazon Transcribe)具有廣泛的詞彙量,並包含方言、噪音和俚語。

在本文中,我將演示:

  • 語音轉文字的工作原理
  • 如何處理要轉錄的音頻
  • 使用Keras解決問題的深度學習模型
  • 一種評估此模型的方法
  • 將預測模型集成到項目中的腳本

簡介

語音只是由我們的聲帶引起的空氣周圍振動而產生的一系列聲波。這些聲波由麥克風記錄,然後轉換為電信號。然後使用高級信號處理技術處理信號,分離音節和單詞。得益於深度學習方面令人難以置信的最新進展,計算機也可以從經驗中學習理解語音。

語音識別通過聲學和語言建模使用算法來工作。聲學建模表示語音和音頻信號的語言單元之間的關係;語言建模將聲音與單詞序列進行匹配,以幫助區分聽起來相似的單詞。通常,基於循環層的深度學習模型用於識別語音中的時間模式,以提高系統內的準確性。也可以使用其他方法,例如隱馬爾可夫模型(第一個語音識別算法是使用這種方法)。在本文中,我將僅討論聲學模型。

信號處理

有多種方法可以將音頻波轉換為算法可以處理的元素,其中一種方法(在本教程中將使用的一種方法)是在等距的點上記錄聲波的高度:

我們每秒讀取數千次,並記錄一個代表當時聲波高度的數字。這是一個未壓縮的.wav音頻文件。「 CD質量」音頻以44.1 kHz(每秒44,100個讀數)採樣。但是對於語音識別而言,16khz(每秒16,000個樣本)的採樣率足以覆蓋人類語音的頻率範圍。

用這種方法,音頻是通過一個數字向量來表示的,其中每個數字以1/16000秒的間隔表示聲波的振幅。這個過程類似於圖像預處理,如下例所示:

多虧尼奎斯特定理(1933年— 弗拉基米爾·科特爾尼科夫(Vladimir Kotelnikov)),我們知道,只要採樣速度至少是我們要記錄的最高頻率的兩倍,我們就可以使用數學方法從間隔採樣中完美重建原始聲波。

Python庫

為了完成這個任務,我使用Anaconda環境(Python 3.7)和以下Python庫:

  • ipython (v 7.10.2)
  • keras (v 2.2.4)
  • librosa (v 0.7.2)
  • scipy (v 1.1.0)
  • sklearn (v 0.20.1)
  • sounddevice (v 0.3.14)
  • tensorflow (v 1.13.1)
  • tensorflow-gpu (v 1.13.1)
  • numpy (v 1.17.2)
from tensorflow.compat.v1 import ConfigProto
from tensorflow.compat.v1 import Session
import os
import librosa
import IPython.display as ipd
import matplotlib.pyplot as plt
import numpy as np
from scipy.io import wavfile
import warnings

config = ConfigProto()
config.gpu_options.allow_growth = True
sess = Session(config=config)

warnings.filterwarnings("ignore")

1.數據集

我們在實驗中使用TensorFlow提供的語音指令數據集。它包括由成千上萬不同的人發出的由30個短單詞組成的65000個一秒鐘長的話語。我們將建立一個語音識別系統,它可以理解簡單的語音命令。您可以從此處下載數據集(https://www.kaggle.com/c/tensorflow-speech-recognition-challenge)。

2.預處理音頻波

在使用的數據集中,一些記錄的持續時間少於1秒,並且採樣率太高。因此,讓我們閱讀聲波並使用下面的預處理步驟來解決這個問題。這是我們要執行的兩個步驟:

  • 重採樣
  • 刪除少於1秒的短命令

讓我們在下面的Python代碼片段中定義這些預處理步驟:

train_audio_path = './train/audio/'

all_wave = []
all_label = []
for label in labels:
    print(label)
    waves = [f for f in os.listdir(train_audio_path + '/'+ label) if f.endswith('.wav')]
    for wav in waves:
        samples, sample_rate = librosa.load(train_audio_path + '/' + label + '/' + wav, sr = 16000)
        samples = librosa.resample(samples, sample_rate, 8000)
        if(len(samples)== 8000) : 
            all_wave.append(samples)
            all_label.append(label)

由上可知,信號的採樣率為16000 hz。我們把它重採樣到8000赫茲,因為大多數語音相關的頻率都在8000赫茲。

第二步是處理我們的標籤,這裡我們將輸出標籤轉換為整數編碼,將整數編碼標籤轉換為one-hot 向量,因為這是一個多目標問題:

from sklearn.preprocessing import LabelEncoder
from keras.utils import np_utils

label_enconder = LabelEncoder()
y = label_enconder.fit_transform(all_label)
classes = list(label_enconder.classes_)
y = np_utils.to_categorical(y, num_classes=len(labels))

預處理步驟的最後一步是將2D數組reshape為3D,因為conv1d的輸入必須是3D數組:

all_wave = np.array(all_wave).reshape(-1,8000,1)

3.創建訓練和驗證集

為了執行我們的深度學習模型,我們將需要生成兩個集合(訓練和驗證)。對於此實驗,我使用80%的數據訓練模型,並在其餘20%的數據上進行驗證:

from sklearn.model_selection import train_test_split
x_train, x_valid, y_train, y_valid = train_test_split(np.array(all_wave),np.array(y),stratify=y,test_size = 0.2,random_state=777,shuffle=True)

4.機器學習模型架構

我使用Conv1d和GRU層來建模用於語音識別的網絡。Conv1d是一個僅在一維上進行卷積的卷積神經網絡,而GRU的目標是解決標準循環神經網絡的梯度消失問題。GRU也可以看作是LSTM的一個變體,因為兩者的設計相似,在某些情況下,可以產生同樣優秀的結果。

該模型基於deepspeech h2和Wav2letter++ algoritms這兩種著名的語音識別方法。下面的代碼演示了使用Keras提出的模型:

from keras.layers import Bidirectional, BatchNormalization, CuDNNGRU, TimeDistributed
from keras.layers import Dense, Dropout, Flatten, Conv1D, Input, MaxPooling1D
from keras.models import Model
from keras.callbacks import EarlyStopping, ModelCheckpoint
from keras import backend as K
K.clear_session()

inputs = Input(shape=(8000,1))
x = BatchNormalization(axis=-1, momentum=0.99, epsilon=1e-3, center=True, scale=True)(inputs)
#First Conv1D layer
x = Conv1D(8,13, padding='valid', activation='relu', strides=1)(x)
x = MaxPooling1D(3)(x)
x = Dropout(0.3)(x)
#Second Conv1D layer
x = Conv1D(16, 11, padding='valid', activation='relu', strides=1)(x)
x = MaxPooling1D(3)(x)
x = Dropout(0.3)(x)
#Third Conv1D layer
x = Conv1D(32, 9, padding='valid', activation='relu', strides=1)(x)
x = MaxPooling1D(3)(x)
x = Dropout(0.3)(x)
x = BatchNormalization(axis=-1, momentum=0.99, epsilon=1e-3, center=True, scale=True)(x)
x = Bidirectional(CuDNNGRU(128, return_sequences=True), merge_mode='sum')(x)
x = Bidirectional(CuDNNGRU(128, return_sequences=True), merge_mode='sum')(x)
x = Bidirectional(CuDNNGRU(128, return_sequences=False), merge_mode='sum')(x)
x = BatchNormalization(axis=-1, momentum=0.99, epsilon=1e-3, center=True, scale=True)(x)
#Flatten layer
# x = Flatten()(x)
#Dense Layer 1
x = Dense(256, activation='relu')(x)
outputs = Dense(len(labels), activation="softmax")(x)
model = Model(inputs, outputs)
model.summary()

注意:如果僅使用CPU來訓練此模型,請用GRU替換CuDNNGRU層。

下一步是將損失函數定義為分類交叉熵,因為它是一個多類分類問題:

model.compile(loss='categorical_crossentropy',optimizer='nadam',metrics=['accuracy'])

Early stopping和模型檢查點是回調,以在適當的時間停止訓練神經網絡並在每個epoch後保存最佳模型:

early_stop = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=10, min_delta=0.0001) 
checkpoint = ModelCheckpoint('speech2text_model.hdf5', monitor='val_acc', verbose=1, save_best_only=True, mode='max')

讓我們在32的batch size上訓練機器學習模型,並評估保留集上的性能:

hist = model.fit(
    x=x_train, 
    y=y_train,
    epochs=100, 
    callbacks=[early_stop, checkpoint], 
    batch_size=32, 
    validation_data=(x_valid,y_valid)
)

該命令的輸出為:


5.可視化

我將依靠可視化來了解機器學習模型在一段時間內的性能:

from matplotlib import pyplot
pyplot.plot(hist.history['loss'], label='train')
pyplot.plot(hist.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()

6.預測

在這一步中,我們將加載最佳的權重,並定義識別音頻和將其轉換為文本的函數:

from keras.models import load_model
model = load_model('speech2text_model.hdf5')

def s2t_predict(audio, shape_num=8000):
    prob=model.predict(audio.reshape(1,shape_num,1))
    index=np.argmax(prob[0])
    return classes[index]

對驗證數據進行預測:

import random
index=random.randint(0,len(x_valid)-1)
samples=x_valid[index].ravel()
print("Audio:",classes[np.argmax(y_valid[index])])
ipd.Audio(samples, rate=8000)

這是一個提示用戶錄製語音命令的腳本。可以錄製自己的語音命令,並在機器學習模型上測試:

import sounddevice as sd
import soundfile as sf

samplerate = 16000  
duration = 1 # seconds
filename = 'yes.wav'
print("start")
mydata = sd.rec(int(samplerate * duration), samplerate=samplerate,
    channels=1, blocking=True)
print("end")
sd.wait()
sf.write(filename, mydata, samplerate)

最後,我們創建一個腳本來讀取保存的語音命令並將其轉換為文本:

#reading the voice commands
test, test_rate = librosa.load('./test/left.wav', sr = 16000)
test_sample = librosa.resample(test, test_rate, 4351)
print(test_sample.shape)
ipd.Audio(test_sample,rate=8000)

#converting voice commands to text
s2t_predict(test_sample)

最後

語音識別技術已經成為我們日常生活的一部分,但目前仍局限於相對簡單的命令。隨著技術的進步,研究人員將能夠創造出更多能夠理解會話語音的智能系統。

關鍵字: