語音識別第一課:基於Tensorflow的端到端語音識別技術

2021-01-08 讀芯術

全文共6655字,預計學習時長13分鐘

本文闡述了如何利用Tensorflow編寫一個基本的端到端自動語音識別(Automatic Speech Recognition,ASR)系統,詳細介紹了最小神經網絡的各個組成部分以及可將音頻轉為可讀文本的前綴束搜索解碼器。

雖然當下關於如何搭建基礎機器學習系統的文獻或資料有很多,但是大部分都是圍繞計算機視覺和自然語言處理展開的,極少有文章就語音識別展開介紹。本文旨在填補這一空缺,幫助初學者降低入門難度,提高學習自信。

前提

初學者需要熟練掌握:

· 神經網絡的組成

· 如何訓練神經網絡

· 如何利用語言模型求得詞序的概率

概述

· 音頻預處理:將原始音頻轉換為可用作神經網絡輸入的數據

· 神經網絡:搭建一個簡單的神經網絡,用於將音頻特徵轉換為文本中可能出現的字符的概率分布

· CTC損失:計算不使用相應字符標註音頻時間步長的損失

· 解碼:利用前綴束搜索和語言模型,根據各個時間步長的概率分布生成文本

本文重點講解了神經網絡、CTC損失和解碼。

音頻預處理

搭建語音識別系統,首先需要將音頻轉換為特徵矩陣,並輸入到神經網絡中。完成這一步的簡單方法就是創建頻譜圖。

def create_spectrogram(signals):

stfts = tf.signal.stft(signals, fft_length=256)

spectrograms = tf.math.pow(tf.abs(stfts), 0.5)

return spectrograms

這一方法會計算出音頻信號的短時傅立葉變換(Short-time Fourier Transform)以及功率譜,其最終輸出可直接用作神經網絡輸入的頻譜圖矩陣。其他方法包括濾波器組和MFCC(Mel頻率倒譜係數)等。

了解更多音頻預處理知識:https://haythamfayek.com/2016/04/21/speech-processing-for-machine-learning.html

神經網絡

下圖展現了一個簡單的神經網絡結構。

語音識別基本結構

頻譜圖輸入可以看作是每個時間步長的向量。1D卷積層從各個向量中提取出特徵,形成特徵向量序列,並輸入LSTM層進一步處理。LSTM層(或雙LSTM層)的輸入則傳遞至全連接層。利用softmax激活函數,可得出每個時間步長的字符概率分布。整個網絡將會用CTC損失函數進行訓練(CTC即Connectionist Temporal Classification,是一種時序分類算法)。熟悉整個建模流程後可嘗試使用更複雜的模型。

class ASR(tf.keras.Model):

def __init__(self, filters, kernel_size, conv_stride, conv_border, n_lstm_units, n_dense_units):

super(ASR, self).__init__()

self.conv_layer = tf.keras.layers.Conv1D(filters,

kernel_size,

strides=conv_stride,

padding=conv_border,

activation='relu')

self.lstm_layer = tf.keras.layers.LSTM(n_lstm_units,

return_sequences=True,

activation='tanh')

self.lstm_layer_back = tf.keras.layers.LSTM(n_lstm_units,

return_sequences=True,

go_backwards=True,

activation='tanh')

self.blstm_layer = tf.keras.layers.Bidirectional(self.lstm_layer, backward_layer=self.lstm_layer_back)

self.dense_layer = tf.keras.layers.Dense(n_dense_units)

def call(self, x):

x = self.conv_layer(x)

x = self.blstm_layer(x)

x = self.dense_layer(x)

return x

為什麼使用CTC呢?搭建神經網絡旨在預測每個時間步長的字符。然而現有的標籤並不是各個時間步長的字符,僅僅是音頻的轉換文本。而文本的各個字符可能橫跨多個步長。如果對音頻的各個時間步長進行標記,C-A-T就會變成C-C-C-A-A-T-T。而每隔一段時間,如10毫秒,對音頻數據集進行標註,並不是一個切實可行的方法。CTC則解決上了上述問題。CTC並不需要標記每個時間步長。它忽略了文本中每個字符的位置和實際相位差,把神經網絡的整個概率矩陣輸入和相應的文本作為輸入。

CTC 損失計算

輸出矩陣示例

