ASR/CV/ML      Kaldi初次手动训练模型流程   

本文环境:
● 硬件:
2018版 MacBook Pro
  ▶ CPU:2.3 GHz Intel Core i5
  ▶ 内存:8 GB 2133 MHz LPDDR3
  ▶ 无独立显卡
● Kaldi:
commit id:66f5434d29e2a528b9363e0fa25f2793069602a3
● 参考文献:
https://www.bilibili.com/video/BV19a4y1h7cB
https://www.bilibili.com/video/BV1Ch411p7fJ
https://www.bilibili.com/video/BV1KU4y1K7gz
https://blog.csdn.net/weixin_42217661/article/details/117715318
《Kaldi语音识别实战》陈果果、都家宇、那兴宇、张俊博 / 著

● www.gaohaiyan.com

1.编译kaldi

Mac上使用brew安装较慢或不能下载墙外程序时,可为 brew 配置国内镜像。终端执行以下命令:
阿里镜像:

中科大镜像:

重置


1.1.检查依赖

进入 %kaldi%/tools/ 目录。
检查依赖是否安装完备。缺啥安装啥

./check_dependencies.sh: automake is not installed.
./check_dependencies.sh: autoconf is not installed.
./check_dependencies.sh: wget is not installed.
./check_dependencies.sh: sox is not installed.
./check_dependencies.sh: gfortran is not installed
./check_dependencies.sh: neither libtoolize nor glibtoolize is installed
./check_dependencies.sh: Intel MKL does not seem to be installed.
 ... Download the installer package for your system from:
 ...  https://software.intel.com/mkl/choose-download
 ... You can also use other matrix algebra libraries. For information, see:
 ...  http://kaldi-asr.org/doc/matrixwrap.html
./check_dependencies.sh: The following prerequisites are missing; install them first:
  automake autoconf wget sox gfortran libtool

gfortran可以从 https://github.com/fxcoudert/gfortran-for-macOS/releases 下载。

1.2.编译tools

进入 %kaldi%/tools/ 目录。

if [ -d "" ]; then \
  cp -p "/cub-1.8.0.tar.gz" .; \
else \
  wget -nv -T 10 -t 3 -O cub-1.8.0.tar.gz \
    https://github.com/NVlabs/cub/archive/1.8.0.tar.gz; \
fi
if [ -d "" ]; then \
  cp -p "/sph2pipe-v2.5.tar.gz" \
    sph2pipe-2.5.tar.gz; \
else \
  wget -nv -T 10 -t 3 -O sph2pipe-2.5.tar.gz \
    https://github.com/burrmill/sph2pipe/archive/2.5.tar.gz; \
fi
extras/check_dependencies.sh: python2.7 is installed, but the python2 binary does not exist. Creating a symlink and adding this to tools/env.sh
x SCTK-20159b580249f1598caa35ab469bd1acdb3dd86c/CHANGELOG
---
很多很多...
---
libtool: install: chmod 644 %kaldi%/tools/openfst-1.7.2/lib/fst/olabel_lookahead-fst.a
make[3]: Nothing to be done for `install-exec-am'.
make[3]: Nothing to be done for `install-data-am'.
rm -f openfst
ln -s openfst-1.7.2 openfst
-e
Warning: IRSTLM is not installed by default anymore. If you need IRSTLM
Warning: use the script extras/install_irstlm.sh
All done OK.


1.2.1安装irstlm

这是kaldi自带的训练工具。

****() Installing IRSTLM
Cloning into 'irstlm'...
remote: Enumerating objects: 1781, done.
remote: Total 1781 (delta 0), reused 0 (delta 0), pack-reused 1781
Receiving objects: 100% (1781/1781), 3.54 MiB | 641.00 KiB/s, done.
Resolving deltas: 100% (1187/1187), done.
patching file configure.ac
patching file src/Makefile.am
---
很多...
---
make[2]: Nothing to be done for `all'.
Making install in src
.././install-sh -c -d '%kaldi%/tools/irstlm/lib'
/bin/sh ../libtool --mode=install /usr/bin/install -c libirstlm.la '%kaldi%/tools/irstlm/lib'
libtool: install: /usr/bin/install -c .libs/libirstlm.lai %kaldi%/tools/irstlm/lib/libirstlm.la
Making install in scripts
make[2]: Nothing to be done for `install-exec-am'.
.././install-sh -c -d '%kaldi%/tools/irstlm/bin'
/usr/bin/install -c add-start-end.sh build-lm-qsub.sh build-lm.sh rm-start-end.sh split-ngt.sh mdtsel.sh build-sublm.pl goograms2ngrams.pl lm-stat.pl merge-sublm.pl ngram-split.pl sort-lm.pl split-dict.pl plsa.sh '%kaldi%/tools/irstlm/bin'
Making install in doc
make[2]: Nothing to be done for `install-exec-am'.
/Library/Developer/CommandLineTools/usr/bin/make install-exec-hook
cd %kaldi%/tools/irstlm/ && \
    ln -s -n -f lib lib64
make[2]: Nothing to be done for `install-data-am'.
***() Installation of IRSTLM finished successfully
***() Please source the tools/env.sh in your path.sh to enable it

