基於深度學習的中文語音識別系統框架(pluse)


本文搭建一個完整的中文語音識別系統,包括聲學模型和語言模型,能夠將輸入的音頻信號識別為漢字。

聲學模型使用了應用較為廣泛的遞歸循環網絡中的GRU-CTC的組合,除此之外還引入了科大訊飛提出的DFCNN深度全序列卷積神經網絡,也將引入阿里的架構DFSMN。

語言模型有傳統n-gram模型和基於深度神經網絡的CBHG網絡結構,該結構是谷歌用於TTS任務中的tacotron系統,本文中將該系統部分結構移植過來用於搭建拼音序列生成漢字序列系統。

數據集采用了目前能找到的所有中文免費數據,包括:thchs-30、aishell、primewords、st-cmd四個數據集,訓練集總計大約450個小時。

該項目地址在:https://github.com/audier/my_ch_speech_recognition寫的時候可能有些亂,后續會整理。

聲學模型

聲學模型目前開源了部分示例模型,更大模型將在確認識別結果后更新。

GRU-CTC

我們使用 GRU-CTC的方法搭建了第一個聲學模型,在gru_ctc_am.py中,利用循環神經網絡可以利用語音上下文相關的信息,得到更加准確地信息,而GUR又能選擇性的保留需要的信息。該模型使用python/keras進行搭建,本文系統都基於python搭建。
網絡結構如下:
該結構沒有真正使用,只是一個基本框架,類似於helloworld,用於作為示例。

def creatModel():
	input_data = Input(name='the_input', shape=(500, 26))
	layer_h1 = Dense(512, activation="relu", use_bias=True, kernel_initializer='he_normal')(input_data)
	layer_h1 = Dropout(0.2)(layer_h1)
	layer_h2 = Dense(512, activation="relu", use_bias=True, kernel_initializer='he_normal')(layer_h1)
	layer_h2 = Dropout(0.2)(layer_h2)
	layer_h3 = Dense(512, activation="relu", use_bias=True, kernel_initializer='he_normal')(layer_h2)
	layer_h4_1 = GRU(512, return_sequences=True, kernel_initializer='he_normal', dropout=0.3)(layer_h3)
	layer_h4_2 = GRU(512, return_sequences=True, go_backwards=True, kernel_initializer='he_normal', dropout=0.3)(layer_h3)
	layer_h4 = add([layer_h4_1, layer_h4_2])
	layer_h5 = Dense(512, activation="relu", use_bias=True, kernel_initializer='he_normal')(layer_h4)
	layer_h5 = Dropout(0.2)(layer_h5)
	layer_h6 = Dense(512, activation="relu", use_bias=True, kernel_initializer='he_normal')(layer_h5)
	layer_h6 = Dropout(0.2)(layer_h6)
	layer_h7 = Dense(512, activation="relu", use_bias=True, kernel_initializer='he_normal')(layer_h6)
	layer_h7 = Dropout(0.2)(layer_h7)
	layer_h8 = Dense(1177, activation="relu", use_bias=True, kernel_initializer='he_normal')(layer_h7)
	output = Activation('softmax', name='Activation0')(layer_h8)
	model_data = Model(inputs=input_data, outputs=output)
	#ctc層
	labels = Input(name='the_labels', shape=[50], dtype='float32')
	input_length = Input(name='input_length', shape=[1], dtype='int64')
	label_length = Input(name='label_length', shape=[1], dtype='int64')
	loss_out = Lambda(ctc_lambda, output_shape=(1,), name='ctc')([labels, output, input_length, label_length])
	model = Model(inputs=[input_data, labels, input_length, label_length], outputs=loss_out)
	model.summary()
	ada_d = Adadelta(lr=0.01, rho=0.95, epsilon=1e-06)
	model=multi_gpu_model(model,gpus=2)
	model.compile(loss={'ctc': lambda y_true, output: output}, optimizer=ada_d)
	#test_func = K.function([input_data], [output])
	print("model compiled successful!")
	return model, model_data

DFCNN

由於兩個原因在使用GRU作為語音識別的時候我們會遇到問題。一方面是我們常常使用雙向循環神經網絡才能取得更好的識別效果,這樣會影響解碼實時性。另一方面隨着網絡結構復雜性增加,雙向GRU的參數是相同節點數全連接層的6倍,這樣會導致訓練速度非常緩慢。
科大訊飛提出了一種使用深度卷積神經網絡來對時頻圖進行識別的方法,就是DFCNN,利用CNN參數共享機制,可以將參數數量下降一個級別,且深層次的卷積和池化層能夠充分考慮語音信號的上下文信息,且可以在較短的時間內就可以得到識別結果,具有較好的實時性。
該模型在cnn_witch_fbank.pycnn_ctc_am.py中,實驗中是所有網絡結果最好的模型,目前能夠取得較好的泛化能力,聲學模型識別率能夠達到90%以上,其網絡結構如下:
DFCNN