假設真實的數據標籤為CAT,在四個時間步長中,有序列C-C-A-T,C-A-A-T,C-A-T-T,_-C-A-T,C-A-T-_與真實數據相對應。將這些序列的概率相加,可得到真實數據的概率。根據輸出的概率矩陣,將序列的各個字符的概率相乘,可得到單個序列的概率。則上述序列的總概率為0.0288+0.0144+0.0036+0.0576+0.0012=0.1056。CTC損失則為該概率的負對數。Tensorflow自帶損失函數文件。

解碼

由上文的神經網絡,可輸出一個CTC矩陣。這一矩陣給出了各個時間步長中每個字符在其字符集中的概率。利用前綴束搜索,可從CTC矩陣中得出所需的文本。

除了字母和空格符,CTC矩陣的字符集還包括兩種特別的標記(token,也稱為令牌)——空白標記和字符串結束標記。

空白標記的作用:CTC矩陣中的時間步長通常比較小,如10毫秒。因此,句子中的一個字符會橫跨多個時間步長。如,C-A-T會變成C-C-C-A-A-T-T。所以,需要將CTC矩陣中出現該問題的字符串中的重複部分摺疊,消除重複。那麼像FUNNY這種本來就有兩個重複字符(N)的詞要怎麼辦呢?在這種情況下,就可以使用空白標記,將其插入兩個N中間,就可以防止N被摺疊。而這麼做實際上並沒有在文本中添加任何東西,也就不會影響其內容或形式。因此,F-F-U-N-[空白]-N-N-Y最終會變成FUNNY。

結束標記的作用:字符串的結束表示著一句話的結束。對字符串結束標記後的時間步長進行解碼不會給候選字符串增加任何內容。

步驟

初始化

· 準備一個初始列表。列表包括多個候選字符串,一個空白字符串,以及各個字符串在不同時間步長以空白標記結束的概率,和以非空白標記結束的概率。在時刻0,空白字符串以空白標記結束的概率為1,以非空白標記結束的概率則為0。

迭代

· 選擇一個候選字符串,將字符一個一個添加進去。計算拓展後的字符串在時刻1以空白標記和非空白標記結束的概率。將拓展字符串及其概率記錄到列表中。將拓展字符串作為新的候選字符串,在下一時刻重複上述步驟。

· 情況A:如果添加的字符是空白標記,則保持候選字符串不變。

· 情況B:如果添加的字符是空格符,則根據語言模型將概率與和候選字符串的概率成比例的數字相乘。這一步可以防止錯誤拼寫變成最佳候選字符串。如,避免COOL被拼成KUL輸出。

· 情況C:如果添加的字符和候選字符串的最後一個字符相同,(以候選字符串FUN和字符N為例),則生成兩個新的候選字符串,FUNN和FUN。生成FUN的概率取決於FUN以空白標記結束的概率。生成FUNN的概率則取決於FUN以非空白標記結束的概率。因此,如果FUN以非空白標記結束,則去除額外的字符N。

輸出

經過所有時間步長迭代得出的最佳候選字符串就是輸出。

為了加快這一過程,可作出如下兩個修改。

1.在每一個時間步長,去除其他字符串,僅留下最佳的K個候選字符串。具體操作為:根據字符串以空白和非空白標記結束的概率之和,對候選字符串進行分類。

2.去除矩陣中概率之和低於某個閾值(如0.001)的字符。

具體操作細節可參考如下代碼。

def prefix_beam_search(ctc,

alphabet,

blank_token,

end_token,

space_token,

lm,

k=25,

alpha=0.30,

beta=5,

prune=0.001):

'''

function to perform prefix beam search on output ctc matrix and return the best string

:param ctc: output matrix

:param alphabet: list of strings in the order their probabilties are present in ctc output

:param blank_token: string representing blank token

:param end_token: string representing end token

:param space_token: string representing space token

:param lm: function to calculate language model probability of given string

:param k: threshold for selecting the k best prefixes at each timestep

:param alpha: language model weight (b/w 0 and 1)

:param beta: language model compensation (should be proportional to alpha)

:param prune: threshold on the output matrix probability of a character.

If the probability of a character is less than this threshold, we do not extend the prefix with it

:return: best string

'''

zero_pad = np.zeros((ctc.shape[0]+1,ctc.shape[1]))

zero_pad[1:,:] = ctc

ctc = zero_pad

total_timesteps = ctc.shape[0]

# #### Initialization ####

null_token = ''

Pb, Pnb = Cache(), Cache()

