这一章,我们来一起看一下语音助手的QU层中用到的query纠错和改写。
为什么要做纠错:
由于语音助手中绝大多数的query来源均为语音对话,ASR模块的结果就会由于误收音、少收音、或者识别的字错误导致输入给NLU层的query是错误的。错误的query会直接影响下游服务的识别,导致最终执行结果错误,影响用户体验。比如:
- (错误)打开和平静音 ->(正确) 打开和平精英。
- (错误)第一个7点的闹钟->(正确)定一个7点的闹钟。
- (错误)定一个7 点的孬种-> (正确)定一个7点的闹钟。
同时由于ASR本身是有语言模型对query进行平滑的,所以进入到NLU的是已经经过平滑的结果,所以对于NLU来做纠错,由于没有用户原始的语音信息,所以实现起来难度更大。同时,考虑到线上的实时性和稳定性,这个纠错对于性能的要求也很高。
解决方案:
query纠错的解决方案主要包含几个步骤:混淆挖掘、数据清洗、错误检测、候选召回、候选排序、后处理。 根据效果和实时性的要求不同,又可以分为在线端与离线端两部分。
下面对各个模块进行一个简单的说明。
1、混淆挖掘与数据清洗
这一步的目的主要为了建立混淆词、混淆句数据库,为后续的错误检测和候选召回提供数据库支撑。
为了能够尽量挖掘到可能存在的混淆词句,这里可以利用新词发现来做,挖掘内部凝聚度足够高同时左右邻字足够丰富的词,新词发现的方法这里就不展开讲了。除此之外,也可以进行混淆词句挖掘,利用近音相似、语义相似、拼音字符串的方法挖掘到混淆词。将挖掘到的新词+混淆词,通过各种方法进行清洗后,形成混淆词词典、拼音trie树等,作为基础数据库。
2、错误检测
这一步主要为了对输入的query进行错误检测,识别其是否可能存在错误,以及存在错误的位置。比较常用的方法就是:
- 使用混淆词典匹配,即将query分词后,在混淆词典中匹配是否命中混淆词。
- 使用语言模型ngram,即计算句子中的一个词和它的左右邻的共现概率,如果共现概率很低,则很可能这个词就是错误的,这里我们假设在全量句子的数据中,正确共现远比错误共现多,不然是检测不了的。
- 使用拼音CBOW,即加入拼音向量,将目标词的上下文的拼音向量,利用CBOW的方法预测目标词的拼音向量,然后将预测的向量与目标词的拼音向量做相似度匹配,相似度低的则可能存在错误。
- 使用Bert当做语言模型,直接预测句子中每个词的概率,不过这种方法效果不太可控,同时由于bert性能较慢,所以线上的实时方案中较少使用,可以在离线挖掘中使用。
3、候选召回
这一步主要是为了为错误词找到其原本对的词,比如“和平静音”中的“静音”,其正确词应该为“精英”。这一步主要利用各种方法找到错误词可能对应的正确词,以及这些正确词的概率,然后进行一个综合的排序。一些可用的特征和选择为:
- 混淆词典:即通过检测到的错误词,到混淆词词典中进行匹配,找到其对应的正确词。
- 语言模型:通过双向2gram,预测得到错误词位置对应的高概率的候选词。
- 拼音CBOW:即通过上下文拼音向量,利用CBOW的方式预测得到错误次位置的拼音向量,以及对应的候选词。
- DTW近音相似度:提到DTW之前,先可以了解下dimsim这个开源库,这个库可以用来衡量两个中文发音的相似度,主要利用声母韵母向量进行内积,但是DTW要求比较相似度的两个词长度必须是相同的,但是实际中可能存在多收音,少收音等情况,所以需要比较两个不同长度的拼音相似度,这里就用到了DTW方法,即Dynamic Time Warping,其主要思想为动态规划,将序列某个时刻的点跟另一时刻多个连续的点进行对应,这里不展开说明,可以google搜索一下。通过近音相似度匹配,可以在混淆词典中挖掘到更多的近音的混淆词。
- bert语言模型:即直接利用Bert预测错误词位置对应的正确词。
4、候选排序
这一步即将上面找到的潜在正确词,进行一个综合的排序。其可以利用的特征为:编辑距离、近音相似度、语言模型概率,黑白名单,PPL分数。
这里说一下PPL分数,perplexity(困惑度)是用来度量一个概率分布或概率模型预测样本的好坏程度,简单来说,就是衡量一句话到底是不是自然语言,分数越低越好。
将2.3中找到的候选词,利用2.4中找到每个候选词的各个维度的分数,然后利用梯度提升树GBDT做一个综合的排序,当然,也可以利用xgboost,其效果会更好一些,关于GBDT和xgboost的区别,后续会有文章将两者进行对比。
扩展思路:
上面的各个模块中,都有提到bert,其实可以直接利用bert,做一个端到端的翻译模型,将纠错的任务当做翻译的任务来做,输入为错误的query,输出为纠正后的query,不过这种方法效果不太可控,用于线上实时纠错风险较大,因为一旦这一步纠错出现错误,导致query更加难以理解,会对下游的任务带来蝴蝶效应式的错误。当然,如果其应用场景为类似搜索引擎上的,给出一个候选结果让用户去选,而不是直接拿去执行,这个也是个不错的选择。