kaldi中的chain model详解
chain model的结构
chain model实际上是借鉴了CTC的思想,引入了blank用来吸收不确定的边界。但CTC只有一个blank,而chain model中每一个建模单元都有自己的blank。如下图所示:
对应kaldi中的结构定义为:
在kaldi中,把Sp和Sb看做同一个状态(都对应state 0),只是pdfclass不同。ForwardPdfClass表示Sp,SelfLoopPdfClass表示Sb。
kaldi中的chain model训练
chain model实际上也是一种序列鉴别性训练的方法,所以它也要构造分母fst和分子fst。
ps:这里不用分母词图(lattice)和分子词图(lattice)的表述,一、因为chain model(lattice free)不需要构建分母词图,而是用类似于HCLG这样的fst结构代替分母词图。二、同时chain model为了将每个句子分成一小块chunk,也会把分子lattice转换成分子fst(因为fst可以保留时间对齐信息,方便根据时间切分成块)
下面我们讲解chain model训练的关键步骤(为了系统性地说明,我们以aishell中的BAC009S0712W0300这个音频为例)
一、为每个句子构建训练图,然后解码得到每个句子的可能对齐结果(lattice)
这一步类似于构建解码用的HCLG,但解码用的HCLG是所有句子通用的。而我们这里构建的HCLG是根据每个句子的transcripts(转录文本)构建的,所以图会比较小,每个句子有自己的一个HCLG图。具体构建训练图的方法可参考:
有了训练图之后,我们就可以在上面解码,得到每个句子所有可能的对齐方式。kaldi中将所有可能的对齐用lattice这样的数据结构来保存,这样可以节省存储空间。得到的lattice(CompactLattice)的格式如下:
说明:
第一列和第二列是lattice结点的编号
第三列是word
接下来的两个数字(比如4.45809,3339.97)分别是语言模型概率和声学模型概率
接下来以”_“分隔的每个数字都是每一帧对应的transition-id。
为什么不是得到唯一的(最有可能的)对齐呢?kaldi文档中有解释:
Instead of enforcing a particular pronunciation of the training data, we use as our reference a lattice of alternative pronunciations of the training data, generated by a lattice-generating decoding procedure using an utterance-specific graph as the decoding graph. This generates all alignments of pronunciations that were within a beam of the best-scoring pronunciation.(也就是说考虑了多种发音组合的情况,比如上图的“规划”这个发音,他可以是“gui gui hua \<eps> \<eps>”或”gui gui gui hua \<eps>“等等)
这一步构建的训练图在后面分母fst的构建和分子fst的构建中都会用到。
二、分母fst的构建
1、构建phone级别的语言模型
构建语言模型必须要有语料,那么phone级别的语料从何而来呢?首先根据第一步的lattice(多种可能的对齐方式),我们进一步解码得到最有可能的对齐方式。kaldi中每个句子的最有可能的对齐方式写在ali文件中,格式如下:
BAC009S0712W0300 2 1 1 1 1 1 1 1 1 1 1 1 1 1 6290 6289 6289 6289 3856 3855 3855 3855 4830 4829 4829 4829 4829 2886 2885 2885 2614 2613 2613 2856 2855 2855 2855 2855 2855 2855 2855 2608 2607 2607 2607 2456 2455 2455 2548 2547 2547 2862 2861 2861 2861 5936 5935 5935 5935 5935 5935 2340 2339 2339 2339 2592 2591 2591 2591 2591 2810 2809 2809 2809 2809 2809 1922 1921 1921 1921 5294 5293 5293 5293 3478 3477 3477 3840 3839 1078 1077 1077 1280 1279 1764 1763 1763 1763 1763 5294 5293 5293 5293 1954 1953 1953 1953 5150 5149 5149 5149 5149 5149 5149 5149 5149 5149 2 1 1 1 1 1 1 1 1 1 1 1 1
说明:加粗的表示音频名字,音频名字后跟的数字表示每一帧对应的transition-id。
根据transition-id,我们可以得到每一帧对应的phone,如下:
BAC009S0712W0300 sil zh ong1 sh ix2 ii iu2 ii ie2 ii iu3 x iang1 ii ing4 g ui1 m o2 d e5 g ui1 h ua4 sil
2、构建分母fst
chain model的分母fst类似于解码时建立的HCLG图。但是chain model的语言模型是phone级别,所以构图时我们不需要发音词典了,其实构造的是HCP(P表示phone LM,HCP就是fst结构,所以叫分母fst)。为了限制HCP图的大小,我们使用4元phone LM。值得注意的是:不同的句子是共用同一个HCP图,这一点与传统的序列鉴别性训练不同,传统的序列鉴别性每个句子都有自己的分母lattice。
三、分子fst的构建
1、将第一步得到的以word为单位的lattice转换成以phone为单位的lattice。
chain model是在phone-level上进行训练的,所以需要得到以phone为单位的对齐,如下图所示:
2、构建分子fst:将phone-level的lattice转换成fst,同时将transiton-id转换成pdf-id
lattice与fst的不同是,根据fst中编码了time-alignment信息,可以方便我们根据时间点切分整段音频。为什么要将transiton-id转换成pdf-id?因为声学模型是对pdf-id建模。
说明:
第一列和第二列是fst结点的编号
第三列和第四列是pdf-id(输出和输出相同,实际上它是FSA)
同时,在这一步,我们还会以3倍的步幅跳帧进行采样(至于为什么可以跳帧,在最下面的“常见疑问”模块会有我自己的理解)。从这个图我们可以看到跳帧采样的现象,理论上音素sil对应41帧(通过上上张phone leveld的图中sil对应的transition-id数可以得到),但现在13帧(通过上张图,1和218(1和218都对应到音素sil)连续出现的次数可以得到)。或许看上张图,你还有疑问,为什么pdf-id 218之间还有pdf-id 253呢?这是因为原来的对齐结果不一定是准确的(基于CD-HMM-GMM),kaldi中提供了--left-tolerance和--right-tolerance两个选项,以phone为单位,允许phone在原来的对齐结果基础上,向前延伸--left-tolerance帧和向后延伸-right-tolerance帧(通常是5帧)。
到这一步,理论上每个句子的分子fst就构建完成了。
4、将每个句子的分子fst分成多个小chunk,用于训练
之所以将整个音频分成chunk,是为了加快训练速度和解码速度。因为fst中有时间对齐信息,所以我们很容易将整段fst分成一小块,如下图所示:
Chain model和传统的序列鉴别性训练(MMI/MPE/sMBR)的区别
基于CD-DNN-HMM的序列鉴别性训练,需要以下几步:
1. 训练一个基于CE(交叉熵)准则的CD-DNN-HMM模型作为种子模型,因为CD-DNN-HMM通常会优于CD-GMM-HMM。然后利用该种子模型,得到基于状态层面的强制对齐作为分子词图。
2. 基于一元语言模型构建一个HCLG,然后在HCLG上解码得到每个句子的分母词图。之所以采用一元的语言模型,应该是为了使词图不会太大。
chain model虽然也是一种序列鉴别性训练,但它的训练流程比较简单:
1. chain model不需要事先训练一个CE准则的DNN模型;而是直接使用CD-HMM-GMM模型得到每个句子的对齐结果,然后生成分子fst。
2. chain model不需要为每个句子构建分母fst,而是直接使用HCP图(P表示phone LM)。
同时,chain model是直接在phone级别上建模的。传统的序列鉴别性训练是在word-level上建模的。
chain model的优点:
1、解码速度更快。因为chain model采用拼帧降采样(每三帧取一帧)的方式,也就是说帧移变成了30ms,而不是10ms,所以帧率是传统神经网络声学模型的三分之一;
2、训练速度更快。不需要预先训练DNN模型,同时省去了分母lattice的生成。
chain model和CTC对比
这是Dan Povey在回答为什么将CTC脚本从kaldi中移除的原话:
Firstly, CTC was never in the master branch of Kaldi.
It's dropped permanently, **because the 'chain' models were always
better than CTC**. And I removed the branch because I don't want to
answer questions about it (and because it's a waste of their time
too). BTW, a presentation by Google here at Interspeech is saying something
similar, that a conventional model, discriminatively trained, with 1/3
the normal frame rate, beats CTC.
常见的疑问
1、为什么说chain model是lattice free?
答:之前的鉴别性训练是需要对每个音频解码得到分母词图(每个音频都有自己对应的词图)。而chain model的分母fst实际上是HCP(P表示发音词典的概率),也就是说所有音频共享同一个HCP图,不需要分别解码得到对应的lattice,所以叫lattice free。
2、为什么chain model可以采用跳帧降采样的方式训练和解码,而传统的HMM-GMM不行?
答:主要跟建模粒度有关。chain model中的每个phone只有一个state(不考虑blank),所以我们可以认为它的建模单元是phone。而传统的HMM-GMM的每个phone有3或5个state,所以传统的HMM-GMM实际上是对state建模。因为state的建模粒度比较小,采用跳帧的方式时,可能跳过了中间重要的几个state,从而影响识别结果。而phone的建模粒度较大,采用跳帧的方式通常不会跳过phone。
3、实际处理时(如kaldi),为什么要将句子分成多个小块(chunk)?
答:对于非循环模型和非chain模型的情况,分成chunk主要是考虑到我们训练时是利用上下文信息的,比如考虑了前10帧和后10帧,那么每个训练的example需要存储21帧特征,8个example需要存储168帧。如果我们将连续8帧做成一个chunk,那么我们只需要存储28帧(10+8+10),节省了存储空间。
- 点赞
- 收藏
- 关注作者
评论(0)