基於kaldi的在線語音識別

本文是基於kaldi的在線語音識別,使用b/s架構進行在線識別。適用於剛剛接觸的小白。

開發環境:jdk-1.8,Ubuntu16.04,Eclipse。

開發過程:

(1)準備必須的文件

如果你想要實現在線語音識別功能在kaldi下,那麼你需要有訓練好的“35.mdl、final.mdl、HCLG.fst、words.txt、”這些文件。這些文件分別位於你訓練的文件中的   比如 kaldi/egs/cn/s1/exp/*tri1/  和 kaldi/egs/cn/s1/exp/tri1/graph/目錄下。(不同的模型,不同的文件)

(2)文件的準備以及代碼的修改

在kaldi/tools目錄下運行 sudo bash extras/install_portaudio.sh

從kaldi/egs/voxforge/的目錄下拷貝出來online_demo文件夾(先運行run.sh (sudo bash run.sh)之後再拷貝)。拷貝到你訓練的模型文件夾下。比如kaldi/cn/目錄下。創建完成之後,在online_demo/online_data/models/目錄下,創建一個文件,比如tir1(三因素的模型),然後將(1)中的四個文件拷貝到tri1中。

將你要識別的音頻文件拷貝到online_demo/online_data/audio/目錄下。

(3)修改online_demo/run.sh

將這段話改爲你的模型的文件夾的名字

# Change this to "tri2a" if you like to test using a ML-trained model
ac_model_type=tri1

將你的模型文件放置進去

online-wav-gmm-decode-faster --verbose=1 --rt-min=0.8 --rt-max=0.85\
            --max-active=4000 --beam=12.0 --acoustic-scale=0.0769 \
            scp:$decode_dir/input.scp $ac_model/final.mdl$ac_model/HCLG.fst \
            $ac_model/words.txt '1:2:3:4:5' ark,t:$decode_dir/trans.txt \
            ark,t:$decode_dir/ali.txt $trans_matrix;;

將以下的代碼刪掉

if [ ! -s ${data_file}.tar.bz2 ]; then
    echo "Downloading test models and data ..."
    wget -T 10 -t 3 $data_url;

    if [ ! -s ${data_file}.tar.bz2 ]; then
        echo "Download of $data_file has failed!"
        exit 1
    fi
fi

(4)遇到的問題

可能解碼出來的結果不是你想要的句子,那麼你需要手動進行“拼接”,因爲這裏的解碼只解碼到了  一個詞的“ID”,然後生成的是“詞的序列”,不是你想要的,那麼你就要手動拼接,我寫的拼接代碼如下,僅供參考,不會的可以再問我。

package com.imut.handlwav;
/**
* Created by IMUT-GB503-韓佳俊
* Date 2017-12-18
* Email [email protected]
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;

public class WavToWord {

public static String Handle(String path) {
String result = null;
//將音頻文件拷貝到你所用模型的文件下的在線識別文件的音頻文件中
String command="cp "+path+" /home/jiajun/kaldi/egs/cn/online_demo/online-data/audio/";
EcecuteShell(command);
//執行識別命令
command = "bash /home/jiajun/OnlineDecoding/run.sh";
EcecuteShell(command);
//將識別ID組合成序列(詞序列)
IDCombine("/home/jiajun/kaldi/egs/cn/online_demo/work/trans.txt","/home/jiajun/kaldi/egs/cn/online_demo/work/ref.txt");
//將ID翻譯成句子
IDToWord("/home/jiajun/kaldi/egs/cn/online_demo/work/ref.txt","/home/jiajun/kaldi/egs/cn/online_demo/online-data/models/tri1/words.txt","/home/jiajun/OnlineDecoding/result.txt");
//提取結果內容
result = WithdrawResult("/home/jiajun/OnlineDecoding/result.txt");
//刪除拷貝進來的音頻文件
command="rm -rf /home/jiajun/kaldi/egs/cn/online_demo/online-data/audio/";
EcecuteShell(command);
//因爲上一步的刪除也會把文件夾刪掉,因爲必須有文件夾,所以要再創建一個
command="mkdir /home/jiajun/kaldi/egs/cn/online_demo/online-data/audio/";
EcecuteShell(command);
command="touch /home/jiajun/kaldi/egs/cn/online_demo/online-data/audio/trans.txt";
EcecuteShell(command);
return result;
}
//執行linux下的shell命令
public static void EcecuteShell(String command) {
try {
Process ps = Runtime.getRuntime().exec(command);
ps.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
//提取結果
private static String WithdrawResult(String path) {
StringBuilder result = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new FileReader(path));// 構造一個BufferedReader類來讀取文件
String s = null;
while ((s = br.readLine()) != null) {// 使用readLine方法,一次讀一行
if(s.equals(""))
continue;
result.append(s);
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return result.toString();
}

//把一個音頻的ID號(對應單詞)組合起來,形成ID序列(句子)
public static void IDCombine(String readPath,String outPath) {
FileOutputStream out = null;
try {
BufferedReader br = new BufferedReader(new FileReader(readPath));// 構造一個BufferedReader類來讀取文件
String s = null;
String result="";
out = new FileOutputStream(new File(outPath));
while ((s = br.readLine()) != null) {// 使用readLine方法,一次讀一行
String temp[]=s.split(" ");
for(int i=1;i<temp.length;i++) {
result=result+temp[i];
result=result+" ";
}
}
result=result.trim();
out.write(result.getBytes());
br.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//將識別的ID號轉換成句子。這個得自己手動寫,文件結構爲多行,在每一行有兩列: ID 對應的單詞 ,根據識別的ID號將單詞組合起來。
public static void IDToWord(String readPath1,String readPath2,String outPath) {
FileOutputStream out = null;
try {
BufferedReader br = new BufferedReader(new FileReader(readPath1));// 構造一個BufferedReader類來讀取文件
String s1 = null;
String result="";
out = new FileOutputStream(new File(outPath));
while ((s1 = br.readLine()) != null) {// 使用readLine方法,一次讀一行
String temp[]=s1.split(" ");
for(int i=0;i<temp.length;i++) {
BufferedReader brtemp = new BufferedReader(new FileReader(readPath2));// 構造一個BufferedReader類來讀取文件
String stemp = null;
while ((stemp = brtemp.readLine()) != null) {// 使用readLine方法,一次讀一行
String wordToId[]=stemp.split(" ");
if(temp[i].equals(wordToId[1])) {
result=result+wordToId[0];
result=result+" ";
}
}
brtemp.close();
}
}
result=result.trim();
out.write(result.getBytes());
br.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
(5)注意事項

一定要根據你的據地路徑來改,以上的代碼均是根據我的路徑來改的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章