kaldi源代码简单说明
kaldi是开源的,基于C++的语音识别工具。一方面语音识别有较高的技术门槛,包含了很多方面的东西,另一方面kaldi集成了太多的东西,造成了其代码量很大,阅读起来很困难。
kaldi现在集成了很多的东西,造成其代码量很大,直接阅读起来感觉无从下手。但是,每个项目,一开始的时候,都是比较简单的,代码量也较小。
我从git上下载过来kaldi源码后,通过git reset 命令,回退到最原始的版本,看最原始版本的代码,就没有那么难了。最原始的版本,虽然缺失了很多功能,比如online解码、神经网络,kws等,但是其基本的代码还是有的。这里主要就是记录了阅读这些代码时总结的一些东西。当然,代码也只是走马观花地看了一遍,没有仔细看细节。
kaldi/base 文件夹 ==============================================
包含两个基本的头文件 kaldi-type.h kaldi-common.h
四个小模块 kaldi-error kaldi-math kaldi-utils io-funcs
kaldi-type.h 中定义了基本的unint32 int32等类型,以及BaseFloat
kaildi-error 中,定义了 KALDI_ERR KALDI_WARN KALDI_LOG 和 KALDI_EXIT 等。还是用的define,以及类中返回stream的方法。比起后面的版本,要简单很多
kalid-math 中,定义了基本的π,根号2等的值,定义一些最大最小值,定义随机数的实现,LogAdd LogSum等,公约数,因式分解等
kaldi-utils中,KALDI_SWAP4 KALDI_DISALLOW_COPY_AND_ASSIGN KALDI_ASSERT_IS_INTEGER_TYPE KALDI_STRTOLL 等
io-funcs中,定义基本输入输出,类模板定义方式 WriteBasicType ReadBasicType,可以是二进制或文本模式
四个小模块分别生成.o文件,然后生成kaildi-base.a。每个模块都有测试代码。
kaldi/matrix文件夹 ==============================================
生成的.o文件 kaldi-matrix.o kaldi-vector.o packed-matrix.o sp-matrix.o tp-matrix.o matrix-functions.o srfft.o
生成的.a文件 kaldi-matrix.a
kaldi-blas.h matrix-comm.h 两个基本的头文件;前者定义使用哪个blas,后者定义了基本的矩阵类型
packed-matrix 基本压缩矩阵,声明模板类PackedMatrix
tp-matrix 和 sp-matrix 三角矩阵和对称矩阵TpMatrix SpMatrix,其基类是PackedMatrix
kaldi-vector 和 kaldi-matrix kaldi中的向量和矩阵,声明模板类 VectorBase Vector SubVector MatrixBase SubMatrix Matrix
jama-eig jama-svd 特征分解和奇异值分解,只有使用atlas时才用到这两个文件,因为其他的库已经自带这两个算法了
matrix-functions 矩阵计算应用函数,如计算FFT; srfft 另一种高效的FFT计算方法
matrix-lib.h 包含了所有的应用头文件
Eigenvalue Decomposition 特征分解
Singular Value Decomposition 奇异值分解
symmetric matrices 对称矩阵
invert 求逆; singular matrix 奇异矩阵,行列式为0;非奇异矩阵才可以求逆矩阵
transpose 转置
kaldi/utils文件夹 ===============================================
【common-utils.h】包含此文件夹下所有的应用头文件
【timer.h】定义一个时间对象,可以计算当时与生成该对象时的时间差。
【edit-distance】计算编辑距离
【stl-utils】stl一部分STL算法函数总结,很多地方都会用到
【const-integer-set】快速判断一个整数是否在一个集合中
【hash-list】解码时用到的一个结构体/类
生成五个.o文件:text-utils.o kaldi-io.o kaldi-table.o parse-options.o simple-io.funcs.o 最后生成 kaldi-utils.a
1 text-utils 含一些基本的字符串处理函数,如SplitStringToVector SplitStringToIntegers ConvertStringToInteger
2 parse-options 处理参数的类ParseOptions。用到text-utils
3 kaldi-io 定义了 Output 和 Input 这两个类,用于输入输出。用到 text-utils/parse-optins/kaldi-pipebuf这些头文件
4 simple-io-funcs 对kaldi-io又进行了简单封装,定义成了4个IO函数。
5 kaldi-table 定义了一些table类,如 RandomAccessTableReader SequentialTableReader
【table-types】定义常用的tabel types。它依赖于 kaldi-table/kaldi-holder和matrix。需要认真搞懂的类。
kaldi中blas库的使用 ============================================
1、kaldi默认使用 atlas,但可以在 src目录下运行 configure 时指定用其他的blas库,如openblas,mkl等
2、用atlas时,configure代码会用多种方式检查系统中是否有atlas相关的动态/静态库了,如果有了,则只需atlas的头文件,就可以编译了。如果没有,则configure出错,需要先安装atlas
3、使用openblas,则需要先手动安装好openblas。如果程序已经是多线程的了,则不要在安装openblas时,指定USE_THREAD=1。
4、指定的blas库不同,生成的kaldi.mk文件不一样,这些不同会影响编译链接,影响src/matrix/kaldi-blas.h文件的define语句。
5、一般编解码用的代码,可以在configure中指定用静态库。
6、libquadmath.so 是高精度浮点数计算用的,GCC 4.6之后支持; libgfortran,一般编译blas库均用到
kaldi/itf文件夹 ================================================
1、clusterable-itf:聚类接口
2、context-dep-itf:联系tree和fst的接口,可以将一串上下文音素,映射为叶子ID。
3、decodable-itf:解码接口,包含特征提取和声学模型,可供解码对象用
4、optimizable-itf:好像是优化计算的接口,比如计算梯度。
kaldi/feat文件夹 ===============================================
1、feature-functions:定义了一些参数类(如MelBanksOptions)和常用函数(如Dither、ExtractWindow),是mel-computations和feature-mfcc的桥梁。
2、mel-computations:定义了计算mel系数(特征)的类,mel特征是计算 mfcc和plp特征的基础。
3、feature-mfcc、feature-plp:计算mfcc特征和plp特征的类。这些(包含mel)都用到矩阵,都依赖于matrix
4、wave-reader:读取wav文件的类。
feature-functions.o feature-mfcc.o feature-plp.o mel-computations.o wave-reader.o ----> kaldi-feature.a
kaldi/tree文件夹 ===============================================
1、clusterable-class、cluster-utils 聚类相关的类和算法。 build-tree时通过聚类生成问题集,然后构建树
2、event-map 定义的是EventType 和 EventMap (CE/SE/TE)这些类,树tree的主体,就是一个 EventMap 对象。
3、build-tree、build-tree-questions和build-tree-utils是跟构建树相关的类和函数,最终生成的是 EventMap 对象。
4、context-dep 从接口ContextDependencyInterface派生出类ContextDependency,这个就是“树”了。它的私有数据成员就是N、P和EventMap。它可以通过compute函数,来输入一个(三音素和pdfclass-id),输出其pdf-id。(这就和CLG的ilalel有点关系了)
kaldi/decoder文件夹 ============================================
1、decodable-am-diag-gmm:依赖于gmm/hmm/itf/transform等,从DecodableInterface中派生出DecodableAmDiagGmm、DecodableAmDiagGmmScaled等多个类
2、decodable-am-sgmm:依赖于sgmm/hmm/itf等,从DecodableInterface中派生出DecodableAmSgmm、DecodableAmSgmmScaled等类。
3、training-graph-compiler:依赖于hmm/fst/fstext等,定义类TrainingGraphCompiler。
4、kaldi-decoder:依赖于fst等。定义类模板template<class Decodable, class Fst> class KaldiDecoder。
前面三项会生成 .o 文件;然后一起(可能汇合第4个)构成 kaldi-decoder.a 文件
simple-decoder.h 和 faster-decoder.h 定义两个类,但貌似这些代码不参与 .a 文件的生成。
decodable-matrix.h 从DecodableInterface派生出DecodableMatrixScaled,其实就是在计算likelihood时乘以了scale。
kaldi/hmm文件夹 =============================================
1、hmm-topology:定义类HmmTopology。这个描述了音素的HMM结构。
2、transition-model:转移模型类TransitionModel。里面涉及了phone、HMM-state、pdf-id、transition-state、transition-index、transition-id这些概念。因为涉及了pdf-id,所以其依赖于ContextDependency(树tree)。
3、hmm-utils:跟转移模型相关的函数或类,比如,将TransitionModel转为Ha.fst的函数,增加自环的函数等。需要依赖fst。
4、tree-accu:只有一个函数,将状态的和加起来,用以训练树。
transition-model中的三元组,由“音素/状态/ PDF”构成。这些三元组,就是transition-state。每个state中有若干转移,就是transition-index。所有t-state的index集合起来,就是t-id。TransitionModel中有函数,进行这些id直接的转换。
kaldi/gmm文件夹 =============================================
按照文档说明,类DiagGmm是一个简单的对角协方差高斯混合模型。一个声学模型,就是由很多个DiagGmm构成的,比如AmDiagGmm。AmDiagGmm由pdf-id做索引,每一项都是一个DiagGmm。一个AmDiagGmm和一个TransitionModel结合起来,就是一个完整的模型(写入磁盘的,就是这两个的集合)。
DiagGmm和AmDiagGmm都是功能简单的类,它们没有例如模型估计、特征参数变换等功能。
FullGmm跟DiagGmm类似,但它是全协方差的GMM模型。它主要为训练UBMs做准备。
【model-comm.h】【diag-gmm.h】【am-diag-gmm.h】【estimate-diag-gmm/estimate-am-diag-gmm.h】
【full-gmm.h】【estimate-full-gmm.h】
kaldi/gmmbin文件夹 ===========================================
在前面feature、gmm、hmm、tree和decoder等的基础上,实现了一系列的命令行工具。如对于简单的gmm,就有如下一些:
gmm-init-mono mono训练的第一步,用以生成0.mdl和tree
gmm-est 模型参数重新估计和更新,输入old.mdl和acc文件,输出new.mdl。基本就是AmDiagGmm和TransitionModel根据数据,执行Update函数。
gmm-acc-stats-ali 根据对齐结果,计算数据,放入acc文件中。
gmm-decode-simple 使用SimpleDecoder做解码。就是AmDiagGmm和TransitionModel和特征,构成decodable,然后读取fst,执行Decode()。
gmm-decode-faster 使用FasterDecoder做解码。
gmm-align-compiled 根据模型、图和特征,做对齐操作。其实就是读取AmDiagGmm和TransitionModel,然后在图上加上转移概率,然后做FasterDecoder。
gmm-align 跟上面的gmm-align-compiled类似,只是这个输入没有图,只有L.fst和scp,需要自己编译图,然后做解码。
gmm-sum-accs 将多个acc文件合并为一个。
kaldi/lm文件夹 ===============================================
kaldi-lmtable和kaldi-lm 最终生成 kaldi-lm.a;它们的功能就是将arpa文件转为G.fst。
arpa2fst.cc 应用的就是上面两个文件/类。
kaldi/optimization文件夹 ===============================================
一些优化算法
kaldi/transform文件夹 ===============================================
一些特征变换的类或函数
kaldi/bin文件夹
一些常用工具,例如以下几个
cluster-phones 对音素聚类,生成问题集。输入是phone-set和tree-stats(acc-tree-stats的输出),输出是questions.txt。
compile-questions 对于cluster-phones生成的结果,进行问题去重,以及转换格式。
build-tree 根据问题集和状态,生成树。
compile-train-graphs 生成训练图
compute-wer 计算错误率
make-h-transducer 生成Ha.fst
总的来说, base、matrix和utils这三个文件夹中的代码是基础。这三个文件夹中的代码,所定义的函数和类,基本功能需要先弄清楚。
feat是特征提取相关的。gmm、hmm和tree是声学模型相关的。fst和decoder跟解码有关。
看代码的时候,还要结合kaldi官网的资料,和一些网上的中文资料,会更快速,更容易看懂函数的意图。
---------------------
作者:shzyiwai
来源:CSDN
原文:https://blog.csdn.net/u013677156/article/details/78060254
版权声明:本文为博主原创文章,转载请附上博文链接!