新生成的env.sh里设置了3个环境变量,以利于之后直接执行
%kaldi%/egs/aishell/s5/path.sh 或
%kaldi%/egs/aishell/s5/run.sh 或
%kaldi%/egs/yesno/s5/run.sh
等示例项目指令。

export PATH=%kaldi%/tools/python:${PATH}
export IRSTLM=%kaldi%/tools/irstlm
export PATH=${PATH}:${IRSTLM}/bin


1.2.2安装srilm

这是早于kaldi诞生的工具。指令如“ngram-xxx”。
使用脚本安装srilm须要注册账号(收费),所以手动下载安装。
1)先装好gawk。
Macos brew install gawk
Linux sudo apt install gawk
2)然后从这里下载 https://github.com/BitSpeech/SRILM/tags ,本例1.7.2,
解压 SRILM-1.7.2.zip 到 %kaldi%/tools/srilm ,
3)extras/install_srilm.sh文件修改如下:

4)执行:

SRILM download requires some information about you
Usage: extras/install_srilm.sh <name> <organization> <email>
Moonmen:tools moonmen$ extras/install_srilm.sh
mkdir -p include lib bin
/Library/Developer/CommandLineTools/usr/bin/make init
for subdir in misc dstruct lm flm lattice utils zlib; do \
     (cd $subdir/src; /Library/Developer/CommandLineTools/usr/bin/make SRILM=%kaldi%/tools/srilm MACHINE_TYPE=macosx OPTION= MAKE_PIC= init) || exit 1; \
     done
cd ..; %kaldi%/tools/srilm/sbin/make-standard-directories
/Library/Developer/CommandLineTools/usr/bin/make ../obj/macosx/STAMP ../bin/macosx/STAMP
mkdir ../bin/macosx/
touch ../bin/macosx/STAMP
/Library/Developer/CommandLineTools/usr/bin/make release-headers
for subdir in misc dstruct lm flm lattice utils zlib; do \
     (cd $subdir/src; /Library/Developer/CommandLineTools/usr/bin/make SRILM=%kaldi%/tools/srilm MACHINE_TYPE=macosx OPTION= MAKE_PIC= release-headers) || exit 1; \
     done
%kaldi%/tools/srilm/sbin/decipher-install -p 0444 cfuncproto.h ../../include
%kaldi%/tools/srilm/sbin/decipher-install -p 0444 zconf.h ../../include
/Library/Developer/CommandLineTools/usr/bin/make depend
for subdir in misc dstruct lm flm lattice utils zlib; do \
      (cd $subdir/src; /Library/Developer/CommandLineTools/usr/bin/make SRILM=%kaldi%/tools/srilm MACHINE_TYPE=macosx OPTION= MAKE_PIC= depend) || exit 1; \
      done
rm -f Dependencies.macosx
cc -Wall -Wno-unused-variable -Wno-uninitialized -Wno-overloaded-virtual -DHAVE_LIBLBFGS -I%kaldi%/tools/srilm/../liblbfgs-1.10/include -I/usr/include -I. -I../../include -DHAVE_ZOPEN -MM ./option.c ./zio.c ./fcheck.c ./rand48.c ./version.c ./ztest.c | sed -e "s&^\([^ ]\)&../obj/macosx"'$(OBJ_OPTION)'"/\1&g" -e "s&\.o&.o&g" >> Dependencies.macosx
c++ -Wall -Wno-unused-variable -Wno-uninitialized -Wno-overloaded-virtual -DINSTANTIATE_TEMPLATES -DHAVE_LIBLBFGS -I%kaldi%/tools/srilm/../liblbfgs-1.10/include -I/usr/include -I. -I../../include -DHAVE_ZOPEN -MM ./Debug.cc ./File.cc ./MStringTokUtil.cc ./tls.cc ./tserror.cc ./tclmain.cc ./testFile.cc ./testRand.cc | sed -e "s&^\([^ ]\)&../obj/macosx"'$(OBJ_OPTION)'"/\1&g" -e "s&\.o&.o&g" >> Dependencies.macosx
%kaldi%/tools/srilm/sbin/generate-program-dependencies ../bin/macosx ../obj/macosx "" ztest testFile testRand | sed -e "s&\.o&.o&g" >> Dependencies.macosx
make[2]: Nothing to be done for `release-programs'.
/Library/Developer/CommandLineTools/usr/bin/make release-scripts
for subdir in misc dstruct lm flm lattice utils zlib; do \
     (cd $subdir/src; /Library/Developer/CommandLineTools/usr/bin/make SRILM=%kaldi%/tools/srilm MACHINE_TYPE=macosx OPTION= MAKE_PIC= release-scripts) || exit 1; \
     done
make[2]: Nothing to be done for `release-scripts'.
make[2]: Nothing to be done for `release-scripts'.
%kaldi%/tools/srilm/sbin/decipher-install 0555 compare-sclite ../../bin
%kaldi%/tools/srilm/sbin/decipher-install 0555 cumbin ../../bin
make[2]: Nothing to be done for `release-scripts'.
readlink: illegal option -- f
usage: readlink [-n] [file ...]
Installation of SRILM finished successfully
Please source the tools/env.sh in your path.sh to enable it