Pb.add(0,null_token,1)

Pnb.add(0,null_token,0)

prefix_list = [null_token]

# #### Iterations ####

for timestep in range(1, total_timesteps):

pruned_alphabet = [alphabet[i] for i in np.where(ctc[timestep] > prune)[0]]

for prefix in prefix_list:

if len(prefix) > 0 and prefix[-1] == end_token:

Pb.add(timestep,prefix,Pb.get(timestep - 1,prefix))

Pnb.add(timestep,prefix,Pnb.get(timestep - 1,prefix))

continue

for character in pruned_alphabet:

character_index = alphabet.index(character)

# #### Iterations : Case A ####

if character == blank_token:

value = Pb.get(timestep,prefix) + ctc[timestep][character_index] * (Pb.get(timestep - 1,prefix) + Pnb.get(timestep - 1,prefix))

Pb.add(timestep,prefix,value)

else:

prefix_extended = prefix + character

# #### Iterations : Case C ####

if len(prefix) > 0 and character == prefix[-1]:

value = Pnb.get(timestep,prefix_extended) + ctc[timestep][character_index] * Pb.get(timestep-1,prefix)

Pnb.add(timestep,prefix_extended,value)

value = Pnb.get(timestep,prefix) + ctc[timestep][character_index] * Pnb.get(timestep-1,prefix)

Pnb.add(timestep,prefix,value)

# #### Iterations : Case B ####

elif len(prefix.replace(space_token, '')) > 0 and character in (space_token, end_token):

lm_prob = lm(prefix_extended.strip(space_token + end_token)) ** alpha

value = Pnb.get(timestep,prefix_extended) + lm_prob * ctc[timestep][character_index] * (Pb.get(timestep-1,prefix) + Pnb.get(timestep-1,prefix))

Pnb.add(timestep,prefix_extended,value)

else:

value = Pnb.get(timestep,prefix_extended) + ctc[timestep][character_index] * (Pb.get(timestep-1,prefix) + Pnb.get(timestep-1,prefix))

Pnb.add(timestep,prefix_extended,value)

if prefix_extended not in prefix_list:

value = Pb.get(timestep,prefix_extended) + ctc[timestep][-1] * (Pb.get(timestep-1,prefix_extended) + Pnb.get(timestep-1,prefix_extended))

Pb.add(timestep,prefix_extended,value)

value = Pnb.get(timestep,prefix_extended) + ctc[timestep][character_index] * Pnb.get(timestep-1,prefix_extended)

Pnb.add(timestep,prefix_extended,value)

prefix_list = get_k_most_probable_prefixes(Pb,Pnb,timestep,k,beta)

# #### Output ####

return prefix_list[0].strip(end_token)

這樣,一個基礎的語音識別系統就完成了。對上述步驟進行複雜化,可以得到更優的結果,如,搭建更大的神經網絡和利用音頻預處理技巧。

完整代碼:https://github.com/apoorvnandan/speech-recognition-primer

注意事項:

