有趣的开源软件:语音识别工具Kaldi (二)

时间:2022-08-31 18:13:24

在上一篇blog中简单的介绍了Kaldi的安装方法 有趣的开源软件:语音识别工具Kaldi (一) 在这篇blog中继续Kaldi模型训练的步骤,介绍一下在模型训练之前的一些数据准备的工作。因为我也是正在学习语音识别和Kaldi,有些地方不一定说的很正确,如果发现错误,还请指正。

在Kaldi源代码树中,有一个叫做egs的文件夹,在这个文件夹中保存着一些Kaldi在公共数据集上的训练步骤(shell脚本)以及测试的结果。其中,中文的语音识别公共数据集一共有三个,分别是

  • gale_mandarin: 中文新闻广播数据集(LDC2013S08, LDC2013S08)
  • hkust: 中文电话数据集(LDC2005S15, LDC2005T32)
  • thchs30: 清华大学30小时的数据集,可以在http://www.openslr.org/18/下载

在这blog中使用的是hkust数据集进行实验。

目录结构

hkust数据集相关的脚本以及实验结果位于kaldi/egs/hkust,它的目录结构如下

.
├── README.txt
└── s5
├── cmd.sh
├── conf
│   ├── cmu2pinyin
│   ├── decode.config
│   ├── fbank.conf
│   ├── mfcc.conf
│   ├── pinyin2cmu
│   └── pinyin_initial
├── local
│   ├── create_oov_char_lexicon.pl
│   ├── ext
│   │   ├── 195k_chinese_word2char_map
│   │   ├── hkust_word2ch_tran.pl
│   │   ├── score_basic_ext.sh
│   │   └── score.sh
│   ├── hkust_data_prep.sh
│   ├── hkust_extract_subdict.pl
│   ├── hkust_format_data.sh
│   ├── hkust_normalize.pl
│   ├── hkust_prepare_dict.sh
│   ├── hkust_segment.py
│   ├── hkust_train_lms.sh
│   ├── nnet
│   │   ├── run_cnn.sh
│   │   ├── run_dnn.sh
│   │   └── run_lstm.sh
│   ├── nnet2
│   │   ├── run_5d.sh
│   │   └── run_convnet.sh
│   ├── nnet3
│   │   ├── run_ivector_common.sh
│   │   ├── run_lstm.sh
│   │   └── run_tdnn.sh
│   ├── score_basic.sh
│   ├── score_sclite_conf.sh
│   ├── score_sclite.sh
│   └── score.sh
├── path.sh
├── RESULTS
├── run.sh
├── steps -> ../../wsj/s5/steps
└── utils -> ../../wsj/s5/utils

其中README.txt是对于这个数据集的一些说明性的东西,对于这个数据集不熟悉的话可以去看一下。

s5/run.sh包含了在这个数据集上所有的训练步骤,包括数据预处理、训练以及测试gmm/dnn/lstm/blstm/tdnn等模型、实验结果统计在内的各种脚本。理论上来说只要相关环境配置正确,运行run.sh就能完成整个训练步骤。但是Kaldi的官方文档还是建议能够将这个文件里面的脚本一步一步粘贴到shell里面运行。这样既能够容易的发现错误,又可以对Kaldi整个运行的步骤有所了解。

s5/RESULTS里面保存着最近的实验结果。这边稍简单贴几条(CER也就是character error rate):

  • mono0a(mono-phone的GMM-HMM): %CER 80.89
  • tri1(最简单的tri-phone GMM-HMM): %CER 60.01
  • tri5a_mmi_b0.1(用MMI损失函数): %CER 43.95
  • dnn5b_pretrain-dbn_dnn: %CER 39.42
  • cnn5c_pretrain-dbn_dnn: %CER 38.80
  • tdnn_sp: %CER 33.79
  • lstm_sp_ld5: %CER 33.51

s5/conf就是一些训练所要用到的配置文件。