evn.sh文件又多了4行:

export PATH=%kaldi%/tools/python:${PATH}
export IRSTLM=%kaldi%/tools/irstlm
export PATH=${PATH}:${IRSTLM}/bin
export LIBLBFGS=%kaldi%/tools/liblbfgs-1.10
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}:${LIBLBFGS}/lib/.libs
export SRILM=%kaldi%/tools/srilm
export PATH=${PATH}:${SRILM}/bin:${SRILM}/bin/macosx

根据需要每次在终端手动设置,或者直接加入环境变量。
之后在终端输入指令的前一两个字母,然后按 Tab 键就能出现相关提示。

1.2.3安装openblas

本步骤,在Linux替代MKL。
查看%kaldi%/tools/extras/install_openblas.sh中OPENBLAS_VERSION对版本的要求,也可修改为新版,
从github.com/xianyi/OpenBLAS/releases下载tar.gz到~/Download中,
执行:

安装成功提示

Install OK!
OpenBLAS is installed successfully.


1.3.编译源码

进入 %kaldi%/src 目录。
替换MKL ./configure −−mathlib=OPENBLAS
或使用默认MKL ./configure

Configuring KALDI to use MKL.
Checking compiler g++ ...
Checking OpenFst library in %kaldi%/tools/openfst-1.7.2 ...
Checking cub library in %kaldi%/tools/cub-1.8.0 ...
Performing OS specific configuration ...
On Darwin: Checking for Accelerate framework ...
Configuring for OS X version 10.14 ...
Successfully configured for Darwin with Accelerate framework.
WARNING: CUDA will not be used! If you have already installed cuda drivers
      and CUDA toolkit, try using the --cudatk-dir= option. A GPU and CUDA
      are required to run neural net experiments in a realistic time.
Kaldi has been successfully configured. To compile:
  make -j clean depend; make -j <NCPU>
where is the number of parallel builds you can afford to do. If unsure,
use the smaller of the number of CPUs or the amount of RAM in GB divided by 2,
to stay within safe limits. 'make -j' without the numeric value may not limit
the number of parallel jobs at all, and overwhelm even a powerful workstation,
since Kaldi build is highly parallelized.

