Python語音識別終極指南

譯者 | 廉潔
編輯 | 明明
出品 | AI科技大本營(公衆號ID:rgznai100)


【AI科技大本營導讀】亞馬遜的 Alexa 的巨大成功已經證實:在不遠的未來,實現必定程度上的語音支持將成爲平常科技的基本要求。整合了語音識別的 Python 程序提供了其餘技術沒法比擬的交互性和可訪問性。最重要的是,在 Python 程序中實現語音識別很是簡單。閱讀本指南,你就將會了解。你將學到:python

  • 語音識別的工做原理;
  • PyPI 支持哪些軟件包;
  • 如何安裝和使用 SpeechRecognition 軟件包——一個功能全面且易於使用的 Python 語音識別庫。

▌語言識別工做原理概述

語音識別源於 20 世紀 50 年代早期在貝爾實驗室所作的研究。早期語音識別系統僅能識別單個講話者以及只有約十幾個單詞的詞彙量。現代語音識別系統已經取得了很大進步,能夠識別多個講話者,而且擁有識別多種語言的龐大詞彙表。git

語音識別的首要部分固然是語音。經過麥克風,語音便從物理聲音被轉換爲電信號,而後經過模數轉換器轉換爲數據。一旦被數字化,就可適用若干種模型,將音頻轉錄爲文本。github

大多數現代語音識別系統都依賴於隱馬爾可夫模型(HMM)。其工做原理爲:語音信號在很是短的時間尺度上(好比 10 毫秒)可被近似爲靜止過程,即一個其統計特性不隨時間變化的過程。api

許多現代語音識別系統會在 HMM 識別以前使用神經網絡,經過特徵變換和降維的技術來簡化語音信號。也可使用語音活動檢測器(VAD)將音頻信號減小到可能僅包含語音的部分。bash

幸運的是,對於 Python 使用者而言,一些語音識別服務可經過 API 在線使用,且其中大部分也提供了 Python SDK。網絡

▌選擇 Python 語音識別包

PyPI中有一些現成的語音識別軟件包。其中包括:函數

  • apiai
  • google-cloud-speech
  • pocketsphinx
  • SpeechRcognition
  • watson-developer-cloud
  • wit

一些軟件包(如 wit 和 apiai )提供了一些超出基本語音識別的內置功能,如識別講話者意圖的天然語言處理功能。其餘軟件包,如谷歌雲語音,則專一於語音向文本的轉換。測試

其中,SpeechRecognition 就因便於使用脫穎而出。ui

識別語音須要輸入音頻,而在 SpeechRecognition 中檢索音頻輸入是很是簡單的,它無需構建訪問麥克風和從頭開始處理音頻文件的腳本,只需幾分鐘便可自動完成檢索並運行。google

SpeechRecognition 庫可知足幾種主流語音 API ,所以靈活性極高。其中 Google Web Speech API 支持硬編碼到 SpeechRecognition 庫中的默認 API 密鑰,無需註冊就可以使用。SpeechRecognition 以其靈活性和易用性成爲編寫 Python 程序的最佳選擇。

▌安裝 SpeechRecognation

SpeechRecognition 兼容 Python2.6 , 2.7 和 3.3+,但若在 Python 2 中使用還須要一些額外的安裝步驟。本教程中全部開發版本默認 Python 3.3+。

讀者可以使用 pip 命令從終端安裝 SpeechRecognition:

$ pip install SpeechRecognition複製代碼

安裝完成後請打開解釋器窗口並輸入如下內容來驗證安裝:

>>> import speech_recognition as sr
>>> sr.__version__
'3.8.1'
複製代碼

注:不要關閉此會話,在後幾個步驟中你將要使用它。

若處理現有的音頻文件,只需直接調用 SpeechRecognition ,注意具體的用例的一些依賴關係。同時注意,安裝 PyAudio 包來獲取麥克風輸入。

▌識別器類

SpeechRecognition 的核心就是識別器類。

Recognizer API 主要目是識別語音,每一個 API 都有多種設置和功能來識別音頻源的語音,分別是:

  • recognize_bing(): Microsoft Bing Speech

  • recognize_google(): Google Web Speech API

  • recognize_google_cloud(): Google Cloud Speech - requires installation of the google-cloud-speech package

  • recognize_houndify(): Houndify by SoundHound

  • recognize_ibm(): IBM Speech to Text

  • recognize_sphinx(): CMU Sphinx - requires installing PocketSphinx

  • recognize_wit(): Wit.ai

以上七個中只有 recognition_sphinx()可與CMU Sphinx 引擎脫機工做, 其餘六個都須要鏈接互聯網。

SpeechRecognition 附帶 Google Web Speech API 的默認 API 密鑰,可直接使用它。其餘六個 API 都須要使用 API 密鑰或用戶名/密碼組合進行身份驗證,所以本文使用了 Web Speech API。

如今開始着手實踐,在解釋器會話中調用 recognise_google()函數。

>>> r.recognize_google()複製代碼

屏幕會出現:

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: recognize_google() missing 1 required positional argument: 'audio_data'複製代碼

相信你已經猜到告終果,怎麼可能從空文件中識別出數據呢?

這 7 個 recognize_*() 識別器類都須要輸入 audio_data 參數,且每種識別器的 audio_data 都必須是 SpeechRecognition 的 AudioData 類的實例。

AudioData 實例的建立有兩種路徑:音頻文件或由麥克風錄製的音頻,先從比較容易上手的音頻文件開始。

▌音頻文件的使用

首先須要下載音頻文件(https://github.com/realpython/python-speech-recognition/tree/master/audio_files),保存到 Python 解釋器會話所在的目錄中。

AudioFile 類能夠經過音頻文件的路徑進行初始化,並提供用於讀取和處理文件內容的上下文管理器界面。

支持文件類型

SpeechRecognition 目前支持的文件類型有:

  • WAV: 必須是 PCM/LPCM 格式

  • AIFF

  • AIFF-C

  • FLAC: 必須是初始 FLAC 格式;OGG-FLAC 格式不可用

如果使用 Linux 系統下的 x-86 ,macOS 或者是 Windows 系統,須要支持 FLAC文件。若在其它系統下運行,須要安裝 FLAC 編碼器並確保能夠訪問 flac 命令。

使用 record() 從文件中獲取數據

在解釋器會話框鍵入如下命令來處理 「harvard.wav」 文件的內容:

>>> harvard = sr.AudioFile('harvard.wav')
>>> with harvard as source:
...   audio = r.record(source)
...複製代碼

經過上下文管理器打開文件並讀取文件內容,並將數據存儲在 AudioFile 實例中,而後經過 record()將整個文件中的數據記錄到 AudioData 實例中,可經過檢查音頻類型來確認:

>>> type(audio)
<class 'speech_recognition.AudioData'>複製代碼

如今能夠調用 recognition_google()來嘗試識別音頻中的語音。

>>> r.recognize_google(audio)
'the stale smell of old beer lingers it takes heat to bring out the odor a cold dip restores health and zest a salt pickle taste fine with ham tacos al Pastore are my favorite a zestful food is the hot cross bun'
複製代碼

以上就完成了第一個音頻文件的錄製。

利用偏移量和持續時間獲取音頻片斷

若只想捕捉文件中部分演講內容該怎麼辦?record() 命令中有一個 duration 關鍵字參數,可以使得該命令在指定的秒數後中止記錄。

例如,如下內容僅獲取文件前四秒內的語音:

>>> with harvard as source:
...   audio = r.record(source, duration=4)
...
>>> r.recognize_google(audio)
'the stale smell of old beer lingers'
複製代碼

在with塊中調用record() 命令時,文件流會向前移動。這意味着若先錄製四秒鐘,再錄製四秒鐘,則第一個四秒後將返回第二個四秒鐘的音頻。

>>> with harvard as source:
...   audio1 = r.record(source, duration=4)
...   audio2 = r.record(source, duration=4)
...
>>> r.recognize_google(audio1)
'the stale smell of old beer lingers'
>>> r.recognize_google(audio2)
'it takes heat to bring out the odor a cold dip'
複製代碼

除了指定記錄持續時間以外,還可使用 offset 參數爲 record() 命令指定起點,其值表示在開始記錄的時間。如:僅獲取文件中的第二個短語,可設置 4 秒的偏移量並記錄 3 秒的持續時間。

>>> with harvard as source:
...   audio = r.record(source, offset=4, duration=3)
...
>>> recognizer.recognize_google(audio)
'it takes heat to bring out the odor'
複製代碼

在事先知道文件中語音結構的狀況下,offset 和 duration 關鍵字參數對於分割音頻文件很是有用。但使用不許確會致使轉錄不佳。

>>> with harvard as source:
...   audio = r.record(source, offset=4.7, duration=2.8)
...
>>> recognizer.recognize_google(audio)
'Mesquite to bring out the odor Aiko'
複製代碼

本程序從第 4.7 秒開始記錄,從而使得詞組 「it takes heat to bring out the odor」 ,中的 「it t」 沒有被記錄下來,此時 API 只獲得 「akes heat」 這個輸入,而與之匹配的是 「Mesquite」 這個結果。

一樣的,在獲取錄音結尾詞組 「a cold dip restores health and zest」 時 API 僅僅捕獲了 「a co」 ,從而被錯誤匹配爲 「Aiko」 。

噪音也是影響翻譯準確度的一大元兇。上面的例子中因爲音頻文件乾淨從而運行良好,但在現實中,除非事先對音頻文件進行處理,不然不可能獲得無噪聲音頻。

噪聲對語音識別的影響

噪聲在現實世界中確實存在,全部錄音都有必定程度的噪聲,而未經處理的噪音可能會破壞語音識別應用程序的準確性。

要了解噪聲如何影響語音識別,請下載 「jackhammer.wav」 (https://github.com/realpython/python-speech-recognition/tree/master/audio_files)文件,並確保將其保存到解釋器會話的工做目錄中。文件中短語 「the stale smell of old beer lingers」 在是很大鑽牆聲的背景音中被念出來。

嘗試轉錄此文件時會發生什麼?

>>> jackhammer = sr.AudioFile('jackhammer.wav')
>>> with jackhammer as source:
...   audio = r.record(source)
...
>>> r.recognize_google(audio)
'the snail smell of old gear vendors'
複製代碼

那麼該如何處理這個問題呢?能夠嘗試調用 Recognizer 類的adjust_for_ambient_noise()命令。

>>> with jackhammer as source:
...   r.adjust_for_ambient_noise(source)
...   audio = r.record(source)
...
>>> r.recognize_google(audio)
'still smell of old beer vendors'
複製代碼

這樣就與準確結果接近多了,但精確度依然存在問題,並且詞組開頭的 「the」 被丟失了,這是什麼緣由呢?

由於使用 adjust_for_ambient_noise()命令時,默認將文件流的第一秒識別爲音頻的噪聲級別,所以在使用 record()獲取數據前,文件的第一秒已經被消耗了。

可以使用duration關鍵字參數來調整adjust_for_ambient_noise()命令的時間分析範圍,該參數單位爲秒,默認爲 1,現將此值下降到 0.5。

>>> with jackhammer as source:
...   r.adjust_for_ambient_noise(source, duration=0.5)
...   audio = r.record(source)
...
>>> r.recognize_google(audio)
'the snail smell like old Beer Mongers'
複製代碼

如今咱們就獲得了這句話的 「the」,但如今出現了一些新的問題——有時由於信號太吵,沒法消除噪音的影響。

若常常遇到這些問題,則須要對音頻進行一些預處理。能夠經過音頻編輯軟件,或將濾鏡應用於文件的 Python 包(例如SciPy)中來進行該預處理。處理嘈雜的文件時,能夠經過查看實際的 API 響應來提升準確性。大多數 API 返回一個包含多個可能轉錄的 JSON 字符串,但若不強制要求給出完整響應時,recognition_google()方法始終僅返回最可能的轉錄字符。

經過把 recognition_google()中 True 參數改爲 show_all 來給出完整響應。

>>> r.recognize_google(audio, show_all=True)
{'alternative': [
 {'transcript': 'the snail smell like old Beer Mongers'}, 
 {'transcript': 'the still smell of old beer vendors'}, 
 {'transcript': 'the snail smell like old beer vendors'},
 {'transcript': 'the stale smell of old beer vendors'}, 
 {'transcript': 'the snail smell like old beermongers'}, 
 {'transcript': 'destihl smell of old beer vendors'}, 
 {'transcript': 'the still smell like old beer vendors'}, 
 {'transcript': 'bastille smell of old beer vendors'}, 
 {'transcript': 'the still smell like old beermongers'}, 
 {'transcript': 'the still smell of old beer venders'}, 
 {'transcript': 'the still smelling old beer vendors'}, 
 {'transcript': 'musty smell of old beer vendors'}, 
 {'transcript': 'the still smell of old beer vendor'}
], 'final': True}
複製代碼

能夠看到,recognition_google()返回了一個關鍵字爲 'alternative' 的列表,指的是全部可能的響應列表。此響應列表結構會因 API 而異且主要用於對結果進行調試。

▌麥克風的使用

若要使用 SpeechRecognizer 訪問麥克風則必須安裝 PyAudio 軟件包,請關閉當前的解釋器窗口,進行如下操做:

安裝 PyAudio

安裝 PyAudio 的過程會因操做系統而異。

Debian Linux

若是使用的是基於 Debian的Linux(如 Ubuntu ),則可以使用 apt 安裝 PyAudio:

$ sudo apt-get install python-pyaudio python3-pyaudio複製代碼

安裝完成後可能仍須要啓用 pip install pyaudio ,尤爲是在虛擬狀況下運行。

macOS

macOS 用戶則首先須要使用 Homebrew 來安裝 PortAudio,而後調用 pip 命令來安裝 PyAudio。

$ brew install portaudio
$ pip install pyaudio
複製代碼

Windows

Windows 用戶可直接調用 pip 來安裝 PyAudio。

$ pip install pyaudio
複製代碼

安裝測試

安裝了 PyAudio 後可從控制檯進行安裝測試。

$ python -m speech_recognition
複製代碼

請確保默認麥克風打開並取消靜音,若安裝正常則應該看到以下所示的內容:

A moment of silence, please...
Set minimum energy threshold to 600.4452854381937
Say something!
複製代碼

請對着麥克風講話並觀察 SpeechRecognition 如何轉錄你的講話。

Microphone 類

請打開另外一個解釋器會話,並建立識一個別器類的例子。

>>> import speech_recognition as sr
>>> r = sr.Recognizer()
複製代碼

此時將使用默認系統麥克風,而不是使用音頻文件做爲信號源。讀者可經過建立一個Microphone 類的實例來訪問它。

>>> mic = sr.Microphone()
複製代碼

若系統沒有默認麥克風(如在 RaspberryPi 上)或想要使用非默認麥克風,則須要經過提供設備索引來指定要使用的麥克風。讀者可經過調用 Microphone 類的list_microphone_names()函數來獲取麥克風名稱列表。

>>> sr.Microphone.list_microphone_names()
['HDA Intel PCH: ALC272 Analog (hw:0,0)',
 'HDA Intel PCH: HDMI 0 (hw:0,3)',
 'sysdefault',
 'front',
 'surround40',
 'surround51',
 'surround71',
 'hdmi',
 'pulse',
 'dmix', 
 'default']
複製代碼

注意:你的輸出可能與上例不一樣。

list_microphone_names()返回列表中麥克風設備名稱的索引。在上面的輸出中,若是要使用名爲 「front」 的麥克風,該麥克風在列表中索引爲 3,則能夠建立以下所示的麥克風實例:

>>> # This is just an example; do not run
>>> mic = sr.Microphone(device_index=3)
複製代碼

但大多數狀況下須要使用系統默認麥克風。

使用 listen()獲取麥克風輸入數據

準備好麥克風實例後,讀者能夠捕獲一些輸入。

就像 AudioFile 類同樣,Microphone 是一個上下文管理器。可使用 with 塊中 Recognizer 類的 listen()方法捕獲麥克風的輸入。該方法將音頻源做爲第一個參數,並自動記錄來自源的輸入,直到檢測到靜音時自動中止。

>>> with mic as source:
...   audio = r.listen(source)
...
複製代碼

執行 with 塊後請嘗試在麥克風中說出 「hello」 。請等待解釋器再次顯示提示,一旦出現 「>>>」 提示返回就能夠識別語音。

>>> r.recognize_google(audio)
'hello'
複製代碼

若是沒有提示再次返回,多是由於麥克風收到太多的環境噪音,請使用 Ctrl + C 中斷這個過程,從而讓解釋器再次顯示提示。

要處理環境噪聲,可調用 Recognizer 類的 adjust_for_ambient_noise()函數,其操做與處理噪音音頻文件時同樣。因爲麥克風輸入聲音的可預測性不如音頻文件,所以任什麼時候間聽麥克風輸入時均可以使用此過程進行處理。

>>> with mic as source:
...   r.adjust_for_ambient_noise(source)
...   audio = r.listen(source)
...
複製代碼

運行上面的代碼後稍等片刻,嘗試在麥克風中說 「hello」 。一樣,必須等待解釋器提示返回後再嘗試識別語音。

請記住,adjust_for_ambient_noise()默認分析音頻源中1秒鐘長的音頻。若讀者認爲此時間太長,可用duration參數來調整。

SpeechRecognition 資料建議 duration 參數很多於0.5秒。某些狀況下,你可能會發現,持續時間超過默認的一秒會產生更好的結果。您所須要的最小值取決於麥克風所處的周圍環境,不過,這些信息在開發過程當中一般是未知的。根據個人經驗,一秒鐘的默認持續時間對於大多數應用程序已經足夠。

處理難以識別的語音

嘗試將前面的代碼示例輸入到解釋器中,並在麥克風中輸入一些沒法理解的噪音。你應該獲得這樣的結果:

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "/home/david/real_python/speech_recognition_primer/venv/lib/python3.5/site-packages/speech_recognition/__init__.py", line 858, in recognize_google
  if not isinstance(actual_result, dict) or len(actual_result.get("alternative", [])) == 0: raise UnknownValueError()
speech_recognition.UnknownValueError
複製代碼

沒法被 API 匹配成文字的音頻會引起 UnknownValueError 異常,所以要頻繁使用 try 和 except 塊來解決此類問題。API 會盡全力去把任何聲音轉成文字,如短咕嚕聲可能會被識別爲 「How」,咳嗽聲、鼓掌聲以及舌頭咔噠聲均可能會被轉成文字從而引發異常。

結語:

本教程中,咱們一直在識別英語語音,英語是 SpeechRecognition 軟件包中每一個recognition _ *()方法的默認語言。可是,識別其餘語音也是絕對有可能且很容易完成的。要識別不一樣語言的語音,請將 recognition _ *()方法的語言關鍵字參數設置爲與所需語言對應的字符串。

做者:David Amos

原文連接:https://realpython.com/python-speech-recognition/

相關文章
相關標籤/搜索