229
社区成员




WeNet更新支持了时间戳。解码器不仅可以返回 Nbest 解码结果,而且还可以返回其中每个字对应的时间信息。
在语音识别一些任务中,字级别的的时间戳和N-best 扮演着重要的作用。例如在视频应用中,语音识别结合字级别的时间戳可以在精确的时间显示字幕,在会议场景中,字级别的时间戳可以标定与会者在说某句话某个字的精确时间。N-best 则包含了更多的识别信息,并提升识别的下游任务,如纠错、NLP 等的准确性。
下面将详细介绍时间戳在WeNet 中的实现(时间戳和 N-best 仅在 runtime 中实现)。
CTC Prefix Beam Search
在介绍时间戳的实现之前,我们先来回顾一下CTC Prefix Beam Search 算法。
上图出自 Sequence ModelingWith CTC,相信大家都已经耳熟能详。神经网络输出一个T X M 的矩阵,其中T 表示音频的帧数 (10 帧); M 表示词典的大小 (5 个字母)。CTC Prefix Beam Search 算法则在该矩阵的基础上,找出概率最高的N 条路径。假设模型的输出如下图左上角的表格所示:
CTC Prefix Beam Search的过程,每个时刻有如下3个动作:
1. 扩展:根据前缀串和当前时刻的输出,计算新串的概率。
2. 规约:将规约串相同的候选概率相加。
3. 裁剪:仅保留top k个最好的序列做下一时刻的拓展,绿色的表示保留,红色的表示被裁减掉,图中k为3。
时间戳
每个前缀串可以由多个串规约而成。WeNet使用前缀串的被规约串中最优的一条路径,即viterbi路径来记录时间信息,viterbi路径中记录了每个字峰值的时间。如下图所示:
解码后一共得到三个解码结果:a, ab和ba。
1. 对于解码结果a来说,考虑到剪枝策略,因此规约前的串只可能是εaε、εaa或者aaa。
· viterbi分数较高的是aaa,为 0.4 X 0.35 X 0.50 = 0.07。
· a的峰值在T = 3,概率为0.50,即时间戳为T = [3]。
2. 对于解码结果ab来说,规约前的串可能是aab或者aεb。
3. viterbi分数较高的是aεb,为0.40 X .040 X .040 = 0.64 。a和b的时间戳为T = [1, 3]。
4. 对于解码结果ba来说,规约前的串可能是εba、bεa、baε、baa或者bba。
· viterbi分数较高的是bεa,为0.35 X 0.40 X 0.50 = 0.07 。b和a的时间戳为T = [1, 3]。
通常一个字的时间戳信息应该包括起始时间和终止时间,而使用上述算法,我们只能获取该字峰值所在的时间。因此在WeNet的实现中,考虑到延迟等因素,我们将峰值所在的时间当做该字的终止时间,上一个字峰值所在的时间当做起始时间。
示例
在启动客户端的时候,可以通过nbest参数来让服务器返回多个候选结果和对应的时间戳。程序的运行结果如下图所示:
代码实现
WeNet使用HashMap来保存解码过程中产生的前缀串及其对应的分数信息。分数信息的结构体定义如下所示:
主要代码的实现在 decoder/ctc_prefix_beam_search.cc 的Search函数中。代码通过for循环遍历每一个时刻,获取每一个时刻的输出,然后执行CTC Prefix Beam Search的过程。代码主要分为四部分:
1. 第一次剪枝
2. Token Passing
3. 第二次剪枝
4. 更新前缀串
第一次剪枝
在上面表格中,词典只包含3个字母['ε', 'a', 'b'],因此每一时刻的输出都包含3个字母。而我们的字典一共包含4233个汉字,需要通过剪枝来降低计算的开销。这里 opts_.first_beam_size 默认的取值为10,即只保留概率最高的前10个汉字的概率及其索引。
Token Passing
Token Passing部分的代码首先通过for循环遍历当前时刻的10个输出,然后对前缀串进行扩展和规约(代码如下):
第二次剪枝
第二次剪枝只保留分数最高的前N条路径(N-Best),便于后续的重打分。这里 opts_.second_beam_size默认的取值为10。
更新前缀串
将next_hyps中的新串更新到前缀串集合cur_hyps中,并且获取当前每个解码结果的分数等信息。
总结
上述内容就是CTC Prefix Beam Search算法和时间戳在WeNet中的实现,虽然CTC Prefix Beam Search的整个过程较为简单,但是需要在其中保留更多的路径信息,以获取每条规约后路径的时间戳。对这部分内容感兴趣的同学,可以参考WeNet中提供的单元测试进行调试与学习。
[0]. WeNet. https://github.com/mobvoi/wenet
[1]. Sequence Modeling With CTC. https://distill.pub/2017/ctc
[2]. CTC prefix beam search. https://robin1001.github.io/2020/12/11/ctc-search
[3]. CTC的Decode算法-Prefix Beam Search. http://placebokkk.github.io/asr/2020/02/01/asr-ctc-decoder.html