用Python 訓練自己的語音識別系統,這波操作穩了

2021-01-07 AI科技大本營

作者 | 李秋鍵

責編 | Carol

封圖 | CSDN 付費下載自視覺中國

近幾年來語音識別技術得到了迅速發展,從手機中的Siri語音智能助手、微軟的小娜以及各種平臺的智能音箱等等,各種語音識別的項目得到了廣泛應用。

語音識別屬於感知智能,而讓機器從簡單的識別語音到理解語音,則上升到了認知智能層面,機器的自然語言理解能力如何,也成為了其是否有智慧的標誌,而自然語言理解正是目前難點。

同時考慮到目前大多數的語音識別平臺都是藉助於智能雲,對於語音識別的訓練對於大多數人而言還較為神秘,故今天我們將利用python搭建自己的語音識別系統。

最終模型的識別效果如下:

實驗前的準備

首先我們使用的python版本是3.6.5所用到的庫有cv2庫用來圖像處理;

Numpy庫用來矩陣運算;Keras框架用來訓練和加載模型。Librosa和python_speech_features庫用於提取音頻特徵。Glob和pickle庫用來讀取本地數據集。

數據集準備

首先數據集使用的是清華大學的thchs30中文數據。

這些錄音根據其文本內容分成了四部分,A(句子的ID是1~250),B(句子的ID是251~500),C(501~750),D(751~1000)。ABC三組包括30個人的10893句發音,用來做訓練,D包括10個人的2496句發音,用來做測試。

data文件夾中包含(.wav文件和.trn文件;trn文件裡存放的是.wav文件的文字描述:第一行為詞,第二行為拼音,第三行為音素);

數據集如下:

模型訓練

1、提取語音數據集的MFCC特徵:

首先人的聲音是通過聲道產生的,聲道的形狀決定了發出怎樣的聲音。如果我們可以準確的知道這個形狀,那麼我們就可以對產生的音素進行準確的描述。聲道的形狀在語音短時功率譜的包絡中顯示出來。而MFCCs就是一種準確描述這個包絡的一種特徵。

其中提取的MFCC特徵如下圖可見。

故我們在讀取數據集的基礎上,要將其語音特徵提取存儲以方便加載入神經網絡進行訓練。

其對應的代碼如下:

#讀取數據集文件

text_paths = glob.glob('data/*.trn')

total = len(text_paths)

print(total)

with open(text_paths[0], 'r', encoding='utf8') as fr:

lines = fr.readlines

print(lines)

#數據集文件trn內容讀取保存到數組中

texts =

paths =

for path in text_paths:

with open(path, 'r', encoding='utf8') as fr:

lines = fr.readlines

line = lines[0].strip('\n').replace(' ', '')

texts.append(line)

paths.append(path.rstrip('.trn'))

print(paths[0], texts[0])

#定義mfcc數

mfcc_dim = 13

#根據數據集標定的音素讀入

def load_and_trim(path):

audio, sr = librosa.load(path)

energy = librosa.feature.rmse(audio)

frames = np.nonzero(energy >= np.max(energy) / 5)

indices = librosa.core.frames_to_samples(frames)[1]

audio = audio[indices[0]:indices[-1]] if indices.size else audio[0:0]

return audio, sr

#提取音頻特徵並存儲

features =

for i in tqdm(range(total)):

path = paths[i]

audio, sr = load_and_trim(path)

features.append(mfcc(audio, sr, numcep=mfcc_dim, nfft=551))

print(len(features), features[0].shape)

2、神經網絡預處理:

在進行神經網絡加載訓練前,我們需要對讀取的MFCC特徵進行歸一化,主要目的是為了加快收斂,提高效果和減少幹擾。然後處理好數據集和標籤定義輸入和輸出即可。

對應代碼如下:

#隨機選擇100個數據集

samples = random.sample(features, 100)

samples = np.vstack(samples)

#平均MFCC的值為了歸一化處理

mfcc_mean = np.mean(samples, axis=0)

#計算標準差為了歸一化

mfcc_std = np.std(samples, axis=0)

print(mfcc_mean)

print(mfcc_std)

#歸一化特徵

features = [(feature - mfcc_mean) / (mfcc_std + 1e-14) for feature in features]

#將數據集讀入的標籤和對應id存儲列表

chars = {}

for text in texts:

for c in text:

chars[c] = chars.get(c, 0) + 1

