2.3 安装
Kaldi不是一个终端用户软件,没有安装包。安装Kaldi指的是编译Kaldi代码,以及准备一些必要的工具和运行环境。由于Kaldi的示例都是使用Shell脚本的,并且其I/O大量依赖管道,因此最佳的运行环境是UNIX类系统。最常用的环境是Debian和Red Hat Linux,但是在Linux的其他发行版、Cygwin和macOS中也可以使用。此外,在Kaldi代码中还提供了在Microsoft Windows下使用Visual Studio编译Kaldi代码的选项,这部分内容在本章中也会提及。
2.3.1 下载Kaldi代码
早期的Kaldi代码使用Sourceforge管理,从2015年5月起,迁移到GitHub上维护,使用git clone下载源代码。
2.3.2 安装CUDA
Kaldi的GPU计算部分使用NVIDIA公司开发的CUDA框架,在NVIDIA官网上有不同版本的安装包可以选择,Kaldi通常支持最新的版本。在安装过程中,要用root权限,每一步都使用默认设置即可。安装好之后查看CUDA的安装位置:
这里安装的是8.0版本,可以看到CUDA已经生成了一个默认安装路径,指向8.0版本。
2.3.3 安装编译依赖库
在Linux和macOS环境下编译Kaldi代码依赖几个系统开发库,进入Kaldi文件夹可以查看依赖库是否已经被安装:
这个脚本将检查以下开发库的安装情况,读者可以根据脚本输出的提示安装。
· 编译工具,要求使用G++、Apple LLVM或Clang。目前,Kaldi对这几个编译工具的版本要求是G++ 4.8.3以上、Apple LLVM 3.3以上、Clang 5.0以上。
· zlib开发库,包括zlib-devel、zlib1g-dev和zlib-devel。
· 矩阵运算开发库,默认是IntelMKL,也可以用ATLAS或OpenBLAS代替。
· 编译支持工具,包括libtool、automake、autoconf、patch、bzip2、gzip、wget、subversion。
· 脚本依赖工具,包括Python、gawk、Perl,这部分工具在编译时不需要,但是在运行样例脚本时非常必要。
2.3.4 安装第三方工具
第三方工具指的是无法在系统安装包管理器中获取的工具。Kaldi提供了安装这些工具的脚本,包括以下几种。
· OpenFst。Kaldi使用FST作为状态图的表现形式,其代码依赖OpenFst中定义的FST结构及一些基本操作,因此OpenFst对于Kaldi的编译是不可或缺的,安装方法如下:
· CUB。CUB是NVIDIA官方提供的CUDA核函数开发库,是目前Kaldi编译的必选工具,安装方法如下:
· Sclite。它是NIST SCTK打分工具的一部分,工具用于生成符合NIST评测规范的统计文件。如果只需要计算识别率,则这个工具不是必须的,Kaldi自身包括一个简单的计算WER的工具compute-wer。Sclite的安装方式如下,在编译的时候可以不安装:
· Sph2pipe。这个工具是用来对SPH音频格式进行转换的,使用LDC数据的示例都要用到这个工具。安装方式如下,在编译的时候可以不安装:
· IRSTLM/SRILM/Kaldi_lm。这是三个不同的语言模型工具,不同的示例使用不同的语言模型工具。安装方式如下,在编译的时候可以不安装:
其中,在安装SRILM时有两点需要注意。第一,SRILM用于商业用途不是免费的,需要到SRILM网站上注册、接受许可协议,才能下载源码包,并需重命名为srilm.tgz,放到tools文件夹下。第二,SRILM的安装依赖lbfgs库,这个库的安装方法是:
· OpenBLAS/MKL。Kaldi的最新版本已经选用MKL作为默认的矩阵运算库。如果需要手工安装OpenBLAS或MKL,方法如下:
2.3.5 选择其他的矩阵库
除上述ATLAS、OpenBLAS和MKL外,Kaldi的矩阵运算代码还支持使用CLAPACK。LAPACK是一个用Fortran语言编写的库,包含一些高阶矩阵操作,如求逆、SVD等。CLAPACK是C版本的LAPACK实现。
2.3.6 编译Kaldi代码
首先要配置编译环境,Kaldi使用configure命令来配置,关键配置如下:
如果编译目的是在服务器上搭建训练环境,则推荐使用如下编译方式:
如果只用CPU运算,则需在配置时加入如下选项:
如果为ARMv8交叉编译,则使用如下编译方式,前提是armv8-rpi3-linux-gnueabihf工具链是可用的,同时要求OpenFst和ATLAS使用armv8-rpi3-linux-gnueabihf工具链编译并安装到/opt/cross/armv8hf。
如果为ARM架构的Android编译,则需要加上--android-includes这个选项,因为Android NDK提供的工具链可能没有把C++的stdlib头文件加入交叉编译的路径中。
运行配置工具会在src文件夹下生成kaldi.mk文件,这个文件在编译过程中会被各个子目录的编译文件引用。通常可以直接进行编译,也可以做如下几项修改。
· Debug级别。默认的级别是“-O1”,为了便于调试可执行命令,可以加入“-O0-DKALDI_PARANOID”。如果为了优化运行速度,不做调试,则可以改用“-O2–DNDEBUG”或“-O3–DNDEBUG”。
· 浮点精度。如果怀疑代码中的某些取整操作影响了结果,则可以把“-DKALDI_DOUBLEPRECISION=0”改成“-DKALDI_DOUBLEPRECISION=1”。
· 如果想忽略OpenFst代码中的有符号/无符号检查造成的警告,则可以在CXXFLAGS中加入“-Wno-sign-compare”。
· 路径修改。如果想改变使用的矩阵库,则可以修改这个文件。但是通常建议直接使用配置工具生成新的kaldi.mk文件。
然后,就可以开始编译Kaldi代码了。一次完整的Kaldi编译可能需要几十分钟,可以使用多线程编译选项加速,例如:
如果对Kaldi代码做了修改,则可以使用如下选项来确定代码能够运行:
如果使用Git升级了Kaldi代码,再编译的时候出错,则通常有两种情况。第一种情况是,Kaldi依赖的第三方工具版本发生了改变,如OpenFst,这种情况需要重新安装OpenFst,然后重新运行配置工具。第二种情况是,Kaldi自身的库发生变化,比如增加或删除了一个库,或者原有库的接口更改了。这两种情况都会造成原来编译出来的库文件失效,需要清理旧的库文件重新编译,以确保编译通过:
Kaldi并没有提供类似make install的方式把所有的编译结果复制到同一个指定地点。编译结束之后,生成的可执行文件都存放在各自的代码目录下,如bin、featbin等,可以在环境变量PATH中增加这些目录的路径以方便调用Kaldi的工具。
2.3.7 配置并行环境
完成Kaldi代码编译后,就可以尝试在单机上运行训练示例了。单机版本的运行可以利用多进程完成并行运算。如果希望进一步利用多个Linux系统的机器并行运算以提高速度,则可以参照本节内容配置并行环境,建立一个Kaldi集群。
Kaldi的多机并行训练是基于数据并行的,如GMM训练的统计量计算、神经网络训练中一个小批次的参数更新等,即各个子任务的执行是互不依赖的。但是在某些时间点上,需要对子任务的输出进行汇总,因此需要保证在不同节点上执行各个子任务的进程能够访问同一个目录,并享有读写权限。所以,首要条件是建立网络文件系统(NFS)。如果本身有使用网络信息服务(NIS)管理的Linux机器,多个机器之间共享用户配置,则可以直接配置NFS;否则,需要首先确保同一个用户在不同的机器上使用相同的UID和GID。查询方法如下:
配置NFS的方法可以根据系统版本的不同在网上找到很多教程,本书不再赘述。完成NFS的配置之后,在要加入集群的机器上设置相互之间的免密码登录,并确认NFS的挂载点在所有机器上有相同的访问权限。这样,一个具有基本的任务分发功能的Kaldi集群就搭建完成了。用这个方法构建的集群无法根据计算资源进行任务分发,适合小型集群和少量用户的情形。
如果希望使用更多机器(如十台以上)组成更大的Kaldi集群,或者希望同时服务多个用户,实现任务排队、根据计算资源进行任务分发及一切高级的任务队列管理功能,就需要在NFS的基础上,使用高级的任务管理系统了。Kaldi支持的任务管理系统包括SGE(Sun Grid Engine)和SLURM(Simple Linux Utility for Resource Management)。用户可以在集群的任意一个节点上向任务管理系统提交任务,任务运行的结果也可以在任意一个节点上获取。JHU的CLSP计算中心有维护的比较好的SGE集群,所以Kaldi默认使用SGE,可以查阅Kaldi文档来了解如何配置以优化并行训练的性能。对于自己搭建集群的读者来说,推荐使用SLURM,相比SGE,这个工具维护的比较积极,有完整的文档和配置教程可以参考。