语音识别Viterbi解码

语音识别解码过程使用的是Viterbi算法,本质上是一种动态规划算法,能够得到全局最优解。为了进一步减少计算复杂度,引用了Beam Search 算法,可以在损失微小性能的条件下提高解码速度,Beam Search无法保证全局最优解。

Viterbi解码算法

Viterbi解码

如果从起点到终点有一条最终路径,那么这条路径子路径也是从起点到相应时刻点的最优路径。如上图,红线是一条从起点到终点的最优路径,那么从起点到时刻4的红线部分也是该时间段的最优路径。换句话说,任一时刻,只需记录到该时刻所有状态的最优路径即可,以时刻4为例,在时刻4,只需记录时刻4上经过三个状态S1,S2,S3的最优路径即可,也就是只需要记录三条路径,接着到时刻5,时刻5的S3状态有两条路径经过,取其中最优路径,时刻5的S2、S1状态类似,也就是说到了时刻5,仍然只需要记录三条路径即可
所以每一时刻需要做两次循环,外层循环现在时刻所有状态,内层循环现在时刻某一状态到下一时刻所有状态。时间复杂度,所有时间段时间复杂度。上图中,N=3,实际大规模语音识别中任一时刻的状态可能很大,比如5000个,这样即使使用了维特比,时间复杂度还是太大,实际中为了解决这个问题,引入了Beam Search算法

Beam Search 算法

Viterbi解码中涉及到现在时刻state数目以及下一时刻state数目,如果我们想要提高解码速度,需要对这两个数值都做缩减。
实际做法是设置阈值,减少语音识别中现在时刻以及下一时刻状态数目,具体做法是:

  1. 对所有状态排序,最优状态放最前面,最优状态得分=best_weight
  2. 设置一个beam,设置阈值1=cur_cutoff,cur_cutoff=best_weight+beam,所有得分在cur_cutoff以内的,保留,反之丢弃,现在时刻的state数目减少。
  3. 计算到下一时刻的最优路径得分new_weight。
  4. 设置一个adaptive_beam, 设置阈值2=next_cutoff,next_cutoff=new_weight+adaptive_beam,所有得分在next_cutoff以内的,保留,反之丢弃,下一时刻的state数目减少。

kaldi实际解码过程中,cur_cutoff、next_cutoff这两个阈值是计算出来,涉及到的传入参数包括:config_.beam,config_.beam_delta,config_.max_active,config_.min_active。之所以引入max_active,min_active是为了保证任意时刻的state数目在[min_active,max_active]之间,单纯的只用beam,有可能会导致某一时刻state数目过大或者过小。

具体Kaldi代码解析见Kaldi 解码代码解析

Reference

http://kaldi-asr.org/doc/index.html

注1: 安德鲁·维特比(Andrew J. Viterbi),CDMA之父,IEEE Fellow ,高通公司创始人之一,高通首席科学家。他开发了卷积码编码的最大似然算法

你可能感兴趣的:(语音识别Viterbi解码)