chars = sorted(chars.items, key=lambda x: x[1], reverse=True)

chars = [char[0] for char in chars]

print(len(chars), chars[:100])

char2id = {c: i for i, c in enumerate(chars)}

id2char = {i: c for i, c in enumerate(chars)}

data_index = np.arange(total)

np.random.shuffle(data_index)

train_size = int(0.9 * total)

test_size = total - train_size

train_index = data_index[:train_size]

test_index = data_index[train_size:]

#神經網絡輸入和輸出X,Y的讀入數據集特徵

X_train = [features[i] for i in train_index]

Y_train = [texts[i] for i in train_index]

X_test = [features[i] for i in test_index]

Y_test = [texts[i] for i in test_index]

3、神經網絡函數定義:

其中包括訓練的批次,卷積層函數、標準化函數、激活層函數等等。

其中第個維度為段的個數,原始語越長,第個維度也越, 第個維度為 MFCC 特徵的維度。得到原始語的數值表後,就可以使 WaveNet 實現。由於 MFCC 特徵為維序列,所以使 Conv1D 進卷積。 因果是指,卷積的輸出只和當前位置之前的輸有關,即不使未來的 特徵,可以理解為將卷積的位置向前偏移。WaveNet 模型結構如下所:

具體如下可見:

batch_size = 16

#定義訓練批次的產生,一次訓練16個

def batch_generator(x, y, batch_size=batch_size):

offset = 0

while True:

offset += batch_size

if offset == batch_size or offset >= len(x):

data_index = np.arange(len(x))

np.random.shuffle(data_index)

x = [x[i] for i in data_index]

y = [y[i] for i in data_index]

offset = batch_size

X_data = x[offset - batch_size: offset]

Y_data = y[offset - batch_size: offset]

X_maxlen = max([X_data[i].shape[0] for i in range(batch_size)])

Y_maxlen = max([len(Y_data[i]) for i in range(batch_size)])

X_batch = np.zeros([batch_size, X_maxlen, mfcc_dim])

Y_batch = np.ones([batch_size, Y_maxlen]) * len(char2id)

X_length = np.zeros([batch_size, 1], dtype='int32')

Y_length = np.zeros([batch_size, 1], dtype='int32')

for i in range(batch_size):

X_length[i, 0] = X_data[i].shape[0]

X_batch[i, :X_length[i, 0], :] = X_data[i]

Y_length[i, 0] = len(Y_data[i])

Y_batch[i, :Y_length[i, 0]] = [char2id[c] for c in Y_data[i]]

inputs = {'X': X_batch, 'Y': Y_batch, 'X_length': X_length, 'Y_length': Y_length}

outputs = {'ctc': np.zeros([batch_size])}

epochs = 50

num_blocks = 3

filters = 128

X = Input(shape=(None, mfcc_dim,), dtype='float32', name='X')

Y = Input(shape=(None,), dtype='float32', name='Y')

X_length = Input(shape=(1,), dtype='int32', name='X_length')

Y_length = Input(shape=(1,), dtype='int32', name='Y_length')

#卷積1層

def conv1d(inputs, filters, kernel_size, dilation_rate):

return Conv1D(filters=filters, kernel_size=kernel_size, strides=1, padding='causal', activation=None,

dilation_rate=dilation_rate)(inputs)

#標準化函數

def batchnorm(inputs):

return BatchNormalization(inputs)

#激活層函數

def activation(inputs, activation):

return Activation(activation)(inputs)

#全連接層函數

def res_block(inputs, filters, kernel_size, dilation_rate):

hf = activation(batchnorm(conv1d(inputs, filters, kernel_size, dilation_rate)), 'tanh')

hg = activation(batchnorm(conv1d(inputs, filters, kernel_size, dilation_rate)), 'sigmoid')

h0 = Multiply([hf, hg])

ha = activation(batchnorm(conv1d(h0, filters, 1, 1)), 'tanh')

hs = activation(batchnorm(conv1d(h0, filters, 1, 1)), 'tanh')

return Add([ha, inputs]), hs

h0 = activation(batchnorm(conv1d(X, filters, 1, 1)), 'tanh')

shortcut =

for i in range(num_blocks):

for r in [1, 2, 4, 8, 16]:

h0, s = res_block(h0, filters, 7, r)

shortcut.append(s)

h1 = activation(Add(shortcut), 'relu')

h1 = activation(batchnorm(conv1d(h1, filters, 1, 1)), 'relu')

