我们利用HCompV工具初始化了一个全局的hmm模型,也熟悉了HTK的一些重要的数据结构。它的输出是更新后的proto和vFloors两个文件,供下一步使用。
在进入下一步之前,需要手工在hmm0目录下制作两个文件hmmdefs和macro,一个是为所有的既定hmm模型复制一个初始参数(除了sp),另一个macro宏文件。
下面列出hmmdefs头两个模型参数,其实都一样的。
~h "sil"
<BEGINHMM>
<NUMSTATES> 5
<STATE> 2
<MEAN> 39
-3.864637e-001 -1.276892e+000 6.429603e-001 -4.361009e+000 6.207581e-001 -6.569096e-001 2.480589e+000 -2.788665e+000 -1.313366e-001 6.740692e-001 -3.017518e+000 -1.560625e+000 5.566235e+001 1.460256e-003 4.730462e-004 -4.827005e-004 -7.249162e-004 -6.306474e-004 6.637267e-004 1.647110e-003 -2.088301e-003 9.362018e-005 -1.825078e-003 -1.855212e-003 -1.778467e-003 3.644651e-003 -1.163874e-004 1.333342e-004 -2.520498e-005 -1.577687e-005 1.496438e-004 -1.295793e-004 -2.109938e-004 5.133062e-004 3.661055e-004 6.873756e-005 1.892049e-004 1.713871e-004 -1.179971e-005
<VARIANCE> 39
4.492153e+001 2.800227e+001 4.004902e+001 7.262168e+001 3.713427e+001 5.923348e+001 3.089855e+001 3.635918e+001 4.011551e+001 3.448929e+001 3.661570e+001 3.404308e+001 7.104830e+001 1.414941e+000 1.002086e+000 1.289929e+000 1.967196e+000 1.588490e+000 1.981885e+000 1.694523e+000 2.165956e+000 1.937736e+000 1.799082e+000 1.821838e+000 1.620020e+000 1.004474e+000 1.865744e-001 1.427446e-001 1.801455e-001 2.748002e-001 2.518953e-001 3.164474e-001 3.122217e-001 3.736564e-001 3.291466e-001 3.174342e-001 3.133416e-001 2.797257e-001 1.262979e-001
<GCONST> 1.081255e+002
<STATE> 3
<MEAN> 39
-3.864637e-001 -1.276892e+000 6.429603e-001 -4.361009e+000 6.207581e-001 -6.569096e-001 2.480589e+000 -2.788665e+000 -1.313366e-001 6.740692e-001 -3.017518e+000 -1.560625e+000 5.566235e+001 1.460256e-003 4.730462e-004 -4.827005e-004 -7.249162e-004 -6.306474e-004 6.637267e-004 1.647110e-003 -2.088301e-003 9.362018e-005 -1.825078e-003 -1.855212e-003 -1.778467e-003 3.644651e-003 -1.163874e-004 1.333342e-004 -2.520498e-005 -1.577687e-005 1.496438e-004 -1.295793e-004 -2.109938e-004 5.133062e-004 3.661055e-004 6.873756e-005 1.892049e-004 1.713871e-004 -1.179971e-005
<VARIANCE> 39
4.492153e+001 2.800227e+001 4.004902e+001 7.262168e+001 3.713427e+001 5.923348e+001 3.089855e+001 3.635918e+001 4.011551e+001 3.448929e+001 3.661570e+001 3.404308e+001 7.104830e+001 1.414941e+000 1.002086e+000 1.289929e+000 1.967196e+000 1.588490e+000 1.981885e+000 1.694523e+000 2.165956e+000 1.937736e+000 1.799082e+000 1.821838e+000 1.620020e+000 1.004474e+000 1.865744e-001 1.427446e-001 1.801455e-001 2.748002e-001 2.518953e-001 3.164474e-001 3.122217e-001 3.736564e-001 3.291466e-001 3.174342e-001 3.133416e-001 2.797257e-001 1.262979e-001
<GCONST> 1.081255e+002
<STATE> 4
<MEAN> 39
-3.864637e-001 -1.276892e+000 6.429603e-001 -4.361009e+000 6.207581e-001 -6.569096e-001 2.480589e+000 -2.788665e+000 -1.313366e-001 6.740692e-001 -3.017518e+000 -1.560625e+000 5.566235e+001 1.460256e-003 4.730462e-004 -4.827005e-004 -7.249162e-004 -6.306474e-004 6.637267e-004 1.647110e-003 -2.088301e-003 9.362018e-005 -1.825078e-003 -1.855212e-003 -1.778467e-003 3.644651e-003 -1.163874e-004 1.333342e-004 -2.520498e-005 -1.577687e-005 1.496438e-004 -1.295793e-004 -2.109938e-004 5.133062e-004 3.661055e-004 6.873756e-005 1.892049e-004 1.713871e-004 -1.179971e-005
<VARIANCE> 39
4.492153e+001 2.800227e+001 4.004902e+001 7.262168e+001 3.713427e+001 5.923348e+001 3.089855e+001 3.635918e+001 4.011551e+001 3.448929e+001 3.661570e+001 3.404308e+001 7.104830e+001 1.414941e+000 1.002086e+000 1.289929e+000 1.967196e+000 1.588490e+000 1.981885e+000 1.694523e+000 2.165956e+000 1.937736e+000 1.799082e+000 1.821838e+000 1.620020e+000 1.004474e+000 1.865744e-001 1.427446e-001 1.801455e-001 2.748002e-001 2.518953e-001 3.164474e-001 3.122217e-001 3.736564e-001 3.291466e-001 3.174342e-001 3.133416e-001 2.797257e-001 1.262979e-001
<GCONST> 1.081255e+002
<TRANSP> 5
0.000000e+000 1.000000e+000 0.000000e+000 0.000000e+000 0.000000e+000
0.000000e+000 6.000000e-001 4.000000e-001 0.000000e+000 0.000000e+000
0.000000e+000 0.000000e+000 6.000000e-001 4.000000e-001 0.000000e+000
0.000000e+000 0.000000e+000 0.000000e+000 7.000000e-001 3.000000e-001
0.000000e+000 0.000000e+000 0.000000e+000 0.000000e+000 0.000000e+000
<ENDHMM>
~h "k"
<BEGINHMM>
<NUMSTATES> 5
<STATE> 2
<MEAN> 39
-3.864637e-001 -1.276892e+000 6.429603e-001 -4.361009e+000 6.207581e-001 -6.569096e-001 2.480589e+000 -2.788665e+000 -1.313366e-001 6.740692e-001 -3.017518e+000 -1.560625e+000 5.566235e+001 1.460256e-003 4.730462e-004 -4.827005e-004 -7.249162e-004 -6.306474e-004 6.637267e-004 1.647110e-003 -2.088301e-003 9.362018e-005 -1.825078e-003 -1.855212e-003 -1.778467e-003 3.644651e-003 -1.163874e-004 1.333342e-004 -2.520498e-005 -1.577687e-005 1.496438e-004 -1.295793e-004 -2.109938e-004 5.133062e-004 3.661055e-004 6.873756e-005 1.892049e-004 1.713871e-004 -1.179971e-005
<VARIANCE> 39
4.492153e+001 2.800227e+001 4.004902e+001 7.262168e+001 3.713427e+001 5.923348e+001 3.089855e+001 3.635918e+001 4.011551e+001 3.448929e+001 3.661570e+001 3.404308e+001 7.104830e+001 1.414941e+000 1.002086e+000 1.289929e+000 1.967196e+000 1.588490e+000 1.981885e+000 1.694523e+000 2.165956e+000 1.937736e+000 1.799082e+000 1.821838e+000 1.620020e+000 1.004474e+000 1.865744e-001 1.427446e-001 1.801455e-001 2.748002e-001 2.518953e-001 3.164474e-001 3.122217e-001 3.736564e-001 3.291466e-001 3.174342e-001 3.133416e-001 2.797257e-001 1.262979e-001
<GCONST> 1.081255e+002
<STATE> 3
<MEAN> 39
-3.864637e-001 -1.276892e+000 6.429603e-001 -4.361009e+000 6.207581e-001 -6.569096e-001 2.480589e+000 -2.788665e+000 -1.313366e-001 6.740692e-001 -3.017518e+000 -1.560625e+000 5.566235e+001 1.460256e-003 4.730462e-004 -4.827005e-004 -7.249162e-004 -6.306474e-004 6.637267e-004 1.647110e-003 -2.088301e-003 9.362018e-005 -1.825078e-003 -1.855212e-003 -1.778467e-003 3.644651e-003 -1.163874e-004 1.333342e-004 -2.520498e-005 -1.577687e-005 1.496438e-004 -1.295793e-004 -2.109938e-004 5.133062e-004 3.661055e-004 6.873756e-005 1.892049e-004 1.713871e-004 -1.179971e-005
<VARIANCE> 39
4.492153e+001 2.800227e+001 4.004902e+001 7.262168e+001 3.713427e+001 5.923348e+001 3.089855e+001 3.635918e+001 4.011551e+001 3.448929e+001 3.661570e+001 3.404308e+001 7.104830e+001 1.414941e+000 1.002086e+000 1.289929e+000 1.967196e+000 1.588490e+000 1.981885e+000 1.694523e+000 2.165956e+000 1.937736e+000 1.799082e+000 1.821838e+000 1.620020e+000 1.004474e+000 1.865744e-001 1.427446e-001 1.801455e-001 2.748002e-001 2.518953e-001 3.164474e-001 3.122217e-001 3.736564e-001 3.291466e-001 3.174342e-001 3.133416e-001 2.797257e-001 1.262979e-001
<GCONST> 1.081255e+002
<STATE> 4
<MEAN> 39
-3.864637e-001 -1.276892e+000 6.429603e-001 -4.361009e+000 6.207581e-001 -6.569096e-001 2.480589e+000 -2.788665e+000 -1.313366e-001 6.740692e-001 -3.017518e+000 -1.560625e+000 5.566235e+001 1.460256e-003 4.730462e-004 -4.827005e-004 -7.249162e-004 -6.306474e-004 6.637267e-004 1.647110e-003 -2.088301e-003 9.362018e-005 -1.825078e-003 -1.855212e-003 -1.778467e-003 3.644651e-003 -1.163874e-004 1.333342e-004 -2.520498e-005 -1.577687e-005 1.496438e-004 -1.295793e-004 -2.109938e-004 5.133062e-004 3.661055e-004 6.873756e-005 1.892049e-004 1.713871e-004 -1.179971e-005
<VARIANCE> 39
4.492153e+001 2.800227e+001 4.004902e+001 7.262168e+001 3.713427e+001 5.923348e+001 3.089855e+001 3.635918e+001 4.011551e+001 3.448929e+001 3.661570e+001 3.404308e+001 7.104830e+001 1.414941e+000 1.002086e+000 1.289929e+000 1.967196e+000 1.588490e+000 1.981885e+000 1.694523e+000 2.165956e+000 1.937736e+000 1.799082e+000 1.821838e+000 1.620020e+000 1.004474e+000 1.865744e-001 1.427446e-001 1.801455e-001 2.748002e-001 2.518953e-001 3.164474e-001 3.122217e-001 3.736564e-001 3.291466e-001 3.174342e-001 3.133416e-001 2.797257e-001 1.262979e-001
<GCONST> 1.081255e+002
<TRANSP> 5
0.000000e+000 1.000000e+000 0.000000e+000 0.000000e+000 0.000000e+000
0.000000e+000 6.000000e-001 4.000000e-001 0.000000e+000 0.000000e+000
0.000000e+000 0.000000e+000 6.000000e-001 4.000000e-001 0.000000e+000
0.000000e+000 0.000000e+000 0.000000e+000 7.000000e-001 3.000000e-001
0.000000e+000 0.000000e+000 0.000000e+000 0.000000e+000 0.000000e+000
<ENDHMM>
就这样粘贴复制,改一下~h 后面双引号里面的字符就是为每一个phone建立初始值。
macro的内容如下:
~o
<VECSIZE> 39<MFCC_0_D_A>
~v "varFloor1"
<Variance> 39
4.492153e-001 2.800227e-001 4.004902e-001 7.262168e-001 3.713427e-001 5.923348e-001 3.089855e-001 3.635918e-001 4.011551e-001 3.448929e-001 3.661570e-001 3.404307e-001 7.104830e-001 1.414941e-002 1.002086e-002 1.289929e-002 1.967196e-002 1.588490e-002 1.981885e-002 1.694523e-002 2.165956e-002 1.937735e-002 1.799082e-002 1.821838e-002 1.620020e-002 1.004474e-002 1.865744e-003 1.427446e-003 1.801455e-003 2.748002e-003 2.518953e-003 3.164474e-003 3.122217e-003 3.736564e-003 3.291466e-003 3.174342e-003 3.133416e-003 2.797257e-003 1.262979e-003
通过调用命令:
HERest -C config -I phones0.mlf -t 250.0 150.0 1000.0 -S train.scp
-H .\hmms\hmm0\macros -H .\hmms\hmm0\hmmdefs -M .\hmms\hmm1 monophones0
在hmm1目录下生成两个文件hmmdefs和macro,分别对应训练后的结果。
打开HTKTools里的HERest.c源码,文件的头部就有注释:HERest.c: Embedded B-W ReEstimation。顾名思义,就是利用Baum-Welch算法来估算hmm参数。为了能理解代码的逻辑,先来回顾下Baum-Welch算法。
对HMM模型而言,三大问题,评估、学习、预测,其中学习算法是比较复杂的。主要是因为,与观察向量一一对应的状态标签并不能获得,这部分属于隐藏量。因此,需要EM算法,而Baum-Welch算法是EM算法思想的一种实现。
EM算法,我个人是感觉理解比较困难,就是在直觉上,它有几道弯需要捋顺。否则看那么多公式、术语会一头雾水。
首选,已知观察向量O,估算,使得概率P(O|)最大,就是模型的参数。如果每个都有一个标签与之对应,那么就可以通过最大似然方法来估算参数就OK了。有些情况下观察向量并不是“完全数据”,其实质是,假设的模型相对于观察数据来说是过于复杂了。我们说还有隐藏的数据,起个名字叫“”,它嵌入在模型中,但无论是观察向量,还是标签数据都没法直接得到它的信息。
现在,我们用一个公式来描述关于这个隐藏参数的概率,。它表示,在已知当前模型参数和观察值的情况下,隐藏向量的概率。第二个关于隐藏向量的公式是,它表示已知模型参数和隐藏向量下,观察O的概率。现在它们的乘积就是,看形式是不是很熟悉?它就是的框架。
再往下走一步,这个隐藏向量是不是有很多情况下,离散形势下的多个值所以把公式改一下得到如果想办法改变的值,使得该公式的值最大,那么就起到了训练的效果了。
最后,还要对上面的公式进行修改。两个地方,一是前一个概率公式加log;二是前后两个概率公式的,其实应该有所区别。最后的公式应该是这样的。给这个公式起一个名字,在EM模型中的术语中就叫“Q函数”,变量是,其中和是已知的。现在就是要求这个“Q函数”最大值的解,其中是前一次值,因为有隐藏量,所以没法求的解析值,只能通过迭代的方式逐步获得一个极值,带来的副作用就是容易陷入局部最优。
到这里,对EM模型的理解大概就可以了。还是要回到Baum-Welch算法上来,我们说B-W算法是EM算法的具体实现,如何理解这句话呢?其实Baum-Welch算法的提出比EM算法还要早的。再次强调下,EM算法不是某一个具体的算法,它是一种思想,跟动态规划类似的。怎么具体通过EM方法来解决应用中遇到的问题呢?就是在理论上按照EM算法的指导,第一步构建刚才的Q函数,第二步求使得它最大的那个因变量的值。该值就是我们的模型参数了,这个过程就是“训练”或者叫“学习”。
Baum-Welch算法用到前向算法和后向算法,利用它们来实现参数的估计。那么自然的,就必须要详细的理解这两个算法是如何实现的,以及它们的物理意义。它们俩都是利用了前一步的计算结果来计算下一步,这是动态规划的本质。
前向算法:
设时间片 t = { 1、 2、 3、 ……T-1、 T }
状态 i = { 1、2、 3、 …… N-1、 N }
= { A, B, }
A是N*N的矩阵;B是N维的参数,表示在某i状态,发射观察向量的概率密度函数;是N维的向量,分别表示初始状态下i状态的概率。
前向算法是已知观察向量,我们记在t时刻i状态,前t个观察向量为()的概率为,那么当t = T时,i分别从1累加到N,就是的值了。
现在看如何累加计算这个 值。
当t = 1时, , i = 1, 2, ... , N 因此这个值是一个向量,维度是N,表示在第一个观察值时,初始状态下每种情况下发出的可能性;第二步,分别从这N个情况下出发,计算第二步状态为i,观察值为的概率,也是一个N为向量。试着借助第一步的计算结果,来演示计算第二步的值,往后推的时候看公式可能就比较容易理解了。
现在第一步得到一个向量值,引入变量j表示1~N,前面的向量某一个元素记为,表示转态j到i的转移概率,表示在状态i下观察向量为的概率。
,通过矩阵运行,利用改成第一步的向量点积相乘转移矩阵a的列,然后对应元素乘以混淆矩阵(向量)的元素。简单的手画了一个草图,以后有时间或者找到别人画的比较清晰的修改补上。
通过已知的模型参数和观察向量,能这样迭代的计算出某一个时间,在某一个状态下获得到目前为止观察值的概率大小,这是前向算法的核心目的。
后向算法与前向算法有很多类似的地方,都是通过一步一步迭代计算直至目标值。
,表示在t时刻i状态下,t+1,t+2,... ,T时刻观察向量分别的概率。
根据定义当t取值为T时没有意义,我们定义它们的值都为常数1。那么来推到下t = T - 1时,如何计算各个值,
,然后可以逐步往前推,当t = 1时,根据系统的初始概率计算得到的概率。