test -d || mkdir
/Library/Developer/CommandLineTools/usr/bin/make depend
The version of configure script matches kaldi.mk version. Good.
****() Installing portaudio
Could not find portaudio tarball pa_stable_v19_20111121.tgz locally, downloading it...
/Library/Developer/CommandLineTools/usr/bin/make -C base/ depend
/Library/Developer/CommandLineTools/usr/bin/make -C bin/ depend
/Library/Developer/CommandLineTools/usr/bin/make -C chain/ depend
rm -f .depend.mk
g++ -M -std=c++14 -I.. -I%kaldi%/tools/openfst-1.7.2/include -O1 -Wall -Wno-sign-compare -Wno-unused-local-typedefs -Wno-deprecated-declarations -Winit-self -DKALDI_DOUBLEPRECISION=0 -DHAVE_EXECINFO_H=1 -DHAVE_CXXABI_H -DHAVE_CLAPACK -msse -msse2 -pthread -g -Wno-mismatched-tags chain-den-graph.cc chain-denominator.cc chain-generic-numerator.cc chain-numerator.cc chain-supervision-test.cc chain-supervision.cc chain-training.cc language-model-test.cc language-model.cc >> .depend.mk
configure.in:55: warning: back quotes and double quotes must not be escaped in: unknown Windows API \"$api\" (do you need --help?)
configure.in:104: warning: The macro `AC_LIBTOOL_WIN32_DLL' is obsolete.
/Library/Developer/CommandLineTools/usr/bin/make -C sgmm2
g++ -std=c++14 -I.. -I%kaldi%/tools/openfst-1.7.2/include -O1 -Wall -Wno-sign-compare -Wno-unused-local-typedefs -Wno-deprecated-declarations -Winit-self -DKALDI_DOUBLEPRECISION=0 -DHAVE_EXECINFO_H=1 -DHAVE_CXXABI_H -DHAVE_CLAPACK -msse -msse2 -pthread -g -Wno-mismatched-tags -I/usr/local/opt/openssl/include -c -o nnet-nnet.o nnet-nnet.cc
---
相当多...
---
g++ -Wl,-rpath -Wl,%kaldi%/tools/openfst-1.7.2/lib -g -L/usr/local/opt/openssl/lib lattice-add-nnlmscore.o ../rnnlm/kaldi-rnnlm.a ../nnet3/kaldi-nnet3.a ../cudamatrix/kaldi-cudamatrix.a ../lat/kaldi-lat.a ../lm/kaldi-lm.a ../fstext/kaldi-fstext.a ../hmm/kaldi-hmm.a ../tree/kaldi-tree.a ../util/kaldi-util.a ../matrix/kaldi-matrix.a ../base/kaldi-base.a %kaldi%/tools/openfst-1.7.2/lib/libfst.dylib -framework Accelerate -lm -lpthread -ldl -o lattice-add-nnlmscore
echo Done
Done


1.4.kaldi内部环境变量

进入 %kaldi%/egs/aishell/s5/ 目录,或者 %kaldi%/egs/wsj/s5 。
查看 path.sh 文件,
第一行 “export KALDI_ROOT=” 对应的是 %kaldi% 根目录。
第二行 [ -f $KALDI_ROOT/tools/env.sh ] && . $KALDI_ROOT/tools/env.sh 注意env.sh路径正确
第三行 “export PATH=$PWD/utils/:$KALDI_ROOT/tools/openfst/bin:$PWD:$PATH” 注意openfst路径正确。
执行 ./path.sh
使编译kaldi后生成的新指令在当前终端生效。

也可以加入到环境变量。
先添加权限
chmod 777 %kaldi%/tools/env.sh
chmod 777 %kaldi%/tools/config/common_path.sh
chmod 777 %kaldi%/egs/wsj/s5/cmd.sh
chmod 777 %kaldi%/egs/wsj/s5/path.sh
然后把文件全路径加入.bash_profile 或Linux的.bashrc文件:
source %kaldi%/egs/wsj/s5/path.sh
再然后,source一下.bash_profile 或.bashrc,就可以在终端敲入指令的前两三个字母,按tab键出现提示了。

注意如果像本例一样单机学习测试,要修改同目录下的(即path.sh中调用的)cmd.sh,把 queue.pl 修改为 run.pl 。


2.材料准备

语料:
http://www.openslr.org/18/
http://www.aishelltech.com/kysjcp
本例:https://aishell-1-sample.oss-cn-beijing.aliyuncs.com/AISHELL-1_sample.zip

通常原始语料包括的信息有:录音员的id和性别、录音内容文稿的文本文件、录制的音频文件。
录音员称呼(id):recorder_01。
文稿文件名通常即录音员id,如 recorder_01.txt 。每行一个句子:
● 今天是星期一
● 我有1个梦想
录音文件则放在通常以录音员id为名称的文件夹中,
每个句子对应一个音频文件:
● ~/wavs/recorder_01/today_is_sunday.wav
● ~/wavs/recorder_01/i_hava_a_dream.wav

把音频文件整理在1个目录,如 %kaldi%/egs/xiaogao/wav/ 。

3.材料整理

选择某种方式(python/shell),整理出如下几个生成模型所需的“档案文件”。

3.1.声学模型材料

下面4个文件放在同一个目录,如 %kaldi%/egs/xiaogao/data/ 。

3.1.1.音频id列表文件 wav.scp

wav.scp是一个文本文件,每行内容为:[音频id] [音频路径] ,如:
● recorder_01_wav_01  %kaldi%/egs/xiaogao/wav/recorder_01/today_is_sunday.wav
● recorder_01_wav_02  %kaldi%/egs/xiaogao/wav/recorder_01/i_have_a_dream.wav
此时的音频id通常是录音员id+音频文件名 。

3.1.2.音频与录音员对照文件utt2spk

utt2spk是一个文本文件,每行内容为:[音频id] [录音员] ,如:
● recorder_01_wav_01  recorder_01
● recorder_01_wav_02  recorder_01
即将音频文件和录音员对应起来。

3.1.3.录音员与音频对照文件spk2utt

内容为:[录音员] [音频id 音频id 音频id ...] ,如:
● recorder_01  recorder_01_wav_01  recorder_01_wav_02  recorder_01_wav_03 ...
● recorder_02  recorder_02_wav_01  recorder_02_wav_02  ...
即将录音员和他录制的全部音频对应起来。每个录音员对应1行。
使用 %kaldi%/egs/wsj/s5/utils/spk2utt_to_utt2spk.pl 可以自动将utt2spk转为spk2utt:
utt2spk_to_spk2utt.pl ./utt2spk > ./spk2utt

3.1.4.音频与文稿分词对照文件 text

内容为:[文本id] [录音语句的文本] ,如:
● recorder_01_wav_01  今天是星期一
● recorder_01_wav_02  我有1个梦想
文本id和音频id相同,对应同一个音频文件。
同时,文本须要做分词,词语之间用空格分开。最终格式如:
● recorder_01_wav_01  今天  是  星期一
● recorder_01_wav_03  我  有  一个  梦想
分词规则:
♦ 标点符号(非汉字和英文大小写字母和数字的)都去除,如:+—*/ ; / ( } 换行符 制表符 表情 数学序号 注音符号 拉丁符号等。
♦ 通常汉语数字不分词,如:一百、五十、三千、十万、一个。
♦ 纯汉语数字语句进行分词,如电话号码:幺、八、六、五、五、六、六、幺、幺、零。
♦ 英文单词之间已有空格的,不需再加更多空格。
♦ 分词时/分词前根据音频对文本进行转换,如‘85cm’转为“八十五厘米”、‘3%’转为“百分之三”、‘3.5℃’转为“三点五度”。

中文分词库 :
https://github.com/fxsjy/jieba

3.1.5.语料检验

使用 %kaldi%/egs/wsj/s5/utils/fix_data_dir.sh 验证 wav.scp、utt2spk、spk2utt、text 四个文件是否备齐。
./fix_data_dir.sh %kaldi%/egs/xiaogao/data

3.2.语言模型材料

下面6个文件放到同一个目录,如 %kaldi%/egs/xiaogao/data/dict/ 。
参考 %kaldi%/egs/hkust/s5/local/hkust_prepare_dict.sh

3.2.1.词语清单文件words.list

上一步分词的同时,生成一个保存全部出现过的词语的文件 words.list。
每行内容为1个词(字):[词语] ,如:
● 是
● 今天
● 我
● 有
● 个
● 梦想
● 星期
● 一
words.list主要用来创建针对自己的项目可用的精简版lexicon.txt。临时使用,这一步是可选的。很多博客或视频里讲到,生产中通常使用尽可能大的lexicon.txt。

3.2.2.发音词典文件 lexicon.txt

内容为:[字/词] [发音音素] 。
首先要有一个类似《新华字典》的大的标准字典。
这里使用kaldi内置的中文发音词典。查看%kaldi%/egs/hkust/s5/local/hkust_prepare_dict.sh文件,约144行:http://www.mdbg.net/chindict/export/cedict/cedict_1_0_ts_utf-8_mdbg.txt.gz 。
下载查看,内容如下:

第一列为繁体,第二列为简体。
第三列是中括号包裹的发音,并非标准的汉语拼音。数字1-4对应拼音声调的阴平、阳平、晌声、去声。
第四列为斜杠开头的用英文对词语的翻译和说明。

cedict_1_0_ts_utf-8_mdbg.txt词汇量还是较小的(9.4M,约120293行),最好使用更全(词语量更多)的发音词典。
aishelltech的http://www.aishelltech.com/kysjcp页面底端“Netdisk”链接页面里,有个resource_aishell.tgz解压后得到1个lexicon文件(3.5M,约139874行)也是发音词典,只有汉语对应发音。

它和kaldi的发音词典不同之处是 “声母” “韵母” 分开了,用此字典生成phones.txt时,声母韵母也是各自独立的。

然后,从标准字典里查出用到的词,提取出我们自己的小字典。
挨个取words.list中的词语,在cedict_1_0_ts_utf-8_mdbg.txt中查找,提取匹配的发音,不得重复,不能有标点,生成lexicon.txt。
最终内容如:

其中:
“!SIL SIL”,是OOA标识词语,即说两个字之间的停顿/静音,或长时间静默。文件最后一行添加。
FIL”这一类内容是原始文本中出现的表示杂音的符号。

有些博客及视频中讲解,生产环境通常使用超集的字典(如上面说的2个的合体),即不根据语料创建小字典。

3.2.3.音素集合文件 phones.txt

也有人讲,此文件命名为phone.txt。就是把lexicon.txt中的发音提取出来。内容:[音素] ,如:
● shang4
● hai3
● yan3
● jing1
使用lexicon.txt将发音拿出来即可,要去重,去标点,有效音素包括杂音符号。如:
● s
● hang4
● h
● ai3
● y
● an3
● j
● ing1

3.2.4.静音音素清单silence_phones.txt

内容如下:
● FIL
● NON
● NPS
● SPK
● STA
● SPN
● SIL
这些是phones.txt文件中出现的,无意义的杂音符号。

3.2.5.非静音音素清单nonsilence_phones.txt

内容即phones.txt中去除静音音素,就是把silence_phones.txt出现的去除剩下的。

3.2.6.填充音素extra_questions.txt

或者叫 optional_silence.txt,可选的静音音素,音调和重音之类的信息,可使用silence_phones.txt中的内容。
内容如下:
● SIL

3.3.其它

回到%kaldi%/egs/xiaogao/
创建2个软连接
ln -s %kaldi%/egs/wsj/steps/ . 把steps链接到当前目录,
ln -s %kaldi%/egs/wsj/utils/ .   把utils链接到当前目录。
ln -s %kaldi/egs/wsj/s5/conf/ .  把conf链接到当前目录。
现在 %kaldi%/egs/xiaogao/ 目录结构:
steps/
utils/
conf/
wav/
  *.wav
data/
  wav.scp
  utt2spk
  spk2utt
  text
  dict/
    lexicon.txt
    phones.txt
    silence_phones.txt
    nonsilence_phones.txt
    optional_silence.txt

模型训练方式:
1)笼统的不区分性别、地域、人员
2)按性别区分,或地域区分
3)按录音人员区分

关于数据拆分:
比如有10个录音员,每人一千条录音,共一万条录音(及对应的文本)。一般的会拿出九千条作训练集,一千条作测试集。

window中的文件转Linux下文件:
方法1:cat dos.txt | tr -d '\r' > lix.txt
方法2:使用dos2unix程序

4.发音词典L.fst

H.fst:HMM模型、C.fst:Context上下文关系、L.fst:Lexicon发音词典、G.fst:Grammar语法模型-语法规则接收器。

4.1.训练

%kaldi%/egs/wsj/s5/utils/prepare_lang.sh参数:
prepare_lang.sh <dict-src-dir> <oov-dict-entry> <tmp-dir> <lang-dir>
● options:
  --num-sil-states <number of states>    默认5。静音音素状态划分数量。用1(单态)会缩小模型体积。
  --num-nonsil-states <number of states>   默认3, 非静音音素状态划分数量。
  --position-dependent-phones (true|false)   默认 true,使用_B、_E、_S、_I划分音素的起始结束状态。
  --share-silence-phones (true|false)     默认 false; if true, share pdfs
  --sil-prob (probability of silence)      默认0.5,必须大于等于0且小于1
  --phone-symbol-table <filename>     默认""。如果非空则使用指定的phones.txt
  --unk-fst <text-fst>             默认none
  --extra-word-disambig-syms <filename>   默认"";
● dict-src-dir 此语言模型材料的目录里 %kaldi%/egs/xiaogao/data/dict ,
  此目录必须包含如下文件:
    extra_questions.txt
    lexicon.txt
    nonsilence_phones.txt
    optional_silence.txt
    silence_phones.txt
  参阅 http://kaldi-asr.org/doc/data_prep.html#data_prep_lang_creating for more info.
● oov-dict-entry   OOA标识词,如果出现了不在词典里的字词,用这个替代。
● tmp-dir       临时目录,如 %kaldi%/egs/xiaogao/lang_tmp
● lang-dir      输出目录,如 %kaldi%/egs/xiaogao/lang_out

进入 %kaldi%/egs/xiaogao 目录,执行语句:
utils/prepare_lang.sh --num-sil-states 1 --num-nonsil-states 1 --position-dependent-phones false ./dict '<SIL>' ./lang_tmp ./lang_out

或者进入 %kaldi%/egs/wsj/s5/utils/目录,使用数据的完整路径作为prepare_lang.sh的参数进行训练。
如果出现错误:

sh: ./path.sh: No such file or directory
--> ERROR: L/lang_out//L.fst is not olable sorted
sh: ./path.sh: No such file or directory
--> ERROR: L/lang_out//L_disambig.fst is not olable sorted
--> ERROR (see error messages above)
prepare_lang.sh: error validating output

回退到 %kaldi%/egs/wsj/s5/ 执行 utils/prepare_lang.sh ...

成功结束后,在 lang_out 下生成 L.fst 语音模型文件。

4.2.查看L.fst

使用 %kaldi%/tools/openfst-1.7.2/bin/fstprint 查看L.fst文件内容。
fstprint %kaldi%/egs/xiaogao/lang_out/L.fst
内容如下,有5列数字,以表的形式演示图结构:
0  1  0  0  0.3453523
第1列,输入状态-起点 ①;
第2列,输出状态-终点 ②;
第3列,输入音素,对应了L.fst同目录的phones.txt ♥;
第4列,输出单词,对应了L.fst同目录的words.txt ♣;
第5列,概率 ♦。
有向图的一条边:① -- ♥ ; ♣/♦ --> ②
可以指定关联的文件进行查看:
fstprint --isymbols=phones.txt --osymbols=words.txt L.fst

使用 %kaldi%/tools/openfst-1.7.2/bin/fstdraw 查看L.fst文件内容。
brew install ghostscript graphviz chkuni-ukai-fonts
fstdraw --isymbols=phones.txt --osymbols=words.txt L.fst > L.dot
dot -Tjpg L.dot > L.jpg
dot生成jpg这一步是非常慢的,因为图的数据结构非常复杂,图片会相当大,即便生成也很难查看。

4.3.tmp-dir下的临时文件

● align_lexicon.txt     词典。词语+发音音素对应的Begin、Internal、End、Singleton状态
● lex_ndisambig     词典。最大同音词字数量+1
● lexiconp.txt       词典。添加词频
● lexiconp_disambig.txt   词典。同音词消除歧义,同音字词添加#标注。#1 - #同音词字数量
● phone_map.txt     音素集合。添加音素的Begin、Internal、End、Singleton状态

4.4.lang-dir下的文件

● L.fst        字典的加权有限状态转换器
● L_disambig.fst   去岐后的
● oov.int      词典之外的词添加id
● oov.txt      词典之外的词。识别结果为
● phones       [文件夹]
  ▶ align_lexicon.ini   字词+BIES音素转id
  ▶ align_lexicon.txt   字词+字词+BIES
  ▶ context_indep.ini
  ▶ context_indep.txt   静音音素列出BIES状态
  ▶ disambig.csl
  ▶ disambig.ini
  ▶ disambig.txt       同音词歧义编号#
  ▶ extra_questions.ini
  ▶ extra_questions.txt   按BIES状态整理音素
  ▶ nonsilence.csl
  ▶ nonsilence.ini
  ▶ nonsilence.txt      去除静音的+BIES
  ▶ optional_silence.csl
  ▶ optional_silence.ini
  ▶ optional_silence.txt   静音音素
  ▶ roots.ini
  ▶ roots.txt         音素的树
  ▶ sets.ini
  ▶ sets.txt          发音音素列出BIES状态
  ▶ silence.csl
  ▶ silence.ini
  ▶ silence.txt         静音音素列出BIES状态。似乎和context_indep.txt相同
  ▶ wdisambig.txt
  ▶ wdisambig_phones.ini
  ▶ wdisambig_words.ini
  ▶ word_boundary.ini
  ▶ word_boundary.txt    明文显示音素的Begin、Internal、End、Singleton状态
● phones.txt  添加BIES状态的音素集合
● topo    表述拓扑的文本文件
● words.txt  添加id的词

5.Grammar模型G.fst

使用《3.1.4.音频与文稿分词对照文件 text》创建的text文件,生成一个去除了第一列音频id的 text.txt 文件。放到一个目录,如 %kaldi%/egs/xiaogao/gram 。
text.txt内容如:
● 今天 是 星期一
● 我 有 一个 梦想

5.1.统计文件

上文《1.2.2》及《1.4》后可以直接在终端调用ngram-count指令了。
%kaldi%/tools/srilm/bin/macosx/ngram-count 的参数:
● -text  指定分词文件。%%kaldi%/egs/xiaogao/gram/text.txt
● -order  指定生成几元的n-gram。计数时每行“短句”最大分词数量。
● -write  指定计数统计文件生成路径。
进入 %kaldi%/egs/xiaogao/gram 目录
ngram-count -text ./text.txt -order 3 -write ./text.count
得到text.count文件。

5.2.统计模型

继续使用ngram-count指令。
● -read      上一步生成的text.count文件
● -order     上一步指定的数值
● -lm      模型生成路径
● -interpolate   开启差值平滑
● -kndiscount   折扣/回退算法,有如下几种:
  ▶ -addsmooth。  “加-k”折扣算法
  ▶ -cdiscount。  使用Ney的绝对折扣算法,使用参数discount作为折扣常数,discount必须要介于0和1之间。
  ▶ -wbdiscount。  使用Witten-Bell折扣算法。
  ▶ -ndiscount。  使用Ristad自然折扣算法。
  ▶ -ukndiscount。 使用“原始Kneser-Ney”的折扣算法。
  ▶ -kndiscount。  经过插值的Kneser-Ney折扣算法,输出的是经过Kneser-Ney算法修正之后的计数。
  ▶ 如果不设定,默认为Good-Turing折扣算法。
ngram-count -read ./text.count -order 3 -lm ./text.lm -interpolate -kndiscount
得到text.lm文件。

关于剪枝,可以压缩模型大小。
https://www.bilibili.com/video/BV19a4y1h7cB?p=4 1:48:00
https://blog.csdn.net/xmdxcsj/article/details/50321613

5.3.G.fst

方法1:

还在 %kaldi%/egs/xiaogao/gram 目录下,
使用 %kaldi%/egs/wsj/s5/utils/format_lm_sri.sh 脚本,参数:
● <lang-dir&gt  《4.1.训练》章节指定的输出目录:如 %kaldi%/egs/xiaogao/lang_out 。
● <arpa-LM>   上一步生成的text.lm
● <lexicon>   可选。《3.2.2.发音词典文件 lexicon.txt》
● <out-dir>   模型生成的目录,不包括文件名。
format_lm_sri.sh ../lang_out ./text.lm ../data/dict/lexicon.txt ./
指令成功后,./ 目录下得到G.fst文件。

方法2:

还在 %kaldi%/egs/xiaogao/gram 目录下,
使用 %kaldi%/src/lmbin/arpa2fst 工具,参数:
● options:
  --disambig-symbol  消岐符号。使用#0,则会进行以下处理:
  ▶ 删除空边。如果一个状态上只发出空边(即回退边),则删除该边并状态合并。从语义上讲是删除了不存在的二元词历史所映射的状态,达到减小状态数的目的。
  ▶ 用特殊符号#0替换回退边上的输入空符号。
  ▶ 将开始结束标签<s> </s>替换为空。
  --read-symbol-table  《4.1.训练》章节指定的输出目录里的words.txt文件:%kaldi%/egs/xiaogao/lang_out/words.txt
● <arpa-LM> 上一步生成的text.lm
● <out-dir> 模型生成的目录包括文件名。
arpa2fst --disambig-symbol=#0 --read-symbol-table=../lang_out/words.txt ./text.lm ./G.fst

5.4.查看G.fst

结合上文《4.2.查看L.fst》使用 %kaldi%/tools/openfst-1.7.2/bin/fstprint 查看L.fst文件内容的操作。
还在 %kaldi%/egs/xiaogao/gram 目录下,
fstprint --isymbols=../lang_out/phones.txt --osymbols=../lang_out/words.txt ./G.fst > G.txt
或 %kaldi%/tools/openfst-1.7.2/bin/fstdraw
fstdraw --isymbols=../lang_out/phones.txt --osymbols=../lang_out/words.txt ./G.fst > G.dot
dot -Tjpg ./G.dot > G.jpg

6.声学模型final.mdl

6.1.H.fst

梅尔倒谱系数,一种语音特征。
%kaldi%/egs/wsj/s5/steps/make_mfcc.sh
make_mfcc.sh [options] <data-dir> [<log-dir> [<mfcc-dir>]
● Options:
  --mfcc-config <config-file>        设置了compute-mfcc-feats参数的文件。
  --nj <nj>               拆分成并行任务数量。
  --cmd <run.pl|queue.pl <queue opts>>   如何执行任务,单机就用run.pl。
  --write-utt2num-frames <true|false>    true会生成一个utt2num_frames文件,记录每个音频有多少帧
  --write-utt2dur <true|false>       true会生成一个utt2dur file文件
● data-dir: 《3.1.4.音频与文稿分词对照文件 text》的路径 %kaldi%/egs/xiaogao/data
● log-dir:  已存在日志目录,默认同data-dir。如 %kaldi%/egs/xiaogao/log
● mfcc-dir: 已存在输出目录,默认同data-dir。如 %kaldi%/egs/xiaogao/mfcc

进入 %kaldi%/egs/xiaogao/ 目录,
steps/make_mfcc.sh --nj 1 ./data ./log ./mfcc
有多少音频文件,就在 %kaldi%/egs/xiaogao/mfcc 下生成多少scp文件和ark文件

6.2.提取特征均值

%kaldi%/egs/wsj/s5/steps/steps/compute_cmvn_stats.sh 参数:
compute_cmvn_stats.sh [options] <data-dir> [<log-dir> [<cmvn-dir>] ]
● Options:
  --fake
  --two-channel
  --fake-dims <n1:n2>
● data-dir  %kaldi%/egs/xiaogao/data/
● log-dir  不设置,则默认同data-dir
● cmvn-dir  不设置,则默认同data-dir

进入 %kaldi%/egs/xiaogao/ 目录,
steps/compute_cmvn_stats.sh ./data ./cmvn_log ./cmvn_out

6.3.训练final.mdl

%kaldi%/egs/wsj/s5/steps/train_mono.sh 参数:
train_mono.sh [options] <data-dir> <lang-dir> <exp-dir>
● options:
  --config <config-file>  配置文件
  --nj <nj>      线程数
  --cmd (utils/run.pl|utils/queue.pl <queue opts>)  如何执行
● data-dir  %kaldi%/egs/xiaogao/data/
● lang-dir  %kaldi%/egs/xiaogao/lang_out/
● exp-dir  %kaldi%/egs/xiaogao/mono/

进入 %kaldi%/egs/xiaogao/ 目录,
steps/train_mono.sh --nj 1 ./data ./lang_out ./mono
./mono 下生成final.mdl声学模型文件。

7.解码网络模型HCLG.fst

%kaldi%/egs/wsj/s5/utils/mkgraph.sh 参数:
mkgraph.sh [options] <lang-dir> <model-dir> <graphdir>
● options:
  --remove-oov     true时,任何包含OOV的将从G.fst编译.
  --transition-scale 
  --self-loop-scale    参阅 http://kaldi-asr.org/doc/hmm.html#hmm_scale.
● lang-dir
● model-dir
● graphdir

进入 %kaldi%/egs/xiaogao/ 目录,
utils/mkgraph.sh ./lang_out ./mono ./graph
./graph 下生成HCLG.fst 。

可以使用 fstprint,或 fstdraw+dot 查看。


承接App定制、企业web站点、办公系统软件 设计开发,外包项目,毕设