#softmax損失函數輸出結果

Y_pred = activation(batchnorm(conv1d(h1, len(char2id) + 1, 1, 1)), 'softmax')

sub_model = Model(inputs=X, outputs=Y_pred)

#計算損失函數

def calc_ctc_loss(args):

y, yp, ypl, yl = args

return K.ctc_batch_cost(y, yp, ypl, yl)

4、模型的訓練:

訓練的過程如下可見:

ctc_loss = Lambda(calc_ctc_loss, output_shape=(1,), name='ctc')([Y, Y_pred, X_length, Y_length])

#加載模型訓練

model = Model(inputs=[X, Y, X_length, Y_length], outputs=ctc_loss)

#建立優化器

optimizer = SGD(lr=0.02, momentum=0.9, nesterov=True, clipnorm=5)

#激活模型開始計算

model.compile(loss={'ctc': lambda ctc_true, ctc_pred: ctc_pred}, optimizer=optimizer)

checkpointer = ModelCheckpoint(filepath='asr.h5', verbose=0)

lr_decay = ReduceLROnPlateau(monitor='loss', factor=0.2, patience=1, min_lr=0.000)

#開始訓練

history = model.fit_generator(

generator=batch_generator(X_train, Y_train),

steps_per_epoch=len(X_train) // batch_size,

epochs=epochs,

validation_data=batch_generator(X_test, Y_test),

validation_steps=len(X_test) // batch_size,

callbacks=[checkpointer, lr_decay])

#保存模型

sub_model.save('asr.h5')

#將字保存在pl=pkl中

with open('dictionary.pkl', 'wb') as fw:

pickle.dump([char2id, id2char, mfcc_mean, mfcc_std], fw)

train_loss = history.history['loss']

valid_loss = history.history['val_loss']

plt.plot(np.linspace(1, epochs, epochs), train_loss, label='train')

plt.plot(np.linspace(1, epochs, epochs), valid_loss, label='valid')

plt.legend(loc='upper right')

plt.xlabel('Epoch')

plt.ylabel('Loss')

plt.show

測試模型

讀取我們語音數據集生成的字典,通過調用模型來對音頻特徵識別。

代碼如下:

wavs = glob.glob('A2_103.wav')

print(wavs)

with open('dictionary.pkl', 'rb') as fr:

[char2id, id2char, mfcc_mean, mfcc_std] = pickle.load(fr)

mfcc_dim = 13

model = load_model('asr.h5')

index = np.random.randint(len(wavs))

print(wavs[index])

audio, sr = librosa.load(wavs[index])

energy = librosa.feature.rmse(audio)

frames = np.nonzero(energy >= np.max(energy) / 5)

indices = librosa.core.frames_to_samples(frames)[1]

audio = audio[indices[0]:indices[-1]] if indices.size else audio[0:0]

X_data = mfcc(audio, sr, numcep=mfcc_dim, nfft=551)

X_data = (X_data - mfcc_mean) / (mfcc_std + 1e-14)

print(X_data.shape)

pred = model.predict(np.expand_dims(X_data, axis=0))

pred_ids = K.eval(K.ctc_decode(pred, [X_data.shape[0]], greedy=False, beam_width=10, top_paths=1)[0][0])

pred_ids = pred_ids.flatten.tolist

print(''.join([id2char[i] for i in pred_ids]))

yield (inputs, outputs)

到這裡,我們整體的程序就搭建完成,下面為我們程序的運行結果:

源碼地址:

提取碼:ndrr

數據集需要自行下載。

作者簡介:李秋鍵,CSDN博客專家,CSDN達人課作者。碩士在讀於中國礦業大學,開發有taptap競賽獲獎等等。

