目标
输入:语音的波形。
输出:语音对应的文字。
详述
我在思考一个问题,如何将语音转化为文字。我知道要使用HMM-GMM算法,虽然了解一些细枝末节的零散知识,但宏观上并没有形成整体概念。
我拆解语音和文字,并省略诸多的细节。语音部分,通过预处理,我可以得到特定的非常长的帧。文字部分,文字通过音节字典,我可以得到特定的音素序列。于是,转换的任务变成了,从帧转化为音素的序列。我可以给这个转换任务打一个分数:100分,80分,60分。但不论结果最后如何,我要有「分数」,才可以评价这个任务,完成的是否出色。
「HMM」和「GMM」就是这两个评价工具。
HMM 和 GMM
HMM 包含了隐藏状态转移,观测状态的输出。转移有一个转移概率,输出也有输出概率。在感冒的例子中,隐藏状态可能是感冒or健康,观测状态可能是正常or冷or热。这里的观测状态都是离散的,这意味着我可以用1,2,3为它们编号,但是有的观测是连续的,例如1.12,1.31之类的,没法离散化,于是这里就不得不用到了 GMM。
我在思考 GMM 的作用:只要给 GMM 一个值,也许是一个帧的信息,它就给我个具体类别的概率。比如,GMM(这个帧) = [0.5的状态a,0.2的状态b, ... ] 。我可以说,有了观测的状态,和已知参数的GMM,我就能够得到隐藏状态了。
我需要勾连隐藏状态和音素之间的关系。通过 HMM ,为特定的音素建立模型,倘若我将手头隐藏状态序列(通过GMM得到的),输入到这个模型里面,计算概率,岂不是就可以得到,观测序列(帧序列)所对应的音素了吗?例如我有/a/和/b/的 HMM 模型,还有一串 GMM 生成出来的隐藏状态序列,通过两个模型,得到两个数字,数字大,说明属于这个音素。
我假设,每个音素,都是由3个 HMM states 组成的 model,通过在这三个 states 之间跳跃,我可以获得无穷无尽的 obs 序列(或者是特定 hidden states 序列)。要强调的是,model 里面只有三个圈圈,和一堆弧线,它只是个模板,不是什么特定序列,也不是特定结果。model 中的每个弧线,每个直线,都会有一个数字,这写数字就是 model 的参数。
有这两个强大的工具,我似乎可以开始训练我的模型,最终完成识别的任务。
训练
首先,我有一个标准的训练数据,句子 “call nine one one”,对应的音素 “k ao l n ay n w ah n w ah n”,还有特定帧序列(obs 序列)。
有两种方式可以训练,一种是使用 Viterbi,一种是使用 Baum-Welch.
Viterbi 方法:
首先初始化对齐,平均分配帧给状态,可以得到初始GMM-HMM模型,利用初始模型和初始参数进行Viterbi解码,得到新的对齐。对齐后进行hard count。这里hard count 是HMM训练的E步,也是GMM训练的基础,GMM训练的数据就是count后得到的。
count后HMM可以进行M步得到转移概率,这就是模型中的A参数。GMM则在count基础上进行E步计算后验概率,再进行M步得到新的均值和方差参数,这是模型中的B参数。
Baum-Welch 方法:
首先初始化对齐,平均分配帧给状态,可以得到初始GMM-HMM模型(也可以任意初始化所有参数),利用初始模型和初始参数进行Baum-Welch算法。
Baum-Welch算法考虑所有的路径,对于某个状态,将所有时刻的状态占用概率相加,可以认为是一个软次数,即进行soft count,估计状态占用概率(期望),即EM算法的E步。
基于估计的状态占用概率,重新估计参数 λ (最大化),即EM算法的M步
新的大模型,我有隐藏状态之间的弧,也有某个状态对于所有帧的输出概率(只要把帧向量扔进它的GMM就可以得到),基于此,我手里握着模型,还有特定的观测 frames 序列,能重新获得新的状态序列。通过这个状态序列,可以更新 GMM,然后再更新转移概率,最终达到收敛。
识别
得到了 HMM-GMM,我想要识别,该怎么办?
刚才得到了每个音素的 HMM 模型,现在,将所有的 HMM 模型,整合到一个巨大的 HMM 模型中。现在,我输入一个全新的frames序列,扔进每个状态的 GMM 中,获得发射概率(同一个时间,有GMM数量个输出概率)。结合之前的转移概率,通过vertebi获得最大概率。