构造好训练图接下来就可以进行训练了。
所谓训练就是在训练图上进行解码,获得最优路径的同时得到对齐序列,根据对齐序列进行统计信息量。
转移概率可以进行数数获得,GMM参数随着对齐的帧数变化而更新,同时GMM分量从一开始的单高斯split出更多的高斯。
如此不断迭代训练获得单音子模型。
4 强制对齐
3.3 align-equal-compiled
align-equal-compiled 和gmm-align-compiled功能比较类似。
align-equal-compiled 在训练前执行一次即可,
gmm-align-compiled 在训练时调用。
功能:
对每一句话,根据这句话的特征和这句话的fst,生成对应的对齐状态序列。
训练时需要将标注跟每一帧特征进行对齐,由于现在还没有可以用于对齐的模型,所以采用最简单的方法 -- 均匀对齐
输入:预编译训练图HCLG.fst、特征
输出:alignment,就是语音每帧对应的HMM state。
输入只有一个图,要得到alignment,需要对图进行viterbi 解码,找到最优路径。
gmm-align-compiled 在训练中执行,而训练中我们不断更新WFST中各个概率参数,使得解码更加准确。
源码解析:
过程之道:
结果:
得到alignment。
/kaldi-trunk/src/bin/copy-int-vector "ark:gunzip -c ali.1.gz|" ark,t:- | head -n 1
0_0_0_0_1_1_1_1为语音id。
后面每个数字都代表一个transition-id。
每个transition-id对应一个状态转移,并且可以映射到唯一的音素上。
每一个transition-id对应一帧,这就是所谓的对齐。
5 提取特征统计信息量
3.4 gmm-acc-stats-ali
功能:
(EM算法之E步)
对对齐后的数据进行训练,获得中间统计量,每个任务输出到一个acc文件。
acc中记录跟HMM 和GMM 训练相关的统计量。
HMM 相关的统计量:两个音素之间互联的边(Arc) 出现的次数。
GMM 相关的统计量:每个pdf-id 对应的特征累计值和特征平方累计值。
输入:模型model,特征,对齐序列alignment
输出:用于训练的统计量
源码解析:
过程之道:
- 根据对齐结果,用每一个转移的出现次数除以该状态的出现次数就得到了HMM的转移概率。
- 在单音素GMM训练中,每一个HMM状态有一个对应的GMM概率密度函数(pdf),所以有多少个HMM状态,就有多少个GMM,也就有多少组GMM参数。
- 对齐后找出某一个HMM状态对应的所有观测(比如状态8对应的o2, o3, o4,在kaldi中则是找到某一transition-id对应的所有观测),也就得到了该状态对应的GMM所对应的所有观测。
- 知道了该GMM对应的所有观测、该GMM的当前参数,就可以根据GMM参数更新公式更新GMM参数了。
结果:
根据对齐信息,计算每个高斯分布的均值和方差。
6 GMM模型迭代
3.5 gmm-est
功能:
(EM算法之M步)
根据上一次的模型,构建新模型 [[x+1].mdl。
输入:上一步训练后的模型、gmm-acc-stat-ali计算的统计量
输出:新模型
源码解析:
过程之道:
- 更新转移模型:根据gmm-acc-stats-ali统计的tid出现的次数,做一个除法就可以更新转移概率矩阵A。
- 更新GMM:gmm-acc-stats-ali已经得到了三个GMM参数更新公式的分子部分,方差累积量只需要减去更新后的均值的平方即可得到正确的方差更新公式。
分母做一个简单的除法就可以更新GMM的分量概率、均值、方差。 - 调用MleAmDiagGmmUpdate()更新GMM的参数,然后在该函数里调用MleDiaGmmUpdate()更新每一个GMM的参数
- 更新每一个分量的参数。
7 迭代训练
功能:
迭代训练:对齐、统计、更新模型
源码解析:
需要注意的是GMM模型一开始是单高斯的,随着模型的训练不断分裂出高斯来,最终达到设定的高斯数。
如何分裂的呢?
- 在分裂之前先获取了每个GMM需要增加到的目标gauus数,也就是target_components 。
- 获取当前GMM的高斯数current_components。
- 进行循环,在每次循环里,先得到所占权重weigh最大的高斯,然后将这个高斯的权重weight变为原来的一半。
- 增加新的高斯,新高斯的均值方差为之前加上一个随机扰动, 权重weight为原高斯的一半。
- 不断迭代直到 current_components == target_components,完成一轮训练,输出新的model。
模型结果:
8 总结
一个问题:
单音子模型的假设是一个音素的实际发音与其左右的音素无关。
这个假设与实际并不符合。
由于单音子模型过于简单,识别结果不能达到最好,因此需要继续优化升级。
就此引入多音子的模型。
最为熟悉的就是三音子模型,即上下文相关的声学模型。
不管模型好坏先进行解码试试效果。
解码之前先构建HCLG图。