转自:

http://www.jianshu.com/p/5b19605792ab?utm_campaign=maleskine&utm_content=note&utm_medium=pc_all_hots&utm_source=recommendation

http://www.jianshu.com/p/6338fab6bd0a

刚刚拿到一个简单语料库练手,发现只有语音和对应文字, 这篇文章记录了从数据预处理到kaldi对数据进行训练和测试的全过程,这里首先训练单音节模型,其他模型后面再补充。

语料库处理

task : 观察语料库

语料库主要用于命令词识别,包括200个词汇,2000条语音,10个说话者分别对200个词汇进行录音。语音目录以说话者id标识:

$ tree -d
├── speaker001
├── speaker002
├── speaker003
├── speaker004
├── speaker005
├── speaker006
├── speaker007
├── speaker008
├── speaker009
├── speaker010
└── Levoice.list
每个说话者文件夹目录下包含对应的200条语音: └┤ tree speaker001
speaker001
├── .wav
├── .wav
├── .wav
...
└── .wav
语音文字说明文件Levoice.list 格式为<语音id> <文字> <录音时长>,例如: └┤ head -n Levoice.list
speaker001/.wav 三六零通讯录 5.6
speaker001/.wav 三六五日历 2.8
语料库所给的资源应用到kaldi还需要汉字发音词典,这里只能自己准备,下面会参考thchs30语料库的词典准备自己的词典。 task : 预处理语料库 为方便后续操作,需要对语料库文件进行预处理,这部分包括: 重新重命名语音文件,使2000个语音文件具有唯一标识(speakerid_voiceid.wav)
划分训练、测试、验证数据集
根据Levoice.list生成utt2words.txt ,进行文件名对应汉字映射。
上述过程脚本(注意rname命令在Ubuntu和Centos中有细微差别): !/bin/bash #if need cv or not
needcv=true # rename wav files by add prefix by "speaker"
start_path=`pwd`
for dirname in $(ls | grep "speaker")
do
#get first filename
filename=$(ls $dirname | head -n )
if [[ $filename =~ "speaker" ]]; then
echo "files in $dirname have already renamed, passing..."
else
echo "now rename flies with prefix speakers"
echo $dirname
cd $dirname
#in centos rename
rename "" $dirname"_00" ""*
# ubuntu using follows
#rename "s/00/$dirname""_00/" *
cd ..
fi
done # devide file to train, cv and test
cd $start_path
rm -rf test train cv && mkdir test train cv i=
for dirname in $(ls | grep "speaker")
do
if [ $i -lt ];then
cp $dirname/* train
else
cp $dirname/* test
fi
let i=$i+1 done function rand(){
min=$1
max=$(($2-$min+1))
num=$(($RANDOM+1000000000))
echo $(($num%$max+$min))
} count=0
array=("0" "0" "0" "0")
#ls -al train
if [ needcv ]; then
for file in $(ls train | grep "speak")
do
array[$count]=$file
let count=$count+1
if [ $count -eq 4 ];then
rnd=$(rand 0 3)
mv train/${array[$rnd]} cv
#echo ${array[$rnd]}
let count=0
fi
done
echo "cv files prepared over, examples number is $(ls cv | wc -l)"
fi
echo "train files number is $(ls train | wc -l)"
echo "test files number is $(ls test | wc -l)"
语料库对训练集、验证集、测试集参考thchs30,这里将说话人9、10语音作为测试集,再从1-8语音集中的1600百条语音文件四条语音为组随机选择一条语音归入验证集,剩下的作为训练集。划分结果训练集、验证集、测试集比例6:2:2。 在语料库目录运行上脚本,会在该目录下产生trian、test和cv目录,这些目录及文件将被后面使用。 最后直接将Levoice.list中的信息进行简单字符替换即可: speaker001/00001.wav 三六零通讯录 5.6
---->
speaker001_00001.wav 三六零通讯录 5.6
可以在vi或其他编辑器中替换即可。 应用Kaldi task0 : 构建kaldi项目结构 参照其他项目,首先复制创建项目结构目录,配置文件以及项目需要使用的依赖工具,这里多参考thchs30部分结构。在egs 目录下建立/wakeup/s5作为项目目录,在该目录下准备以下文件: $ tree -L 1
|-- cmd.sh // 运行配置目录
|-- conf // 配置文件目录
|-- local //存放run.sh 中调用的脚本工具,需要自己编写
|-- path.sh //Kaldi 工具和库目录添加到PATH
|-- run.sh // top层脚本,运行该脚本训练数据和测试, 需要自己编写
|-- steps // kaldi 脚本工具, 复制到工程目录下
|-- tools // kaldi 脚本工具, 复制到工程目录下
`-- utils // kaldi 脚本工具, 复制到工程目录下
这里cmd.sh里根据自己运行方式配置运行参数,这里配置成单机运行 export train_cmd=run.pl
export decode_cmd="run.pl --mem 4G"
export mkgraph_cmd="run.pl --mem 8G"
conf 目录包含一些配置文件,这里主要将系统采样频率与语料库的采样频率设置为一致: $ ls
decode_dnn.config fbank.conf mfcc.conf
$ more mfcc.conf
--use-energy=false # only non-default option.
--sample-frequency=8000
$ more decode_dnn.config
beam=18.0 # beam for decoding. Was 13.0 in the scripts.
lattice_beam=10.0 # this has most effect on size of the lattices.
$ more fbank.conf
--sample-frequency=8000
--num-mel-bins=40
task1 : 准备训练文件 参照kaldi数据准备部分文档,该部分需要自己根据语料库分别就train,test,cross validation目录生成以下文件: text : < uttid > < word >
wav.scp : < uttid > < utter_file_path >
utt2spk : < uttid > < speakid >
spk2utt : < speakid > < uttid >
word.txt : 同 text
编写local/data_pre.sh脚本供run.sh调用(下面会涉及run.sh脚本的编写),传入参数运行目录以及语料库目录: #!/bin/bash
# 2017-3-23 by zqh # This file prepares files needed in kaldi
# including text, wav.scp, utt2spk, spk2utt
# output:
# data/train dir include infomation of train data
# data/test dir include infomation of test data
# data/cv dir include infomation of cross validation data run_dir=$1
dataset_dir=$2 cd $run_dir
echo "prepare data in data/{train, test, cv}"
mkdir -p data/{train,test,cv} #create text, wav.scp, utt2spk, spk2utt
(
i=0
for dir in train cv test; do
echo "clean dir data/$dir"
cd $run_dir/data/$dir
rm -rf wav.scp utt2spk spk2utt word.txt text
#phone.txt
for data in $(find $dataset_dir/$dir/*.wav | sort -u | xargs -i basename {} .wav);do
let i=$i+1
spkid=$(echo $data | awk -F"_" '{print "" $1}')
uttid=$data
echo $uttid $dataset_dir/$dir/$data.wav >> wav.scp
echo $uttid $spkid >> utt2spk
# gen word.txt
echo $uttid $(cat $dataset_dir/utt2word.txt | grep $uttid | awk '{print "" $2}') >> word.txt
# gen phone.txt TODO
done
cp word.txt text
sort wav.scp -o wav.scp
sort utt2spk -o utt2spk
sort text -o text
# sort phone.txt -o phone.txt
done
echo "all file number is $i"
) || exit 1 utils/utt2spk_to_spk2utt.pl data/train/utt2spk > data/train/spk2utt
utils/utt2spk_to_spk2utt.pl data/cv/utt2spk > data/cv/spk2utt
utils/utt2spk_to_spk2utt.pl data/test/utt2spk > data/test/spk2utt
task2 : 训练语言模型 由于这里仅仅需要对语料库中的200个命令词进行识别,大而全的汉语词典并不必要,这里需要根据自己的语料建立词典并且生成语言模型。 task 2.1 : 准备词典 根据kaldi的要求,需要准备的词典包括以下文件(我这里和语料库放在同个目录下,后面kaldi从该目录下读取): [username@hostname dict]$ pwd
/home/username/dataset_wakeup/resource/dict
[username@hostname dict]$ ls
extra_questions.txt lexiconp.txt lexicon.txt nonsilence_phones.txt optional_silence.txt silence_phones.txt
对上面文件简单说明: lexicon.txt: 词典,包括语料中涉及的词汇与发音,与单字及其发音。
silence_phones.txt:静音标识,这里为sil。
nonsilence_phones.txt : 非静音标识,与silence_phones.txt共同组成lexicon.txt中的发音。
extra_questions.txt : 包含重音音调标记,这里没有用到
lexiconp.txt : 如果一个词有不同发音,则会在不同行中出现多次。如果你想使用发音概率,你需要建立 exiconp.txt 而不是 lexicon.txt,这里未使用
以上文件可以参考复制thchs30的resource资源,只要替换lexicon.txt为自己的字典,并且追加thchs30中lexicon.txt中所有的单字及其发音(简单awk命令即可)。此外该语料库仅仅提供了汉字无对应发音,需要自己参考thchs30中的词典准备,(心想只有200条,觉得手打的会很快,事实用了2-3个小时,心累,回头想可以写程序完成)。
lexicon.txt 文件内容大致为: $ more lexicon.txt
SIL sil
<SPOKEN_NOISE> sil
三六零通讯录 s an1 l iu4 l ing2 t ong1 x vn4 l u4
三六五日历 s an1 l iu4 uu u3 r iz4 l i4
三D图库 s an1 d i4 t u2 k u4
task 2.2: 生成语言模型 语言模型训练需要使用n-gram算法,借助sirlm工具可以简单实现,并进行语言模型生成: 安装 下载sirlm安装包(官网下载速慢,也可通过在github上找到相应资源下载),解压后进入最上层目录进行安装。
export SRILM=pwd
make
把$make_dir/bin/i686-m64/加入PATH以便使用其中脚本
生成语言模型 在语料库目录下创建lm_word文件夹(方便管理),复制上面的字典lexicon.txt,并删除前两行,保存为作为words.txt作语料输入文件进行n-gram语言模型生成(由于只是词汇识别设置n=1): ngram-count -order 1 -text words.txt -lm word.arpa
其他参数可以参考: -order 指定n-gram的n是多少,默认是3
-text 提供输入的语料文件,统计该语料中的n-gram
-lm 指定输出的lm文件
-vocab 用来指定对哪些词进行n-gram统计
-wbdiscount1 表示1gram Witten-Bell discounting
Note:参数顺序无所谓
该命令生成arpa格式的语言模型文件,后面由kaldi的其他工具转换为FST格式使用。 完成语言模型的生成后,对应的可以在run.sh脚本中利用该部分的语言模型,通过kaldi提供的工具构建语言模型的FST格式文件,这部分 主要创建了data/{dict,lang,graph}目录及相应文件,并在后面的构建解码图的过程中使用。run.sh脚本该部分代码: #gen lang dir
(
echo "create new dir data/dict,lang,graph"
cd $run_path
mkdir -p data/{dict,lang,graph} && \
cp $dataset//resource/dict/{extra_questions.txt,nonsilence_phones.txt,optional_silence.txt,silence_phones.txt} data/dict && \
cat $dataset/resource/dict/lexicon.txt | \
grep -v '<s>' | grep -v '</s>' | sort -u > data/dict/lexicon.txt || exit 1;
utils/prepare_lang.sh --position_dependent_phones false data/dict "<SPOKEN_NOISE>" data/local/lang data/lang || exit 1;
gzip -c $dataset/King-ASR-M-005/lm_word/word.arpa > data/graph/word.arpa.gz || exit 1;
utils/format_lm.sh data/lang data/graph/word.arpa.gz $dataset/King-ASR-M-005/lm_word/lexicon.txt data/graph/lang || exit 1;
)
这里主要包括utils/prepare_lang.sh 、 和utils/format_lm.sh 两个脚本的调用,不作具体分析。 作者:zqh_zy
链接:http://www.jianshu.com/p/5b19605792ab
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
task4 : 特征提取(FMCC)

完成了语言模型的构建,下面开始生成声学模型部分,首先对语音文件进行特征提取,这里用到了上面准备的文件,包括:text, wav.scp, utt2spk, spk2utt 。
run.sh中完成特征提取,并对语音进行归一化处理: #gen MFCC features
rm -rf data/mfcc && mkdir -p data/mfcc && cp -R data/{train,cv,test} data/mfcc || exit ;
for x in train cv test; do
#make mfcc
steps/make_mfcc.sh --nj $n --cmd "$train_cmd" data/mfcc/$x exp/make_mfcc/$x mfcc/$x || exit ;
#compute cmvn
steps/compute_cmvn_stats.sh data/mfcc/$x exp/mfcc_cmvn/$x mfcc/$x || exit ;
done
生成的特征提取相关文件保存在data/mfcc目录下,真实的数据保存在mfcc/目录下。 task5 : 训练声学模型、 构建解码图 该部分调用kaldi脚本,训练单音节模型,后面测试证明,单个词汇的识别,该模型同样能保证良好的识别效果,同样run.sh脚本中: #monophone
#steps/train_mono.sh --boost-silence 1.25 --nj $n --cmd "$train_cmd" data/mfcc/train data/lang exp/mono || exit ;
声学模型的训练结果文件保存在exp/mono目录下。下面构建解码图,这部分调用utils/mkgraph.sh, 利用先前创建的语言模型和上步训练的声学模型构建HCLG解码图,该部分生成的解码图保存在exp/mono/graph_word文件夹下: utils/mkgraph.sh --mono --nj $n data/graph/lang exp/mono exp/mono/graph_word || exit ;
task6: 测试 在local目录下创建data_decode.sh 脚本对解码步骤进行封装: #!/bin/bash
#decoding wrapper
#run from ../
nj=
mono=false
. ./cmd.sh ## You'll want to change cmd.sh to something that will work on your system.
. ./path.sh ## Source the tools/utils (import the queue.pl)
. utils/parse_options.sh || exit ; decoder=$
srcdir=$
datadir=$ if [ $mono = true ];then
echo "using monophone to generate graph"
opt="--mono"
fi #decode word
$decoder --cmd "$decode_cmd" $srcdir/graph_word $datadir/test $srcdir/decode_test_word || exit
在run.sh脚本中调用上脚本: #test mono model
local/data_decode.sh --nj "steps/decode.sh" exp/mono data/mfcc &
这里注意由于测试集只有两个说话者,并发度设置为2,否则会出现文件分割数与并发数不匹配的情况,解码过程主要用到特征提取后的test文件,上部分生成的解码图,测试结果在exp/mono/decode_test_word文件夹中查看。 为了对测试结果进行评估,还需在local目录下完成打分脚本相关的代码,这里参考thchs30,拷贝文件:score.sh、wer_output_filter 。 下面给出完整的run.sh脚本,之后运行脚本: #!/bin/bash . ./cmd.sh
. ./path.sh run_path=`pwd`
n= #parallel jobs #dataset path
dataset=~/dataset_wakeup #data prepare
#gen text, wav.scp, utt2spk, spk2utt
local/data_prep.sh $run_path $dataset/King-ASR-M- || exit #gen lang dir
(
echo "create new dir data/dict,lang,graph"
cd $run_path
mkdir -p data/{dict,lang,graph} && \
cp $dataset//resource/dict/{extra_questions.txt,nonsilence_phones.txt,optional_silence.txt,silence_phones.txt} data/dict && \
cat $dataset/resource/dict/lexicon.txt | \
grep -v '<s>' | grep -v '</s>' | sort -u > data/dict/lexicon.txt || exit ;
utils/prepare_lang.sh --position_dependent_phones false data/dict "<SPOKEN_NOISE>" data/local/lang data/lang || exit ;
gzip -c $dataset/King-ASR-M-/lm_word/word.arpa > data/graph/word.arpa.gz || exit ;
utils/format_lm.sh data/lang data/graph/word.arpa.gz $dataset/King-ASR-M-/lm_word/lexicon.txt data/graph/lang || exit ;
) #gen MFCC features
rm -rf data/mfcc && mkdir -p data/mfcc && cp -R data/{train,cv,test} data/mfcc || exit ;
for x in train cv test; do
#make mfcc
steps/make_mfcc.sh --nj $n --cmd "$train_cmd" data/mfcc/$x exp/make_mfcc/$x mfcc/$x || exit ;
#compute cmvn
steps/compute_cmvn_stats.sh data/mfcc/$x exp/mfcc_cmvn/$x mfcc/$x || exit ;
done #monophone
steps/train_mono.sh --boost-silence 1.25 --nj $n --cmd "$train_cmd" data/mfcc/train data/lang exp/mono || exit ;
#decode word # make decoder graph
utils/mkgraph.sh --mono data/graph/lang exp/mono exp/mono/graph_word || exit ; #test mono model
local/data_decode.sh --nj "steps/decode.sh" exp/mono data/mfcc &
运行脚本,由于数据量不大,并不需要很长时间,运行测试结束查看效果: [uesrname@hostname scoring_kaldi]$ ls
best_wer log penalty_0. penalty_0. penalty_1. test_filt.txt wer_details
[uesrname@hostname scoring_kaldi]$ more best_wer
%WER 5.57 [ / , ins, del, sub ] exp/mono/decode_test_word/wer_17_1.
错词率为5.%,在penalty_1.0中可以查看最好的识别结果。 小结 文章记录了从拿到语料库,到应用Kaldi的全过程,主要想对流程进行总结,对语音识别相关的原理没有涉及太多。另外这里仅仅训练了单音节模型,其他模型可以参照thchs30完成,这里不再补充。
过程中遇到的小问题很多,一个比较典型的,一开始想偷懒直接使用thchs30的词典,后来识别结果很差,单词均为一个或两个毫不相干的字。考虑自己语料库中的词汇在thchs30的词典中并未涉及,还是通过自己标注词典解决问题。 作者:zqh_zy
链接:http://www.jianshu.com/p/6338fab6bd0a
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

[转]Kaldi命令词识别的更多相关文章

  1. 如何用kaldi做孤立词识别-初版

    ---------------------------------------------------------------------------------------------------- ...

  2. 机器学习&数据挖掘笔记_13(用htk完成简单的孤立词识别)

    最近在看图模型中著名的HMM算法,对应的一些理论公式也能看懂个大概,就是不太明白怎样在一个具体的机器学习问题(比如分类,回归)中使用HMM,特别是一些有关状态变量.观察变量和实际问题中变量的对应关系, ...

  3. 基于HTK语音工具包进行孤立词识别的使用教程

    选自:http://my.oschina.net/jamesju/blog/116151 1前言 最近一直在研究HTK语音识别工具包,前几天完成了工具包的安装编译和测试,这几天又按耐不住好奇,决定自己 ...

  4. Shell出现cd命令无法识别

    出现cd 等命令无法识别的原因可能是: 当前文件实在windows环境下编辑的其换行结尾是 \r\n 和linux环境的 \n 不一致导致错误, 最好在linux系统上通过 VI 命令新建文件,然后通 ...

  5. CRF技能词识别过程

    最近在用CRF做未登录技能词识别,虽然艰难,但是感觉很爽,效率非常高. (1)数据准备: 选取30000行精语料作为训练数据.每一个br作为一条数据.使用已有的技能词典对数据进行无标注分词. (2)训 ...

  6. yesno孤立词识别kaldi脚本

    path.sh主要设定路径等 export KALDI_ROOT=`pwd`/../../.. [ -f $KALDI_ROOT/tools/env.sh ] && . $KALDI_ ...

  7. 如何用kaldi做孤立词识别三

    这次wer由15%下降到0%了,后面跑更多的模型 LOG (apply-cmvn[5.2.124~1396-70748]:main():apply-cmvn.cc:162) Applied cepst ...

  8. 如何用kaldi做孤立词识别二

    基本模型没有变化,主要是调参,配置: %WER     65%  下降到了     15% 后面再继续优化... Graph compilation finish!steps/decode.sh -- ...

  9. 亲自动手用HTK实现YES NO孤立词识别

    很久以前的发在研学论坛的帖子了,再重新整理了一下,希望对新手有用. 完整版链接:http://yun.baidu.com/s/1hapcE 第一步 创建语音文件 录音 命令:HSLab any_nam ...

随机推荐

  1. paloalto防火墙版本升级

    1.准备工作:此部分不影响生产环境,可直接操作. 1)备份: 2)下载OS HA情况下,在主机下载完成后,选择 Sync To Peer(同步到对端)同步到备机. 2.安装更新 1)在备机上选择安装 ...

  2. checkpoint防火墙SmartDashboard登录出错

    SmartDashboard登录是报错:fingerprint不匹配 原因:主备机切换导致 解决:选择凌晨不影响业务的时间拔掉原备机的电源线.

  3. VS2017用正则表达式替换多行代码

    await IndexManyAsync\(item.Value, item.Key, "doc"\);\r\n.*\}.*\r\n.*\} 上面的代码,匹配的是下面的代码 awa ...

  4. Find out where to contain the smartforms

    Go to table E071 and give smarforms name and it will give the transport req for that. Run SE03, choo ...

  5. Android设备直接运行java项目?还杀不死?

    思路:拿到dex可执行文件,使用android执行 使用idea创建java类库,写相关逻辑代码 使用idea导出该类库jar包 使用android dx工具 将jar文件转换为dex可执行文件 dx ...

  6. js对象属性 通过点(.) 和 方括号([]) 的不同之处

    //    js对象属性 通过点(.) 和 方括号([]) 的不同之处 //    1.点操作符: 静态的.右侧必须是一个以属性名称命名的简单标识符.属性名用一个标识符来表示.标识符必须直接出现再js ...

  7. java之servlet学习基础(二)

    上一次写到Servlet的实现方法,主要还是通过继承HttpServlet来实现Servlet.下面主要是回顾一下HttpServletRequest和HttpServletResponse对象中的一 ...

  8. python基础之Day23

    1.封装 什么是? 封:明确地把属性隐藏起来 ,对外隐藏,对内开放 申请名称空间,往里面装入一系列名字 /属性(类比 类 和对象   只是装的概念) 为什么要用? __init__往对象里丢属性 封装 ...

  9. .NET core RSA帮助类

    解决 Operation is not supported on this platform 异常 直接上代码: public class RSAHelper { /// <summary> ...

  10. C#替换文件中特定字符串,按照原来的编码格式保存

    private void button1_Click(object sender, EventArgs e) { var txt1 = "E:\\Temp\\local"; str ...