基于WFST的语音识别热词定制化

        最近学习了kaldi的"Support for grammars and graphs with on-the-fly parts",感觉看英文看着挺费劲,而且中间有许多概念需要有对应的图才能方便理解,所以撰写此文给有需要的同仁。

背景介绍

        语音识别实际应用中通常会遇到识别结果定制化问题,我们有时会称为“热词”问题。例如:想让语音识别引擎准确识别通讯录中的人名。这时采用语音识别定制化方案是一种比较好的选择。

        基于WFST的语音识别解码器的实现方式一般分为动态解码和静态解码两种。这里,kaldi的热词定制化采用的是动态解码和类语言模型(class based language)这两种技术的结合。由于本人主要关心L和G,所以只详细阅读了kaldi文中的L、G、以及LG三部分的内容。

        kaldi文中的大致思路:首先构建了top level的HCLG.fst(简记为top-HCLG.fst),这个HCLG跟传统的HCLG基本一样,只是中间的某些输入标签采用的是自定义的标签符号(例如:某些弧上的输入标签是#nonterm:contact_list,可以代表联系人这个类别);其次构建了sub level的HCLG.fst(简记为sub-HCLG.fst),这个HCLG就是上面top-HCLG.fst在自定义标签上的扩展(例如:扩展上面的#nonterm:contact_list为具体的人名,例如:小明、小李等)。这个图比较小,当有新的人名后,直接扩展后重新构造这个sub-HCLG.fst;最后解码器在解码时当在top-HCLG.fst中遇到了特殊的输入标签(例如这里的#nonterm:contact_list),这时解码器就知道需要动态加载对应的sub-HCLG.fst,进入到sub-HCLG.fst中解码对应内容。

名词解释

原文:Let us define the set of "left-context phones" as the set of phones that can end a word, plus the optional silence, plus the special symbol #nonterm_bos. 

翻译:kaldi文中定义了名词:"left-context phones"(这里翻译成"左上下文音素集"),它由三种集合构成:1)所有词的结尾phone构成的集合(例如:HELLO在发音词典中的发音为HH AH0 L OW1,则最后音素是OW1,OW1属于这个集合);2)静音符;3)特殊符号#nonterm_bos。(吐槽下:刚读这段英语时连断句都搞不太明白)。

主体内容

一、构造G.fst

1. 对于top level的G.fst:跟传统的G.fst一样,只是在所有定制化词的位置使用对应类符号进行替换。例如:这里的真实联系人位置使用#nonterm:contact_list进行了替换。这样解码器解码到该位置时,知道需要进入对应的non top-level的sub-G.fst。

2. 对于not top-level的G.fst:对于所有不是top-level的G.fst,需要开始于#nonterm_begin,结束于#nonterm_end,中间是枚举真正定制化的词。

二、构造L.fst

        L.fst由脚本utils/lang/make_lexicon_fst.py或者utils/lang/make_lexicon_fst_silprob.py进行实现,在prepare_lang.sh中被调用。当提供了参数–left-context-phones和–nonterminals时就会走定制化热词L.fst的构图流程,否则走普通L.fst的构图流程。

1. 传统的L.fst如下图所示:

2. 定制化热词的L.fst不仅需要包含传统L.fst,还需要包含一些特殊的弧。kaldi中的原文如下(看得是不是不知所云):

The lexicon needs to include, in addition to the normal things:

A sequence starting at the start state and ending at the loop-state, with olabel #nonterm_begin and ilabels consisting of, #nonterm_begin followed by all possible left-context phones (and #nonterm_bos) in parallel.

An arc from the loop-state to a final state, with ilabel and olabel equal to #nonterm_end.

For each user-defined nonterminal (e.g. #nonterm:foo) and for #nonterm_begin, a loop beginning and ending at the loop-state that starts with the user-defined nontermal, e.g. #nonterm:foo, on the ilabel and olabel, and then has all left-context-phones on the ilabel only.

        定制化热词的L.fst的如下图所示:

        还没有看懂没有关系,我详细介绍下。对比传统的L.fst定制化热词的L.fst不仅包含所有传统的L.fst需要包含的内容,还需要包含kaldi中的原文说明的其它三种弧:

具体解释如下:

1)以红色不规则形状框起来的部分对应普通L.fst,参看传统的L.fst的图;(注意:这个图的状态0到状态1对应1)的图中的状态0到状态1);

2)由红色横线标出的#nonterm_begin:#nonterm_begin对应规则1(包括后面由绿色正方形框出的部分)。即从开始节点到loop-state终止节点,先从开始节点0到中间节点3,输入标签是#nonterm_begin,输出标签是#nonterm_begin;然后从中间节点3到loop-state,输入标签是所有的left-context-phones(注意:真实的left-context-phones很多,所以这里会有很密集的弧,这里为了看起来方便left-context-phones只有三个)。(这段英文的原话翻译如下:输入标签序列由#nonterm_begin和所有的left-context-phones组成,输出标签序列只有#nonterm_begin。)

注:left-context-phones由三部分组成:1)the set of phones that can end a word(即使word结尾的phone,在kaldi中是以_E(表示END)和_S(表示Single)结尾的phone);2)optional silence;3)特殊符#nonterm_bos。这里就是data/lang_nosp_grammar1/phones/left_context_phones.txt.2里面的内容。

3)由蓝色横线标出的#nonterm_end:#nonterm_end对应规则2。即从循环状态1到终止状态4,输入标签为#nonterm_end,输出标签为#nonterm_end。

4)由黄色横线标出的#nonterm:contact_list:#nonterm:contact_list对应规则3。即对于用户自定义的nonterminal(这里的图中是#nonterm:contact_list),需要有从loop-state开始,到loop-state结束的路径。从loop-state出发的路径的输入标签是#nonterm:contact_list,输出标签是#nonterm:contact_list,然后回到loop-state的路径的输入标签是所有的left-context-phones。

注意:这个图L.fst画得不够好,中间的那个AH0_S:A/0.69315是一条正规的路径,不是一个自环。由于这个词A只有个一发音AH0_S,导致看着像自环。

三、构造LG.fst

1.top-level的LG.fst

2.non top-level的LG.fst

四、剩下HCLG.fst构图中的H和C的部分我不太关注,就没有仔细看,不再此详述。


五、后记

        如果采用CTC,并且使用拼音建模单元的话,只需要构图LG.fst,采用这种方式可以基于LG.fst,使用CTC进行定制化,具体的代码实现难度就比较大了。






参考文章:

1.https://kaldi-asr.org/doc/grammar.html

2.https://www.jianshu.com/p/389cb3c6231b

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,820评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,648评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,324评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,714评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,724评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,328评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,897评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,804评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,345评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,431评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,561评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,238评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,928评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,417评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,528评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,983评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,573评论 2 359