zoukankan      html  css  js  c++  java
  • AI大语音(十一)——WFST解码器(上)(深度解析)

     点击上方“AI大道理”,选择“置顶”公众号

    为了让识别出来的语音符合常规语言表达,引入了语言模型作为约束。

    为了加速解码识别效率又引入了WFST解码机制。

    解码本质:解码就是在网络中寻找最优路径。


    解码方式多种多样,各有优缺点。

    (注:on-the-fly Rescoring 归为动态解码有待商榷)

    1 基于Viterbi的原始动态解码
    无HCLG、一次解码

    基于Viterbi的动态解码是最基础的解码。

    线性词典:动态解码网络仅仅把词典编译为状态网络,构成搜索空间。编译的一般流程为:首先把词典中的所有单词并联构成并联网络;然后把单词替换为音素串;接着把每个音素根据上下文拆分为状态序列;最后把状态网络的首尾根据音素上下文一致的原则进行连接,构成回环。
    编译出来的网络一般称为线性词典(Linear Lexicon)。

    每个单词的状态序列保持严格独立,不同单词的状态之间没有节点共享,因此内存占用比较大,解码过程中的重复计算比较多。

    将上图状态拉成直线,做为Y轴,X轴为时间T。

    随着时间的推移,帧的移动,逐渐对齐到词的最后一个音素的最后一个状态,比如第7帧对齐到“北京”、“北极”、“南京”等词典中每个词的HMM的最后状态,对比累计概率,挑选出“北京”。继续进行下去,结合语言模型,加入语言模型概率,得到最优路径“北京是首都”,即解码结束。

    可见,从状态序列到词序列的整个转化过程十分复杂,且词汇量很大的话,计算量很大,解码效率不高。

    树型词典:一般把单词首尾发音相同的部分进行合并,称为树型词典(Tree Lexicon)。由于大量相同状态的节点被合并在一起,因此可以显著降低搜索空间的规模,减少解码过程的运算量。

    (该方法基本不用)



    2 基于WFST的Viterbi静态解码
    HCLG、一次解码

    为了加快解码速度,可以把动态知识源提取编译好,形成静态网络,在解码时直接调用。
    从输入HMM状态序列,直接得到词序列及其相关得分。

    用H、C、L、G分别表示上述HMM模型、三音子模型、字典和语言模型的WFST形式。

    一般网络构建的流程为:

    或者

    声学得分依然还要根据输入特征单独计算,其他知识源词典、语言模型、上下文依赖不需要再考虑,已经融入整个静态网络中,通过网络的转移弧输入、输出、权重来整体代替。

    由于静态网络已经把搜索空间全部展开,它只需要根据节点间的转移权重计算声学概率和累计概率即可,因此解码速度非常快。

    基于WFST的Viterbi静态解码过程:

    解码过程使用了令牌传播机制Token passing,其实就是viterbi解码的通用版本。

    1)解码第一帧时,从状态节点0出发,首先进行ProcessEmitting处理的发射状态转移弧,节点0转移到节点3、2、6。接着ProcessNonemitting沿着虚线非发射转移弧将6传播到同一时刻下的状态节点1。

    2)解码第二帧时首先切换Token列表,把cur_toks列表转变到pre_toks列表后,将cur_toks置空。然后再进行ProcessEmitting、ProcessNonemitting。

    3)随着时间的推移,帧的进行,到达最后一帧,选择最低累计代价的Token,然后以次Token回溯最优路径。

    其中:

    Emitting Arc 表示发射转移弧,类似HMM的发射状态,观察值产生声学得分

    aoustic_cost;

    Nonemitting Arc表示非发射转移弧,类似HMM的非发射状态,不产生观察值,没有声学得分;

    每条转移弧对应的权重为图代价graph_cost(语言模型得分、转移概率、发音词典)。

    Swap(prev_toks,cur_toks) :

    直到最后一帧,选择最低累计代价的Token,根据该Token回溯最优路径。

    3 基于WFST的Lattice静态解码
    HCLG、一次解码

    Viterbi解码识别只保留一条最优路径,若要保存多种候选识别结果,就需要Lattice。

    (灵魂的拷问:为什么要保存多种候选结果呢?viterbi识别出一条最优路径不够吗?

    AI大语音:不能保证viterbi给的最优路径就是真正的对的路径,错误的路径一样可能成为viterbi算法跑出来的最优路径)

    Lattice解码需要保存多条搜索路径,Token间需要有链表信息。

    前向链接ForwardList与转移弧不同,用来链接前后两帧之间的发射转移弧之间的Token,或同一时刻非发射转移弧之间的Token。

    令牌列表TokenList每帧一个,可以和帧索引建立关联。

    基于WFST的Lattice静态解码过程:

    问题与解决:

    在HCLG中,G的大小对最终的HCLG的大小起主要作用。

    静态图HCLG问题:

    1)静态图HCLG自身占用空间大,难以使用大的语言模型,其在解码运行过程中占用内存也大,难以在移动端直接使用HCLG。

    2)   静态图HCLG构建过程速度慢,消耗内存高。

    为了解决该问题,有两种方法:

    1)on-the-fly Composition;

    2)Rescoring(常规Rescoring、on-the-fly Rescoring)。

    4 on-the-fly Composition
    HCL/G、一次解码、动态解码

    on-the-fly Composition动态解码思路是把HCLG分开成HCL和G,称之为HCL/G。构图时分别构建HCL和G,分别构建的HCL和G。因为不是完全展开的图,这两个图的大小远比其展开的静态图HCLG小,这样就节省了空间。
    另一方面无需再进行HCL和G的Compose这一过程,而这一步恰恰是静态图HCLG构建过程中最为耗时的一步,所以又节省了构图时间。
    在解码时,分别加载HCL和G,然后根据解码动态的对HCL和G进行按需动态Compose,而无需完全Compose展开。

    动态图有什么问题呢?
    动态图HCL/G要在解码时动态的做Compose,也就加大了解码时的计算量,所以解码速度会相对降低。

    5 Rescoring
    HCLG1和G2、二次解码

    Rescoring,其思路是在构建时使用小的LM1构建G1,使用G1构建静态图HCLG1,然后使用小的LM1和大的LM2构建G2(G2中LM的weight为LM2的weight减去LM1的weight)。解码时根据HCLG1和G2的使用方式,又可以做进一步细分:

    1)常规Rescoring:利用HCLG1先全部解码,生成lattice或者nbest,然后在G2上做lattice和nbest的Rescoring。

    2)on-the-fly Rescoring:使用HCLG1做解码,在解码过程中,每当解码出word时,立即再加上G2中的LM weight,所以称之为on-the-fly Rescoring。Kaldi中的BigLM Decoder即为on-the-fly Rescoring。

    6 总结

    基于Voiterbi的原始动态解码词典一旦很大,计算量就会很大,解码速度很慢。

    为了加速解码速度,一方面可以进行剪枝处理,在解码中选出最优路径,超过剪枝阈值的路径则直接删除,不再后续运算。

    另一方面可以把知识源预先编译成一个静态网络,在解码中直接使用。其中一般基于WFST的Viterbi静态解码得到的一条最优路径可能并不是实际上真正的最优路径,为了得到更多的候选结果使用基于WFST的Lattice静态解码。

    静态解码HCLG占用空间大,难以使用大的语言模型,HCLG在构建过程中速度慢,消耗内存高。

    为了解决静态一次解码的问题,可以进行on-the-fly composition动态解码和rescoring解码。

    下期预告

    AI大语音(十二)——WFST解码器(下)(深度解析)

    往期精选

    AI大语音(十)——N-gram语言模型
    AI大语音(九)——基于GMM-HMM的连续语音识别系统
    AI大语音(八)——GMM-HMM声学模型
    AI大语音(七)——基于GMM的0-9语音识别系统
    AI大语音(六)——混合高斯模型(GMM)
    AI大语音(五)——隐马尔科夫模型(HMM)
    AI大语音(四)——MFCC特征提取
    AI大语音(三)——傅里叶变换家族
    AI大语音(二)——语音预处理
    AI大语音(一)——语音识别基础

    ——————

    浅谈则止,细致入微AI大道理

    扫描下方“AI大道理”,选择“关注”公众号

    —————————————————————

    ​     

    —————————————————————

    投稿吧   | 留言吧

     
  • 相关阅读:
    maven打包出错: Failed to clean project: Failed to delete
    Image.Save()发生“GDI+ 中发生一般性错误”
    Vue.js——60分钟快速入门
    PHP-输入变量
    ThinkPHP框架开发的应用的标准执行流程
    ThinkPHP 3.2.2 在 volist 多重循环嵌套中使用 if 判断标签
    ThinkPHP 数据库操作之数据表模型和基础模型 ( Model )
    Namespace declaration statement has to be the very first statement in the script
    ThinkPHP 学习笔记 ( 一 ) 项目部署:应用部署方式与模块分组部署方式
    ThinkPHP 3.2.3 简单后台模块开发(一)常用配置
  • 原文地址:https://www.cnblogs.com/AIBigTruth/p/13997452.html
Copyright © 2011-2022 走看看