相關焦點

  • 基於Julius的機器人語音識別系統構建
    語音識別技術的發展,使得這一理想得以實現,把語音識別技術與機器人控制技術相結合,正成為目前研究的熱點,不但具有較好的理論意義,而且有較大的實用價值。   語音識別技術應用於機器人系統大多是針對特定的環境,設計出語音命令來進行控制的。
  • 專注E2E語音識別,騰訊AILab開源語音處理工具包PIKA
    機器之心報導作者:魔王、杜偉PyTorch + Kaldi,騰訊 AI Lab 開源輕量級語音處理工具包 PIKA,專注於端到端語音識別任務。Kaldi 是一個開源的語音識別系統,由 Daniel Povey 主導開發,在很多語音識別測試和應用中廣泛使用。
  • 語音識別原理及其語音識別系統分類
    人類希望能與機器進一步溝通,從而方便生產與生活,而在語音信號的傳輸過程中,我們不規則的語言行為方式會被背景噪聲和回聲,以及電特性(如話筒等電子設備)進一步扭曲。這一切可變性的聲音來源語音識別更加繁瑣複雜。
  • 使用Python和Keras創建簡單語音識別引擎
    得益於深度學習方面令人難以置信的最新進展,計算機也可以從經驗中學習理解語音。語音識別通過聲學和語言建模使用算法來工作。聲學建模表示語音和音頻信號的語言單元之間的關係;語言建模將聲音與單詞序列進行匹配,以幫助區分聽起來相似的單詞。通常,基於循環層的深度學習模型用於識別語音中的時間模式,以提高系統內的準確性。也可以使用其他方法,例如隱馬爾可夫模型(第一個語音識別算法是使用這種方法)。
  • DSP開發板的語音識別系統的研究
    1 系統參數選擇  一般情況下,語音識別系統按照不同的角度、不同的應用範圍、不同的性能要求有不同的分類方法。針對識別對象不同有孤立詞識別、連接詞識別、連續語音識別與理解和會話語音識別等。針對識別系統的詞彙量有小詞彙量語音識別(1~20個詞彙)、中詞彙量識別(20~1 000個詞彙)和大詞彙量(1 000以上個詞彙)語音識別。
  • 基於嵌入式Linux的語音識別系統硬軟體設計
    在嵌入式Linux作業系統下,運用多進程機制完成了對語音識別晶片、超聲波測距和雲臺的控制,並將語音識別技術應用於多角度超聲波測距系統中。通過測試,系統可以通過識別語音指令控制測量方向,無需手動幹預,最後將測量結果通過語音播放出來。
  • 基於DeepSpeech2實現中文語音識別,實施全流程講解,拿來即用
    你是否在苦苦尋找能識別中文的語音識別模型?那認真看完本文,你也能實現,本文可能為您節省少則幾小時多則數天的工作時間。DeepSpeech2由百度矽谷AI實驗室在2015年發布,是一個採用PaddlePaddle深度學習框架實現的端到端自動語音識別系統,它能通過簡單學習算法較準確的識別英語和中文。
  • 基於DSP的語音識別系統的實現及分析
    語音識別系統一般包括前端處理、特徵參數提取、模型訓練和識別部分。圖1所示是基於模式匹配原理的語音識別系統框圖。    1.3 模型訓練及模式識別  在識別系統後端,從已知模式中獲取用以表徵該模式本質特徵的模型參數即形成模式庫,再將輸入的語音提取特徵矢量參數後與已建立的聲學模型進行相似度比較,同時根據一定的專家知識(如構詞規則,語法規則等)和判別規則決策出最終的識別結果。
  • 用python識別驗證碼
    今天,我們就簡單的說下,怎麼用python來處理驗證碼。(注意:我所有的python相關的文章用的都是python3。)準備工作1、tesseract-ocr軟體Tesseract的OCR引擎最先由HP實驗室於1985年開始研發,至1995年時已經成為OCR業內最準確的三款識別引擎之一。然而,HP不久便決定放棄OCR業務,Tesseract也從此塵封。
  • 基於HMM的連續小詞量語音識別系統的研究
    、小詞量的語音識別系統。實驗證明,該語音識別系統具有較高的識別率和一定程度的魯棒性,實驗室識別率和室外識別率分別達到95.6%,92.3%。關鍵詞:語音識別;嵌入式系統;Hidden Markov Models;ARM;Viterbi算法0 引言 嵌入式語音識別系統是應用各種先進的微處理器在板級或是晶片級用軟體或硬體實現的語音識別。
  • 大熱的麥克風陣列語音識別系統的設計和輕鬆實現,提供軟硬體解決方案
    而本項目與傳統的麥克風陣進行語音識別的方法又有不同,它將語音接收端與語音識別部分組成一個反饋系統,通過優化接收端濾波器的係數,使跟語音識別密切相關的倒譜域似然比最大,來提高語音識別準確率。在進行Matlab仿真之後,將算法應用到FPGA中。FPGA開發板暫定為Xilinx公司的Nexys 3 Spartan-6 FPGA Board。
  • 語音識別是什麼 語音識別聲學特徵介紹【圖文】
    語音識別,什麼是語音識別  語音識別  與機器進行語音交流,讓機器明白你說什麼,這是人們長期以來夢寐以求的事情。語音識別技術就是讓機器通過識別和理解過程把語音信號轉變為相應的文本或命令的高技術。語音識別是一門交叉學科。近二十年來,語音識別技術取得顯著進步,開始從實驗室走向市場。
  • 語音識別算法有哪些_語音識別特徵提取方法
    第二種:基於參數模型的隱馬爾可夫模型(HMM)的方法   該算法主要用於大詞彙量的語音識別系統,它需要較多的模型訓練數據,較長的訓練和識別時間,而且還需要較大的內存空間。   一般連續隱馬爾可夫模型要比離散隱馬爾可夫模型計算量大,但識別率要高。
  • 基於DSP的語音識別計算器電路設計
    但是其基本的操作沒有發生變化,依然是運用手指操作,對於需要進行實時數字計算的一些特殊人群(殘疾人士)或是在一些特殊場合在無法手動操作計算器的情況下,用加入了語音識別模塊的計算器來進行實時數字計算就有相當的必要。 語音識別技術是人機最自然、最簡潔的交流方式,它就是讓機器能夠自動識別並理解說話人要表達的意思,將語音信號轉變為正確的文本或者命令的高科技技術。
  • 語音識別技術簡史
    ;2015 年以後,由於「端到端」技術興起,語音識別進入了百花齊放時代,語音界都在訓練更深、更複雜的網絡,同時利用端到端技術進一步大幅提升了語音識別的性能,直到 2017 年微軟在 Swichboard 上達到詞錯誤率 5.1%,從而讓語音識別的準確性首次超越了人類,當然這是在一定限定條件下的實驗結果,還不具有普遍代表性。
  • 基於FPGA的語音智能操控系統
    語音智能操控系統可以取代多個遙控器,當需要控制某一家電時,只需說出所需調節的內容(如,空調開,溫度25℃),語音智能操控系統就能通過對操控者的語音識別,完成匹配並發出遙控信息完成相應的操作。基於FPGA實現語音智能操控系統具有:(一)設計靈活、操作方便、快捷(二)準確度高,工作範圍大(三)可隨時用語音操控帶有遙控裝置的用電器(四)可擴展性強,增強了系統的外接功能(五)便於更新和系統升級,可隨時嵌入更新系統程序
  • 前沿| MIT研發語音關聯的圖像識別系統,一次破解所有語言
    選自MIT機器之心編譯參與:Jane W、李澤南將錄音語音與圖像相關聯的系統可以達到完全自動語音識別。MIT 研究人員研發了一種新的訓練語音識別系統的方法,它不依賴於轉錄抄本(transcription)。相反,這個系統的工作方式是分析圖像間的關聯和圖像的語言描述,而這些語言描述是在大量的音頻記錄中捕獲的。點擊閱讀原文查看論文。
  • 前沿 MIT研發語音關聯的圖像識別系統,一次破解所有語言
    MIT 研究人員研發了一種新的訓練語音識別系統的方法,它不依賴於轉錄抄本(transcription)。相反,這個系統的工作方式是分析圖像間的關聯和圖像的語言描述,而這些語言描述是在大量的音頻記錄中捕獲的。點擊閱讀原文查看論文。語音識別系統,如手機上將語音轉換為文本的軟體,通常是機器學習的產物。
  • 基於語音識別的移動電子病歷應用探索
    隨著網際網路的快速發展、移動終端的普及應用,藉助人工智慧、數據挖掘等信息技術,語音識別技術得到了突飛猛進的發展。特別是在醫療領域,語音識別技術在歐美國家醫院已得到了廣泛應用,主要用於醫療文書的錄入,節省醫生的錄入時間,將更多的時間留給醫生與患者溝通交流。而這幾年在中國醫院,語音識別的應用也得到了深入的探索與研究,但由於醫生使用習慣、錄入識別率等因素影響,並未廣泛地開展起來。
  • FinTech時代商業銀行智能語音識別技術應用與發展
    (3)聲學模型訓練  基於語音資料庫進行訓練,通過計算語音特徵和發音模板的相似度,為每個聲學單元建立模型參數,識別時將待識別的語音特徵參數與訓練得到的聲學模型進行匹配,獲得識別結果。傳統語音識別系統大多採用GMM-HMM進行聲學模型建模。