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

2020-12-21 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競賽獲獎等等。

相關焦點

  • ASRT:一個中文語音識別系統
    在人類的交流和知識傳播中,大約 70% 的信息是來自於語音。未來,語音識別將必然成為智能生活裡重要的一部分,它可以為語音助手、語音輸入等提供必不可少的基礎,這將會成為一種新的人機互動方式。因此,我們需要讓機器聽懂人的聲音。我們的語音識別系統的聲學模型採用了深度全卷積神經網絡,直接將語譜圖作為輸入。
  • python3+dlib人臉識別及情緒分析
    系統缺點:不能捕捉細微表情的變化,只能大致的判斷出人的情緒,開心、憤怒、驚訝、自然。系統優點:結構簡單,易於上手。應用領域:微笑抓拍,捕捉瞬間的美好、緩解兒童自閉症、交互式遊戲開發。由於人感情的複雜性,這些表情確實不能完完全全的代表一個人內心深處的情緒波動,如要提高判斷的準確性,則需要心率檢測、語音處理等綜合評價。
  • 本土語音揀貨系統替換進口系統|佳麗寶上線百特麥語音系統案例分享
    語音識別準確率不高 原語音系統因為是針對歐美市場開發,在識別中文發音方面存在天然缺陷,具體表現為語音識別率較低,主要體現在2、8、5、7、這些數字上,需要說這些數字的時候,揀貨員很苦惱,因為有時候需要連續重複的說十幾遍系統才能識別正確,進行下一步操作,這大大的降低了他們的揀貨速率。
  • 畢業設計| 樹莓派3B+與opencv3+PyQt5實現人臉識別門禁系統
    今天我們分享來自愚人國度的King的作品,給大家一些參考思路,先來點效果展示,下面是兩個界面:主頁和人臉檢測界面,主頁可以密碼鎖、以及其他操作(自己按需),另一個界面是人臉檢測的界面:id=9d025059ad0326d9511ea4fc2bea321b&type=note注意:opencv-python庫、opencv-contrib-python庫這兩個庫的版本要一致。opencv-contrib-python庫是opencv-python庫的升級版,人臉識別的算法在裡面。
  • python能做什麼
    顧名思義,它就像是由文字組成的雲,相信你對很多網站框裡面有許多的文字,像微博,百度都有最新的內容,都是用文字雲做的。而我們用python來做文字雲是相當的容易的,只要你學會了python的基本語法,那麼做文字雲是得來不費工夫的。 我們可以通過文字雲讓閱讀者的體驗更加直接,能夠知道熱點是哪裡,提高用戶體驗度。
  • 10行代碼實現python人臉識別
    ↑ 關注 + 星標 ~ 有趣的不像個技術號什麼是人臉識別人臉識別,是基於人的臉部特徵信息進行身份識別的一種生物識別技術。用攝像機或攝像頭採集含有人臉的圖像或視頻流,並自動在圖像中檢測和跟蹤人臉,進而對檢測到的人臉進行臉部識別的一系列相關技術,通常也叫做人像識別、面部識別。目前的人臉識別技術已經非常成熟了,還發展成3D人臉識別。
  • 江疏影這波操作穩,網友:全是套路
    江疏影的這波操作穩,網友看到之後紛紛評論,全是套路快來和小編一起看看,到底存在著怎樣的套路吧。,江疏影一臉高冷麵無表情的站在那裡,我們可以看到一個類似於自己造型師的女孩子伸出了手,好像是在幫江疏影整理衣服,就是通過她整理衣服的這個小動作,我們可以注意到一個細節網友們看明白之後,紛紛在底下評論江疏影的這波操作穩啊,為了防止往下掉全是套路呀。
  • 廣東這波操作穩了!
    當監控系統顯示屏的數值一路攀升,並最終定格在這個數字時,袁來深長舒了一口氣。這標誌著18萬標準立方米/小時煤制氫裝置全流程終於打通,德國魯奇低溫甲醇洗技術在沒有外國專家到場的情況下,順利產出高純度氫氣!這正是他和項目團隊加班加點連續奮戰了幾個月的成果。工期沒有延誤,項目建設得以如期推進。日前召開的中央經濟工作會議強調,要增強投資增長後勁,繼續發揮關鍵作用。
  • 人臉識別簡介(使用Python代碼)
    小編沒有iPhone XS,所以就在這裡推薦一篇人臉識別入門佳作吧~人臉識別是計算機視覺的一個子領域,它的應用範圍非常廣泛,現在已經成為世界各地的企業爭相競逐的新技術之一。考慮到市場的盈利現狀,未來這項技術還會有更大的需求空間,所以作為機器學習的學習者,自己動手去從頭開始構建一個人臉識別工具很有價值。
  • 高端化妝品倉庫|繼佳麗寶之後資生堂上線百特麥語音系統案例分享|...
    ■ 省去了配單和分單工作 REP穿戴式語音軟體導入前,當營管釋放完波次後,要列印箱貼和裝箱明細(分開列印),當該波次列印工作完成後,需要專人去將箱貼和裝箱明細,根據訂單號去做匹配,要花費大量的時間。當配單工作結束後,現場組長又要根據運輸線路去分單,又要花費大量的時間。
  • python字典操作大全,學習python第7天
    python字典跟列表類型,能存儲多個數據,並且還能在訪問元素的時候可以很快定位到需要的元素。而python字典操作方法有多少種呢?下面羽憶教程為您介紹。,python字典都是由一個鍵和一個值組成的「鍵值對」,兩者之間用冒號隔開,結構如:sco = {'name':'小明','age': 11},需要注意的是python字典中的值不允許重複。
  • 百度語音首席架構師賈磊:讓語音技術可靠流暢,具備親情和溫暖
    之後的幾年,除了零星的嵌入式設備應用外,語音技術在工業界的拓展乏陳可新,語音產業持續低迷。語音技術的產業應用迎來第二波高潮痛苦的日子總算沒有太長。在2007年,微軟公司收購語音識別技術企業Tellme Networks,並開始組建自己的語音團隊,語音技術的產業應用又重新回到大公司的關注熱點中。
  • 特斯拉語音識別「太接地氣」,在中國臺灣說話要加「那個」
    IT之家1月6日消息去年底,特斯拉推出了車載系統的重大更新包,包含大量新功能,如智能召喚、相鄰車道速度識別、語音命令、部分軟體應用等功能。據網友反映,「語音命令」可以讓車主通過日常口語化語音實現對空調、導航、媒體等功能的控制,讓駕駛員更加專注於駕駛車輛,其識別率也大大增加。而據科技新報報導,特斯拉最新的自動導航功能在中國臺灣上線後,通過人工智慧訓練開始學習臺灣人的說話方式,近日有車主發現,用語音控制時,只要加上「那個」就能準確啟動導航功能。
  • 2019 必知的 10 大頂級 python 庫
    2.靈活TensorFlow 的一個非常重要的特性是,它的操作非常靈活。這意味著它具有模塊性,可以讓你把希望獨立出來的部分分出來3.容易訓練對於分布式計算來說,它很容易在 CPU 和 GPU 上訓練。4.並行神經網絡訓練TensorFlow 提供了管道流,從這個意義上說,你可以訓練多個神經網絡和多個 GPU,這使得模型在大型系統上非常有效。5.大型社區不用說,它是由 Google 開發的,已經有一個龐大的軟體工程師團隊在不斷地改進穩定性。
  • 如何將語音文件轉換為文字?這5款軟體輕鬆做到!
    在我們日常學習和日常工作中,有時會遇到將一段語音文件轉換為文字的情況。尤其是會議記錄,上面在侃侃而談,下面在奮筆疾書。小編就常常需要奮筆疾書記錄會議內容,然後在用手將會議記錄製作成電子版。後來聽說將語音文件其實是可以轉換為文字的,不用那麼麻煩,自己去錄入。下面,小編就開始正題,介紹5款將語音轉換為文字的軟體。
  • 智能語音交互系統 應該有喚醒詞嗎?
    如果沒有喚醒詞,智能語音交互系統會有怎樣的使用感受?最近,我有幸感受過一次。操作沒有喚醒詞的智能語音交互系統不像傳統車機那麼繁瑣,只要說出我們的需求,它就能進行處理最終給予我們相對應的反饋信息。沒有喚醒詞,就像和朋友聊天一樣的智能語音交互系統在現階段絕對是新穎的設計。
  • 17」語音識別PK賽 英語流利說完勝科大訊飛
    17」語音識別PK賽 英語流利說完勝科大訊飛 12 月 16 日,由著名科技媒體PingWest品玩主辦的「HAY!17·無限奇境」嘉年華在北京炸裂開場。
  • python機器學習之使用scikit-learn庫
    引言數據分析由一連串的步驟組成,對於其中預測模型的創建和驗證這一步,我們使用scikit-learn這個功能強大的庫來完成。scikit-learning庫python庫scikit-learn整合了多種機器學習算法。
  • 用Jetson Nano構建一個價值60美元的人臉識別系統
    例如,你無需執行諸如啟用交換文件之類的基本操作。Nvidia積極地推出了一款價格低於60美元的帶有真實GPU的簡單易用的硬體設備。似乎他們正以此為目標瞄準樹莓派,並試圖佔領教育/愛好者市場。看看市場如何反應將是很有趣的。
  • 文職美女上班手動用Excel表格太麻煩,當學會python後easy操作
    通過程序操作excel表格是編程中比較常見的操作,python本身不能直接操作excel,需要安裝第三方的模塊來實現excel的操作。>下面主要以xlrd和xlwd模塊為例,給大家分享下這兩個模塊的使用。