s5/{local, steps, utils}里面则是run.sh所要用到的一些脚本文件。

数据处理

在run.sh最开始的部分主要是一些数据的预处理步骤, 在运行它之前首先把hkust的数据放在某个固定的地方(在STEP1中会用到)。然后切换到run.sh所在的路径,在我的计算机上,它位于~/Documents/kaldi/egs/hkust/s5

$ pwd
/home/ling0322/Documents/kaldi/egs/hkust/s5

因为这个实验中是单机跑,所以需要运行cmd.sh中的几条命令,并且把queue.pl修改成run.pl

$ export train_cmd="run.pl --mem 8G"
$ export decode_cmd="run.pl --mem 8G"
$ export mkgraph_cmd="run.pl --mem 12G"

把这些环境变量export出去,接着可以开始一步一步执行run.sh中的脚本了

STEP 1

$ local/hkust_data_prep.sh /home/ling0322/Documents/hkust-data/LDC2005S15 /home/ling0322/Documents/hkust-data/LDC2005T32

这一步主要做的是将和hkust的数据复制到data文件夹下,以及一些数据格式的转换工作,期间还会使用到mmseg对文本做简单的分词。

STEP 2

下一步工作是生成音素词典,音素词典记录着每一个词发音所包含的音节序列。比如中文词语的音素就可以是声母韵母拆开的序列,依据这样的规则像“测试”的音素序列就可以是“c e4 sh i4”。

不过要成功运行这段脚本,还需要安装一些它依赖的环境

$ sudo apt install gawk swig python-numpy python-dev
$ local/hkust_prepare_dict.sh

在输出中简单检查一下输出,特别是检查以下两行的第一列数字,如果是0的话就是上面某一步骤出错了

10894 data/local/dict/lexicon-ch/words-ch-oov.txt
19467 data/local/dict/lexicon-ch/lexicon-ch-iv.txt

STEP 3

接下去是准备tri-phone模型的决策树question集合以及编译Transducer L。Transducer L用于将音素序列映射成词语序列。关于各个Transducer有什么用可以去参考Some Kaldi Notes。要具体弄清楚Transducer到底是什么,还是需要去看这篇paper:Speech Recognition with Weighted Finite-State Transducers

$ utils/prepare_lang.sh data/local/dict "<UNK>" data/local/lang data/lang

接着是去训练3-gram的语言模型,由这个语言模型生成Transducer G,然后将L和G这两个Transducer拼接起来,产生Transducer LG。Transducer LG可以用来对给定的输入的音素序列,使用3-gram语言模型(G)找出最有可能的词语序列。

$ local/hkust_train_lms.sh
$ local/hkust_format_data.sh

看到

Done training LM of type 3gram-mincount

以及

hkust_format_data succeeded

这一步就成功了

STEP 4

现在可以开始从声音数据中抽取MFCC特征。MFCC中文简称为梅尔频率倒谱系数,是一种尽可能接近人类听觉系统而抽出的一种声音特征的表示方法。这个略微偏向信号处理,具体过程可以去参考语音信号处理相关的书。

在执行下面步骤之前,最好再次检查确认一下$train_cmd是否设置正确

$ echo "$train_cmd"
run.pl --mem 8G

然后运行

$ mfccdir=mfcc
$ for x in train dev; do
$ steps/make_mfcc.sh --cmd "$train_cmd" --nj 10 data/$x exp/make_mfcc/$x $mfccdir || exit 1;
$ steps/compute_cmvn_stats.sh data/$x exp/make_mfcc/$x $mfccdir || exit 1;
$ done

STEP 5

最后一步是清理训练数据,移除一些没用的片段

$ utils/fix_data_dir.sh data/train
fix_data_dir.sh: kept 197387 utterances out of 197391
fix_data_dir.sh: old files are kept in data/train/.backup

至此,数据准备以及预处理阶段就成功完成了,接着就可以开始训练模型阶段了。