kali源代码简单说明

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官网的资料,和一些网上的中文资料,会更快速,更容易看懂函数的意图。


 

猜你喜欢

转载自blog.csdn.net/lbaihao/article/details/84853875