def creatModel():
	input_data = Input(name='the_input', shape=(800, 200, 1))
	# 800,200,32
	layer_h1 = Conv2D(32, (3,3), use_bias=True, activation='relu', padding='same', kernel_initializer='he_normal')(input_data)
	layer_h1 = BatchNormalization(mode=0,axis=-1)(layer_h1)
	layer_h2 = Conv2D(32, (3,3), use_bias=True, activation='relu', padding='same', kernel_initializer='he_normal')(layer_h1)
	layer_h2 = BatchNormalization(axis=-1)(layer_h2)
	layer_h3 = MaxPooling2D(pool_size=(2,2), strides=None, padding="valid")(layer_h2)
	# 400,100,64
	layer_h4 = Conv2D(64, (3,3), use_bias=True, activation='relu', padding='same', kernel_initializer='he_normal')(layer_h3)
	layer_h4 = BatchNormalization(axis=-1)(layer_h4)
	layer_h5 = Conv2D(64, (3,3), use_bias=True, activation='relu', padding='same', kernel_initializer='he_normal')(layer_h4)
	layer_h5 = BatchNormalization(axis=-1)(layer_h5)
	layer_h5 = MaxPooling2D(pool_size=(2,2), strides=None, padding="valid")(layer_h5)
	# 200,50,128
	layer_h6 = Conv2D(128, (3,3), use_bias=True, activation='relu', padding='same', kernel_initializer='he_normal')(layer_h5)
	layer_h6 = BatchNormalization(axis=-1)(layer_h6)
	layer_h7 = Conv2D(128, (3,3), use_bias=True, activation='relu', padding='same', kernel_initializer='he_normal')(layer_h6)
	layer_h7 = BatchNormalization(axis=-1)(layer_h7)
	layer_h7 = MaxPooling2D(pool_size=(2,2), strides=None, padding="valid")(layer_h7)
	# 100,25,128
	layer_h8 = Conv2D(128, (1,1), use_bias=True, activation='relu', padding='same', kernel_initializer='he_normal')(layer_h7)
	layer_h8 = BatchNormalization(axis=-1)(layer_h8)
	layer_h9 = Conv2D(128, (3,3), use_bias=True, activation='relu', padding='same', kernel_initializer='he_normal')(layer_h8)
	layer_h9 = BatchNormalization(axis=-1)(layer_h9)
	# 100,25,128
	layer_h10 = Conv2D(128, (1,1), use_bias=True, activation='relu', padding='same', kernel_initializer='he_normal')(layer_h9)
	layer_h10 = BatchNormalization(axis=-1)(layer_h10)
	layer_h11 = Conv2D(128, (3,3), use_bias=True, activation='relu', padding='same', kernel_initializer='he_normal')(layer_h10)
	layer_h11 = BatchNormalization(axis=-1)(layer_h11)
	# Reshape層
	layer_h12 = Reshape((100, 3200))(layer_h11) 
	# 全連接層
	layer_h13 = Dense(256, activation="relu", use_bias=True, kernel_initializer='he_normal')(layer_h12)
	layer_h13 = BatchNormalization(axis=1)(layer_h13)
	layer_h14 = Dense(1177, use_bias=True, kernel_initializer='he_normal')(layer_h13)
	output = Activation('softmax', name='Activation0')(layer_h14)
	model_data = Model(inputs=input_data, outputs=output)
	# ctc層
	labels = Input(name='the_labels', shape=[50], dtype='float32')
	input_length = Input(name='input_length', shape=[1], dtype='int64')
	label_length = Input(name='label_length', shape=[1], dtype='int64')
	loss_out = Lambda(ctc_lambda, output_shape=(1,), name='ctc')([labels, output, input_length, label_length])

	model = Model(inputs=[input_data, labels, input_length, label_length], outputs=loss_out)
	model.summary()
	ada_d = Adadelta(lr=0.01, rho=0.95, epsilon=1e-06)
	#model=multi_gpu_model(model,gpus=2)
	model.compile(loss={'ctc': lambda y_true, output: output}, optimizer=ada_d)
	#test_func = K.function([input_data], [output])
	print("model compiled successful!")
	return model, model_data

DFSMN

而前饋記憶神經網絡也也解決了雙向GRU的參數過多和實時性較差的缺點,它利用一個記憶模塊,包含了上下幾幀信息,能夠得到不輸於雙向GRU-CTC的識別結果,阿里最新的開源系統就是基於DFSMN的聲學模型,只不過在kaldi的框架上實現的。我們將考慮使用DFSMN+CTC的結構在python上實現。該網絡后續將實現。
結構如下:
DFSMN

語言模型

n-gram

n元語法是一個非常經典的語言模型,這里不過多介紹啦。

CBHG

該想法來自於一個大神搞輸入法的項目,下面部分也引用此處:搜喵出入法
他是利用該模型建立一個按鍵到漢字的作用,本文對其結構和數據處理部分稍作改動,作為語言模型。

