Kaldi 入門教學 - Kaldi tutorial for dummy
最近開始接觸語音辨識,經過一番搜尋後,在網路上找到幾個相關的 toolkit,分別是 CMUSphinx、Kaldi 還有 Mozilla 的 DeepSpeech。CMUSphinx 是由卡內基美隆大學開發的,DeepSpeech 則是由 Mozilla 基於百度的 Deep Speech 研究所開發的,百度發的論文在這邊,有興趣的可以去看一下,這裡就不對這些語音辨識工具多做介紹了,文章把重點放在 Kaldi 的安裝與使用教學。
為什麼選擇 Kaldi
我一開始是想找個可以用 Python 開發的語音辨識工具,因為寫起來比較方便,後來找到 CMUSphinx,他有提供 Python 的介面,但是在網路上看到大家對 CMUSphinx 的評價都不太好(準確度方面),於是我就繼續找,過程中在 Telegram 上面找到一個討論 Speech Recognition 的群組,就上去問一下有沒有比較推薦的訓練工具,有人建議我可以試試 Kaldi,花了些時間搜尋有關 Kaldi 的教學還有說明文件後,發現他的參考資料比 CMUSphinx 多很多,而且官方說明文件也很完整,不過原生的 Kaldi 貌似沒有提供 Python 的 API,使用上是以 shell script 為主,這讓我猶豫了一下,不過後來翻了一下那些 shell script,其實也沒有很複雜,就是檔案多了點,畢竟我目前沒有打算把模型的實作方法整個看懂,重心主要擺在「訓練及使用模型」,了解訓練流程就足夠了,所以就決定先試試看 Kaldi,看他的表現如何。至於為什麼不用 Mozilla 的 DeepSpeech,因為我寫這篇文章的前幾個小時才發現有這個東西,等文章寫好之後我就會去看看 DeepSpeech 了,如果可以的話希望也可以寫一篇教學,寫寫自己的心路歷程。
廢話不多說,現在就開始我們今天的重點,Kaldi 的官網有兩篇教學,Kaldi tutorial 和 Kaldi for Dummies tutorial,這篇文章會針對後者做解說,文章的編排我會盡量按照 Kaldi for Dummies tutorial 的目錄走,內容則會用我自己的方法去說明,不會完全照著原文翻譯,當然還是建議大家有能力的話可以直接去看原文。
開發環境
官方說__盡量在 Linux 環境執行__,畢竟不管是安裝套件或是修改設定,Linux 對開發者還是比較友善的。我則是在 wsl 上執行,因為我只有筆電(Windows 10 Home),然後又不想裝虛擬機,覺得每次開開關關很麻煩,所以決定裝 wsl,我選的是 Ubuntu 18.04 的版本。
官方教學在這邊有列出一些「必須安裝的工具」跟「可裝可不裝的工具」,可以先不管他們,等到安裝完 Kaldi 之後這些工具也一併安裝好了。
下載與安裝 Kaldi
用 git 把 Kaldi 的 source 下載下來
1 | git clone https://github.com/kaldi-asr/kaldi.git kaldi --origin upstream |
然後先照著 kaldi/tools/INSTALL 裡面的說明把該裝的裝一裝,再照著 kaldi/src/INSTALL 裡的步驟安裝 Kaldi。
Kaldi 路徑設置
clone 下來的 kaldi 資料夾裡面有很多東西,官方列出其中幾個比較需要知道的:
- egs:各種範例,每個範例裡面都有 README 可以參考,範例中的 shell script 也都有很詳細的註解,後面的教學也會用到這個資料夾
- misc:一些額外的工具,我自己是沒有管他啦
- src:Kaldi 的 source code,這裡有官方的詳細解說
- tools:很多很多的工具,在訓練的時候會用到,這裡有官方的詳細解說
- windows:如果真的必須在 Windows 上面執行 Kaldi 的話,務必要看看這個資料夾,官方很貼心的提供了一些工具
簡易 Kaldi 範例
情境
現在我們有許多來自不同受試者的錄音檔,錄音的內容為英文數字,每個錄音檔都包含三個數字。例如:「one nine zero」。
目的
我們希望把這些錄音檔拆成 training set 跟 testing set,然後建立自動語音辨識。
第一步
先在 egs 裡面建立一個 digits 資料夾,接下來的動作都會在這個資料夾裡面進行。
準備訓練資料
錄音檔
訓練會用到的錄音檔可以在這邊下載,裡面一共有 128 個單聲道 16000 Hz 的 wav 檔,並且已經被分成 train 與 test,分別包含 80 個與 40 個錄音,檔名的格式是 ID_<錄音裡面的三個數字>
,這邊有八個 ID,可以想成是八個不同的人的錄音,錄音檔按照 ID 又被細分為八個資料夾,所以我們錄音檔的結構會長這樣:
- 八個不同的人
- 每個人有 16 個錄音檔
- 總共 128 個句子(每個人 16 個)
- 總共 128 * 3 個英文數字(每個句子有三個英文數字)
在剛剛建立的 digits 資料夾裡面建立一個名為 digits_audio 的資料夾,在 digits_audio 裡面再建立兩個資料夾 train 跟 test,然後把先前下載好的錄音檔裡面的 train 跟 test 分別放到剛剛建立的 train 跟 test 裡面。
聲學資料
建立好錄音檔後,還得告訴 Kaldi 一些關於這些聲音的資訊,首先先在 digits 下建立一個 data 資料夾,然後在 data 裡面一樣建立 train 跟 test,接著分別在 train 跟 test 裡面依序建立以下這些檔案:
我相信不會有人想要自己一行一行打這些檔案(我自己就不想),所以我寫了幾個簡單的 script 來自動產生這些檔案(除了 spk2gender),連結在這裡,不過建議大家先把下面關於檔案的說明都看完,了解檔案格式之後再跑 script。
spk2gender
這個檔案是關於說話的人的性別,格式如下:
1 | <speakerID> <gender> |
speakerID
可以當成是說話的人的名字,前提是這些名字不重複,gender
就是性別,男生是 m
,女生是 f
,就我們的錄音檔來看,speakerID
就是 1 到 8,前五個是男生,後三個是女生,所以檔案內容會像下面這樣:
1 | 1 m |
wav.scp
這個檔案是每個句子所對應的錄音檔路徑,格式如下:
1 | <utteranceID> <full_path_to_audio_file> |
每個句子都有一個 utteranceID
,utteranceID
沒有特別規定的格式,不過為了方便起見,這邊就以錄音檔的檔名作為 utteranceID
,full_path_to_audio_file
就檔案的完整路徑,所以檔案內容會像下面這樣:
1 | 1-040 /path/to/1-040.wav |
text
這個檔案是每個句子所對應的錄音內容,格式跟參考內容如下:
1 | <utteranceID> <text_transcription> |
1 | 1-040 zero four zero |
utt2spk
這個檔案是每個句子所對應的說話者,格式跟參考內容如下:
1 | <utteranceID> <speakerID> |
1 | 1-040 1 |
corpus.txt
這個檔案要包含所有會出現在自動語音辨識系統裡面的句子,以我們的錄音為例, corpus.txt 裡面會有 128 個句子,分別對應到 128 錄音檔的內容,格式跟參考內容如下:
1 | <text_transcription> |
1 | zero four zero |
另外要注意這個檔案存放的地方跟上面那些檔案比較不一樣,要在之前建立的 data 資料夾裡面,建立一個 local 資料夾,並把 corpus.txt 丟進去。
語言資料
這部分就是要準備一些跟我們要辨識的語言有關的文件,首先先在上個環節建立的 local 下建立 dict 資料夾,接著依序建立以下檔案:
lexicon.txt
這個檔案包含了所有會出現在自動語音辨識系統裡面的字的發音,發音則是由一個至多個音素(phone)組成,格式如下:
1 | <word> <phone 1> <phone 2> ... |
以我們的教學為例, lexicon.txt 裡面就是 0 到 9 的發音,這邊直接把所有的發音提供給大家使用:
1 | !SIL sil |
nonsilence_phones.txt
這個檔案包含了所有 non silence 的音素,這邊一樣把格式跟檔案內容提供給大家:
1 | <phone> |
1 | ah |
silence_phones.txt
這應該看檔名就知道了,格式跟檔案內容如下:
1 | <phone> |
1 | sil |
optional_silence.txt
1 | <phone> |
1 | sil |
到目前為止我們已經把訓練要用的資料都準備好了,接下來要準備訓練用的工具。
準備訓練用的工具
一些必要的工具
把 kaldi/egs/wsj/s5 裡面的 utils 跟 steps 這兩個資料夾複製到我們的 digits 下面,如果想省硬碟空間的話也可以考慮用 symbolic link 的方式。
評估模型表現的工具
在我們的 digits 資料夾下建立一個 local 資料夾,把 kaldi/egs/voxforge/s5/local 裡面的 score.sh 複製到這邊。
SRILM
詳細的安裝說明請到 kaldi/tools/install_srilm.sh 裡面看。
建立 configure
在 digits 下建立一個 conf 資料夾,在裡面建立 decode.config 跟 mfcc.conf 兩個檔案,檔案的內容如下:
decode.config
1 | first_beam=10.0 |
mfcc.conf
1 | --use-energy=false |
這兩個檔案是用來調整訓練模型時候的一些參數。
準備訓練用的 shell script
接著要準備訓練模型的程式,在 digits 下依序建立這三個檔案:
cmd.sh
1 | # Setting local system jobs (local CPU - no external clusters) |
path.sh
1 | # Defining Kaldi root directory |
run.sh
1 |
|
訓練模型
該準備的都準備好了,目前的 digits 資料夾結構會長這樣:
1 | . |
最後在 terminal 打上 ./run.sh
就可以開始訓練了,訓練出來的結果可以去 exp 裡面看,副檔名為 .mdl 的就是我們訓練出來的模型,其中 final.mdl 是訓練過程跑完後的最終模型,他其實是個 link,連到同一個資料夾裡面的 <number>.mdl。
以上就是官方 Kaldi for Dummies tutorial 的解說,接下來會說明怎麼使用訓練好的模型來測試自己的錄音檔。
如何使用模型
準備測試工具
先到 kaldi/src/online 下面 make,把該編譯的東西編一編,然後把 kaldi/egs/voxforge 下面的 online_demo 整個複製到我們的 digits 資料夾下面。
準備模型與錄音檔
在我們剛剛複製過來的 online_demo 下建立兩個資料夾,online-data 跟 work,online-data 要擺我們的模型跟錄音,work 可以先不管他,跑測試的過程中產生的檔案會被丟進去,然後在 online-data 裡面建立 audio 跟 model 兩個資料夾。
把要測試的 wav 放到 audio 裡面,另外在 audio 裡建立一個 trans.txt,檔案內容就是 wav 的對應到的語音內容,舉例來說:test1.wav 的內容是「one two three」,那 trans.txt 就會是:
1 | test1 one two three |
接著在 model 下建立 tri1 資料夾,資料夾內要包含以下四個檔案:
- <number.mdl>:模型(在 digits/exp/tri1 裡面)
- final.mdl:一個 link,連到模型(在 digits/exp/tri1 裡面)
- HCLG.fst:完整的 fst(在 digits/exp/tri1/graph 裡面)
- words.txt:字典,給每個字一個編號(在 digits/exp/tri1/graph 裡面)
修改一下 online_demo 下的 run.sh,把 ac_model_type
改成 tri1
(原本應該是 tri2b_mmi
),另外原本的 run.sh 裡面有一段下載 testing data 的程式碼,把它註解掉。
1 | if [ ! -s ${data_file}.tar.bz2 ]; then |
最後,把 run.sh 裡面 $ac_model/model
的地方都改成 $ac_model/final.mdl
(應該有兩個地方要改),都弄好之後 online_demo 的結構應該會像這樣:
1 | . |
執行 run.sh 就可以看到測試結果了。
vosk api 補上 沒用過