1. 文中代碼使用的是TensorFlow2.0系統,舉例使用的音頻文件選自LibriSpeech資料庫(http://www.openslr.org/12)。

2. 文中代碼並不包括訓練音頻數據集的批量處理生成器。讀者需要自己編寫。

3. 讀者亦需自己編寫解碼部分的語言模型函數。最簡單的方法就是基於語料庫生成一部二元語法字典並計算字符概率。

留言 點讚 關注

我們一起分享AI學習與發展的乾貨

如需轉載,請後臺留言,遵守轉載規範

相關焦點

  • 語音識別新範式:完全的「端到端」模型,優勢在哪裡?
    語音識別新範式以自然語言處理的子領域「語音識別」為例,從 2012 年引入深度學習技術開始,語音識別的研究熱點經歷了三個階段:2011年前後,基於 DNN+HMM(深度神經網絡+隱馬爾科夫模型)的語音識別 2014年前後,基於 LSTM+CTC(長短時記憶網絡+連接時序分類)的不完全端到端語音識別
  • 百度ICML論文:端對端中英文語音識別
    一個簡單但有效的替代解決方案是訓練出端對端語音自動識別模式,使用深度學習的方法用一個模型來代替大多數模式。如同Hannun et al., 2014a and Graves & Jaitly, 2014b在他們的論文所提及一樣。這種端到端的訓練方法簡化了訓練過程,因為它省去了人工引導/校準/集群/ HMM 機械裝置,而這些用於建立先進的自動語音識別(ASR)模式。
  • 語音識別技術簡史
    ;2015 年以後,由於「端到端」技術興起,語音識別進入了百花齊放時代,語音界都在訓練更深、更複雜的網絡,同時利用端到端技術進一步大幅提升了語音識別的性能,直到 2017 年微軟在 Swichboard 上達到詞錯誤率 5.1%,從而讓語音識別的準確性首次超越了人類,當然這是在一定限定條件下的實驗結果,還不具有普遍代表性。
  • 基於語音識別的移動電子病歷應用探索
    隨著網際網路的快速發展、移動終端的普及應用,藉助人工智慧、數據挖掘等信息技術,語音識別技術得到了突飛猛進的發展。特別是在醫療領域,語音識別技術在歐美國家醫院已得到了廣泛應用,主要用於醫療文書的錄入,節省醫生的錄入時間,將更多的時間留給醫生與患者溝通交流。而這幾年在中國醫院,語音識別的應用也得到了深入的探索與研究,但由於醫生使用習慣、錄入識別率等因素影響,並未廣泛地開展起來。
  • 排名 語音識別_語音識別技術排名 - CSDN
    該成果有望推動語音識別技術的大幅進步,已超越人類專業速記員的水平」的字眼令正在從事語音識別研究的科研工作者和技術提供商一陣錯愕,不明真相的群眾紛紛認為當前語音識別已經刷無可刷,語音識別技術已經沒有門檻,語音識別是已經解決的問題了……但是事實並不是這樣,在LibriSpeech這種簡單數據集上「刷」到詞錯誤率2.97%並不困難,語音識別領域仍存在大量的問題需要解決。
  • 使用Python和Keras創建簡單語音識別引擎
    在本文中,我將演示:語音轉文字的工作原理如何處理要轉錄的音頻使用Keras解決問題的深度學習模型一種評估此模型的方法將預測模型集成到項目中的腳本簡介語音只是由我們的聲帶引起的空氣周圍振動而產生的一系列聲波。這些聲波由麥克風記錄,然後轉換為電信號。然後使用高級信號處理技術處理信號,分離音節和單詞。
  • 從不溫不火到炙手可熱:語音識別技術簡史
    ;2015 年以後,由於「端到端」技術興起,語音識別進入了百花齊放時代,語音界都在訓練更深、更複雜的網絡,同時利用端到端技術進一步大幅提升了語音識別的性能,直到 2017 年微軟在 Swichboard 上達到詞錯誤率 5.1%,從而讓語音識別的準確性首次超越了人類,當然這是在一定限定條件下的實驗結果,還不具有普遍代表性。
  • 基於Arduino的文本語音轉換器和語音控制燈
    語音識別技術在自動化中非常有用,它不僅可以讓您免提控制設備,還可以提高系統的安全性。除了製造語音控制小工具外,語音識別還為患有各種殘疾的人們提供了重要幫助。 在之前的帖子中,我們製作了基於Arduino的文本到語音(TTS)轉換器和語音控制燈。
  • AI浪潮下,語音識別建模技術的演進 | 雷鋒網公開課
    本期硬創公開課邀請到了搜狗語音交互中心語音技術部負責人陳偉來為大家分享伴隨著本輪人工智慧浪潮下語音識別建模技術的演進,希望能夠幫大家理清主流的識別建模脈絡以及背後的思考。圖13  CTC尖峰效果演示 可以預期,基於CTC或者引用CTC概念(如LFMMI)的端到端識別技術將逐漸成為主流,HMM
  • FinTech時代商業銀行智能語音識別技術應用與發展
    (3)現代語音識別系統開發應用階段  近些年,隨著大數據和深度學習技術的發展,深度學習方法逐漸被引入到語音識別系統中,相較於傳統的語音識別技術,識別性能獲得了顯著提升。  目前,市場上的語音識別系統大多基於深度神經網絡模型進行建模,大幅提升了各種應用場景下語音識別的準確度和可靠性,使語音識別技術進入了新的應用階段。
  • 智能語音識別技術入門系列(上)
    本系列文章開始,我們將一起探索自動識別、語言處理技術所包含的核心算法、模型及未來的發展趨勢。本篇文章我們主要討論語音識別的基本概念。並理解語音識別技術的流程。(一) 自動語音識別技術ASR自動語音識別,簡稱ASR。
  • 應用、算法、晶片,「三位一體」淺析語音識別
    IBM、微軟、百度等公司在語音識別方面,使用組合模型,不斷提升語音識別性能。微軟基於6個不同的深度神經網絡構成的聲學模型以及4個不同的深度神經網絡構成的語言模型,取得了超越人類的識別準確率。科大訊飛則基於深度全序列卷積神經網絡語音識別框架,取得了實用級的識別性能。雲知聲、捷通華聲、思必馳等智能語音創業公司亦在不斷打磨自己的識別引擎,並能夠把自己的技術落地到產業中。
  • 語音識別技術原理全面解析
    語音識別技術正逐步成為計算機信息處理技術中的關鍵技術,語音技術的應用已經成為一個具有競爭性的新興高技術產業。  1、語音識別的基本原理  語音識別系統本質上是一種模式識別系統,包括特徵提取、模式匹配、參考模式庫等三個基本單元,它的基本結構如下圖所示:    未知語音經過話筒變換成電信號後加在識別系統的輸入端,首先經過預處理,再根據人的語音特點建立語音模型,對輸入的語音信號進行分析,並抽取所需的特 徵,在此基礎上建立語音識別所需的模板。
  • 語音識別的痛點在哪,從交互到精準識別如何做? | 雷鋒網公開課
    語音識別是目前應用最成熟的人機互動方式,從最初大家體驗過的有屏手持設備這種近場的語音識別,如Siri以及各種語音助手,到現在,語音識別的應用已經完成了向智能硬體以及機器人上延伸,不過,新的人機互動對硬體、算法要求更加苛刻,各企業正面臨著巨大的挑戰。
  • 團隊新作 | CIF:基於神經元整合發放的語音識別新機制
    基於CIF的模型不僅有效地支持了在線識別、邊界定位及聲學Embedding提取,而且在兩個中文基準語音識別集(HKUST、AISHELL-2)上創造了SOTA的性能。相關成果被ICASSP 2020錄用為Oral論文。基於注意力機制的端到端模型正深刻影響著語音識別技術的發展。
  • 專注E2E語音識別,騰訊AILab開源語音處理工具包PIKA
    機器之心報導作者:魔王、杜偉PyTorch + Kaldi,騰訊 AI Lab 開源輕量級語音處理工具包 PIKA,專注於端到端語音識別任務。Kaldi 是一個開源的語音識別系統,由 Daniel Povey 主導開發,在很多語音識別測試和應用中廣泛使用。
  • ZLG深度解析:語音識別技術
    語音識別已成為人與機器通過自然語言交互重要方式之一,本文將從語音識別的原理以及語音識別算法的角度出發為大家介紹語音識別的方案及詳細設計過程。語言作為人類的一種基本交流方式,在數千年歷史中得到持續傳承。近年來,語音識別技術的不斷成熟,已廣泛應用於我們的生活當中。語音識別技術是如何讓機器「聽懂」人類語言?
  • 基於Julius的機器人語音識別系統構建
    語音識別技術的發展,使得這一理想得以實現,把語音識別技術與機器人控制技術相結合,正成為目前研究的熱點,不但具有較好的理論意義,而且有較大的實用價值。   語音識別技術應用於機器人系統大多是針對特定的環境,設計出語音命令來進行控制的。
  • 基於Tacotron2實現中文語音合成,免去調試環節,輕鬆上手
    語音合成技術被廣泛應用於人機互動場景,如手機語音助手、地圖導航、智能音箱、文章聽讀等,返回的結果會以語音方式播報。語音合成翻譯成英文是Text-To- Speech,簡稱為TTS。語音合成相比語音識別的應用場景少一些,因工作中有接觸過語音合成並實現,也許有些朋友也需要用到它,特記錄在此,本文側重實現過程,對技術感興趣的朋友建議參考其他文獻,但對於技術新手和初次接觸並期待快速實現的朋友,不妨看看。
  • 基於DSP的語音識別系統的實現及分析
    0 引言  語音識別技術的目的是使機器能理解人類語言,最終使人機通信成為現實。在過去幾十年,自動語音識別(AutomaticSpeech Recognition,ASR)技術已經取得了非常重大的進步。  ASR系統已經能從處理像數字之類的小詞彙量到廣播新聞之類的大詞彙量。然而針對識別效果來說,ASR 系統則相對較差。