拼音輸入的本質上就是一個序列到序列的模型:輸入拼音序列,輸出漢字序列。所以天然適合用在諸如機器翻譯的seq2seq模型上。

模型初始輸入是一個隨機采樣的拼音字母的character embedding,經過一個CBHG的模型,輸出是五千個漢字對應的label。
這里使用的CBHG模塊是state-of-art的seq2seq模型,用在Google的機器翻譯和語音合成中,該模型放在language_model/CBHG.py中,結構如下:
圖片來自 Tacotron: Towards End-to-End Speech Synthesis
CBHG

關於該模型值得注意的幾點:

1.模型先使用一系列的一維卷積網絡,有一系列的filter,filter_size從1到K,形成一個Conv1D Bank。這樣的作用相當於使用了一系列的unigrams, bigrams直到K-grams,盡可能多的拿到輸入序列從local到context的完整信息。其實這樣的模型,與之前我們提到過的IDCNN(Iterated Dilated Convolutionary Nerual Network)有異曲同工之妙。而IDCNN相比較起來有更少的參數,不知道如果把CBHG的Conv1D Bank換成IDCNN是怎樣的效果。

2.模型在最終的BiGRU之前加入了多層的Highway Layers,用來提取更高層次的特征。Highway Layers可以理解為加入了本來不相鄰層之間的“高速公路”,可以讓梯度更好地向前流動;同時又加入一個類似LSTM中門的機制,自動學習這些高速公路的開關和流量。Highway Networks和Residual Networks、Dense Networks都是想拉近深度網絡中本來相隔很遠的層與層之間的距離,使很深的網絡也可以比較容易地學習。

3.模型中還使用了Batch Normalization(繼ReLU之后大家公認的DL訓練技巧),Residual Connection(減少梯度的傳播距離),Stride=1的Max-pooling(保證Conv的局部不變性和時間維度的粒度)以及一個時髦的BiGRU。Tacotron: Towards End-to-End Speech Synthesis這篇文章發表在2017年4月,最潮的DL技術用到了很多。

項目基於深度學習的中文語音識別系統language_model/文件夾中已經默認放置了例子語料,可以通過直接運行CBHG.py進行數據預處理、模型訓練、和模型測試,下面是我用項目中的默認數據在12G GPU上訓練了大概小半天的模型識別結果,如果利用網絡爬蟲增加數據集,將會有更好的泛化結果。

請輸入測試拼音:ta1 mei2 you3 duo1 shao3 hao2 yan2 zhuang4 yu3 dan4 ta1 que4 ba3 ai4 qin1 ren2 ai4 jia1 ting2 ai4 zu3 guo2 ai4 jun1 dui4 wan2 mei3 de tong3 yi1 le qi3 lai2
她沒有多少豪言壯語但她卻把愛親人愛家庭愛祖國愛軍隊完美地統一了起來

請輸入測試拼音:chu2 cai2 zheng4 bo1 gei3 liang3 qian1 san1 bai3 wan4 yuan2 jiao4 yu4 zi1 jin1 wai4 hai2 bo1 chu1 zhuan1 kuan3 si4 qian1 wu3 bai3 qi1 shi2 wan4 yuan2 xin1 jian4 zhong1 xiao3 xue2
除財政撥給兩千三百萬元教太資金外還撥出專款四千五百七十萬元新建中小學

請輸入測試拼音:ke3 shi4 chang2 chang2 you3 ren2 gao4 su4 yao2 xian1 sheng1 shuo1 kan4 jian4 er4 xiao3 jie3 zai4 ka1 fei1 guan3 li3 he2 wang2 jun4 ye4 wo4 zhe shou3 yi1 zuo4 zuo4 shang4 ji3 ge4 zhong1 tou2
可是常常有人告訴姚先生說看見二小姐在咖啡館里和王俊業握着族一坐坐上幾個鍾頭

數據集

數據集采用了目前我能找到的所有中文免費數據,包括:thchs-30、aishell、primewords、st-cmd四個數據集,訓練集總計大約450個小時,在實驗過程中,使用thchs-30+aishell+st-cmd數據集對DFCNN聲學模型進行訓練,以64batch_size訓練。

  • 數據集
    • 共計約430小時,相關鏈接:http://www.openslr.org/resources.php

    • st-cmd、primewords、Aishell、thchs30四個數據集,整理為相同格式,放於some_expriment\data_process\datalist中。包含了解壓后數據的路徑,以及訓練所需的數據標注格式,其中prime數據沒有區分訓練集等,為我手工區分。各個數據集的數量(句)如下:

      Name train dev test
      aishell 120098 14326 7176
      primewords 40783 5046 5073
      thchs-30 10000 893 2495
      st-cmd 10000 600 2000

這是目前能找到的所有開源中文語料,如果還有希望大神能夠留言提示。

轉載請注明出處:https://www.cnblogs.com/sunhongwen/p/9613674.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM