在《浅谈智能搜索和对话式OS》中,提到过,人机对话系统的常见场景有三种,分别为:闲聊型(Chatbot)、问答型(QA)、任务型(VPA)。本篇文章所关注的解析方式主要适用于QA系统中的封闭域问答,也即:将用户问句解析为库中存在的标准问句。
这里讲的七种方法均为我个人阅读文献后归纳整理而来,并不都是成熟稳定可以商业化的做法,目的只是提出思路以作参考。
0.基于规则的方法
基于规则的方法通常在缺乏训练数据的情况下采用,由于与后面的基于统计的方法区别较大,所以记为第零种方法。
基于规则的解析系统通常由两部分构成:一个是『规则库』,解析规则通常为 CFG 上下文无关文法;另一个是『同义词库』,记录了一些标准词的常见同义词。
整个解析就是一个上下文无关文法归约的过程。首先进行自动分词,接着将用户问句中的词依照『同义词库』归约为标准词,然后再将词归约后的问句与『规则库』中的解析规则比对,一旦比对成功,即该条用户问句被成功归约到该条解析规则所对应的标准问句上。
举个例子,同义词库中有这样两条记录:『失败:不上去、不进去、不成功、错误』『登录:登陆、登录』,规则库中有这样一条规则:『账号登录失败:[账号][登录][失败]』。
有一条用户问句是这样的『我账号怎么登陆不上去了』。首先假定分词正确,分词结果为『我|账号|怎么|登陆|不上去|了』;之后进行词归约,归约结果为『我账号怎么登录失败了』;接着与规则『账号登录失败:[账号][登录][失败]』比对,发现比对成功。该条用户问句被成功归约为标准问句『账号登录失败』,我们将系统中『账号登录失败』所对应的标准答案提供给用户,完成交互流程。
这样做在一定程度上能够解决问题,但缺点也特别严重。首先『规则库』与『同义词库』需要人工构建,这需要巨大且长期的人力资源投入。因为语言的表达方式理论上是无限的,而能想到的规则和同义词总是有限的;且随着语言的发展,或是业务的变动,整个规则库和同义词库的维护也需要持续的人力资源投入。
其次,编写规则库需要丰富的经验,对于人员素质的要求极高。因为解析规则的抽象程度相当高,在这样高的抽象程度上,即便编写者具有较丰富的经验(如果没经验会更糟),不同解析规则之间的冲突也是不可避免的,也即同一条用户问句会与多条标准问句的解析规则比对成功,这种情况下的标准问句选择/评分问题,又需要另一套系统来解决。
1.基于检索模型的方法
换个角度,我们可以将依照用户问句找到标准问句的过程看做是输入 Query 得到 Document 的搜索过程。
我们可以尝试采用传统搜索引擎中使用的检索模型来进行用户问句解析。《浅谈搜索引擎基础(上)》中提到,BM25 是目前效果最好的检索模型,我们就以 BM25 模型为例来分析。
BM25 模型的计算公式如下:
BM25 模型计算公式融合了 4 个考虑因素:IDF 因子、文档词频、文档长度因子和查询词频,并利用 3 个自由调节因子(k1、k2 和 b)对各种因子的权值进行调整组合。
其中,N 代表文档总数,n 代表出现对应单词的文档个数,f 指文档中出现对应单词的词频,qf 是查询语句中对应单词的词频,dl 是文档长度。
利用 BM25 模型可以有三种思路,分别把标准问句、标准问句及标准答案、历史中曾经正确匹配过该标准问句的用户问句集作为 Document,利用公式计算其与用户问句的相似度,然后利用相似度进行排序,取出评分最高的标准问句作为解析结果。
对于这个思路我没有做过实验,不过我推测,这种方法虽然节省了大量的人力,但在这种封闭域的 QA 系统中,其表现应当是不如上一种基于规则的方法,基于检索模型的方法在开放域中的表现会更好。
此外,基于传统检索模型的方法会存在一个固有缺陷,就是检索模型只能处理 Query 与 Document 有重合词的情况,传统检索模型无法处理词语的语义相关性。在上一种方法中,通过人工搭建的同义词库,一定程度上解决了语义相关性的问题。
2.基于检索模型+LDA/SMT的方法
上文提到,完全基于检索模型的方法无法处理词语的语义相关性。
为了在一定程度上解决这个问题,我们可以利用 LDA/SMT 等方法通过语料挖掘词之间的同义关系,为每个词自动构建一个同义度高于阈值且大小合适的同义词表。在代入检索模型公式进行计算的过程中,若文档中发现所查找关键词的同义词,可以依据同义程度乘以一定权重后纳入到关键词的词频计算之中。
《浅谈智能搜索和对话式OS》中有对 LDA/SMT 的介绍。
简单的说,LDA 可以合理的将单词归类到不同的隐含主题之中;并且通过计算两篇文章主题向量 θ 的 KL 散度(相对熵),可以得到两篇文章的相似性。SMT 模型出自微软之手,目的即是将翻译模型引入传统检索模型,提高检索模型对语义相关词对的处理能力,该模型也曾被百度采用过以提高搜索引擎返回结果的质量。
3.基于word embedding+DNN的方法
word embedding 将词表示为 Distributed Representation,也即低维向量空间中的一个词向量,Distributed Representation 下的词可以利用余弦距离来计算词之间语义的相关关系。与 one-hot Representation 相对应,one-hot Representation 下的词向量的维数与单词表的维数相同,不同词的词向量之间均正交。传统的词集模型(SOW)和词袋模型(BOW)采用的即是 one-hot Representation。
我们可以采用深度学习的方法来得到词 Distributed Representation 的词向量。比如训练一个普通的神经概率语言模型,就可以得到词的词向量,或者参考 word2vec 中的方式,训练 CBOW 或者 Skip-gram 模型。神经概率语言模型、CBOW 以及 Skip-gram 的介绍在《浅谈智能搜索和对话式OS》均有提及。
借助百度这张图来讲,利用 DNN 建模的思路如下:
我们需要使用一批用户问句-标准问句对的正例和反例作为训练语料,借助上面的方式,同时将正例和反例进行 word embedding 后送入 DNN 中,并采用 Pairwise ranking loss 的方式来建模正例和反例之间的语义差别。
4.基于word embedding+CNN的方法
上一种基于 DNN 的方法,在一定程度上已经可以解决词的语义相关性的问题,但对句子中的短距离依赖关系并没有做恰当的处理,比如无法区分『甲到乙』和『乙到甲』。
根据百度的评测结果,CNN 在处理短距离依赖关系上拥有更好的表现。
该图出自李航博士 Convolutional Neural Network Architectures for Matching Natural Language Sentences 中的 ARC-1:
其做法的基本思路是:将问句中的每个词,都做 word embedding,得到每个词所对应的固定长度的词向量,我们将问句表示成一个二维矩阵,每一行代表问句中相应词所对应的词向量。将这个二维矩阵进行多次卷积池化(卷积核的宽度与词向量维数相同,高度多为 2-5),最后得到一个一维特征向量,我们用 CNN 同时处理用户问句和标准问句,得到用户问句和库中标准问句所对应的特征向量。之后将这两个向量拼接起来送入多层感知机,由它来计算两个问句之间的匹配程度。
另外,有人指出,直接将两个特征向量拼接起来送入 MLP 会丢失边界信息,所以我们同时将特征向量 a、特征向量 b 和 aTb 同时送入 MLP 来计算相似度。
5.基于word embedding+CNN(ARC-2)的方法
ARC-2 结构同样出自李航博士的上述论文:
ARC-2 相较于 ARC-1 的改进在于,ARC-2 尝试让两个句子在得到像 ARC-1 结果那样的高层抽象表示之前就进行相互作用,不再先分别通过 CNN 结构得到各自高层抽象表示。
在 ARC-1 模型中,一张 feature map 仅仅是一个列向量,或者说是一个一维矩阵,若干个列向量并在一起形成了 ARC-1 示意图中的模样(二维),而在 ARC-2 中,一张 feature map 成为了一个二维矩阵,若干个二维矩阵叠在一起形成了 ARC-2 示意图中的模样(三维)。
再之后的卷积、池化过程就与 CV 中 CNN 的卷积、池化过程类似了。与上一种方法类似的,在进行 1D convolution 时,涉及到两个词向量的连接,同样可以采用之前提到的做法来避免边界信息的丢失。
6.基于LSTM+CNN(ARC-2)的方法
同样有人提出,在 ARC-2 结构中,直接采用传统的 word embedding 方法得到的词向量组成句子作为输入并不是最佳方案,最佳方案是采用已经过了 LSTM 的 hidden state。
我们可以采用 LSTM 结构训练一个 RNN 语言模型,如下图(以普通 RNN 为例):
从图中可以发现,当输出为『e』时,hidden layer 向量中第三分量最大,而输出为『l』时,第一分量最大,输出『o』时,第二分量最大。我们可以将 RNN 的 hidden state 当做 Distributed Representation 的词向量来使用,将其作为 CNN(ARC-2)的输入,经测试可以得到更好的结果。
番外
中文分词
一个可信度高的分词结果是进行后续解析步骤的基本前提。
在《浅谈自然语言处理基础(中)》中,我介绍了一些经典的分词方法,不过都是些较早的研究成果。CRF方法是目前公认的效果最好的分词算法。
CRF 方法的思想非常直接,就是将分词问题看作一个序列标注问题,为句子中的每个字标注词位:
- 词首,常用B表示
- 词中,常用M表示
- 词尾,常用E表示
- 单子词,常用S表示
CRF 分词的过程就是对词位标注后,将 B 和 E 之间的字,以及 S 单字构成分词。网上有很多公开的基于 CRF 的分词工具。
解析优化
至少存在四个角度可以在已有模型的基础上进一步提高解析质量,包括:问句归一化、用户状态、强化学习、多轮对话。
问句归一化
问句归一化的目的是对用户的输入具有较好的容错性。
简单的一些比如:简繁体归一化、全角半角归一化、标点符号处理和大小写归一化。复杂一些的比如汉语错别字的纠正。错别字自动纠正技术的应用非常广泛,而且在提高系统用户体验上能够发挥很大的作用,可以说性价比极高。
错别字纠正通常的做法是训练噪声信道模型。
用户状态
我们可以对用户状态提取特征,在训练和解析时将其作为附加信息一并作为神经网络的输入。
可以被考虑的用户状态至少包含:
- 用户的过往使用记录:比如账号注册时长、历史付费金额
- 用户的过往问答记录:用户过去询问过的问题和这次的问题可能会具有一定的相关性
- 用户的进入路径:可能隐含着用户问题的触发源页面
- 用户的当前问答记录:同一个 Session 中用户询问的问题通常具有一定的相关性
强化学习
其次可以采用强化学习的方法,通过设计合理的奖赏机制,让解析系统在与环境互动的过程中自主进行策略更新。
强化学习与普通的监督学习方法相比存在两个明显的优点:一个是强化学习策略更新所需要的数据主要来源于与环境的交互/采样,而不是昂贵的人工标记数据;另一个是强化学习所产生的策略是根据奖赏机制自主迭代更新的,会有一些创新的做法,而不仅仅是模仿人类提供的『标准』做法。
QA 问句解析中虽然不像游戏一样拥有『策略\创新玩法』这样的概念,但仍然可以在解析优化中帮助大量节省数据的人工标记开销。
应用强化学习方法的核心问题之一就是奖赏机制的设计,在 QA 的场景下设计奖赏机制,至少可以考虑以下几个角度:
- 退出 QA 页面时可以要求用户对本次 QA 做出反馈(已被蚂蚁金服小蚂答和京东智能客服采用),负面反馈可以被进一步区分为『解析错误』和『答案错误』,只有属于『解析错误』的负面反馈才被用于优化解析系统
- 系统是否连续多次提供给用户相同的回答(以系统回答而不是用户问句为标准)
- 用户是否最终选择接入人工(如果人工接入不是自动的)
- 通过文本情感分析识别用户的情绪变化
多轮对话
多轮对话技术可以进一步提高与用户对话的连贯性。
我倾向于将多轮对话划分为『封闭域』和『开放域』两个场景,不同场景的实现思路也应该不同。
封闭域场景多轮对话的特点是:系统能解决的问题是一个有限集,多轮对话的目的是将用户引导到我们可以解决的问题上。
而开放域场景多轮对话的特点是:系统需要解决的问题是一个无限集,多轮对话的目的是依照上下文更准确的理解用户的需求。
在这样的指导思想下,封闭域多轮对话的核心思路应该是『填槽』,而开放域多轮对话的核心思路是『上下文替换』和『主体补全』。
《浅谈智能搜索和对话式OS》中介绍了百度利用 slot filling 技术来做 NLU,并利用『上下文替换』和『主体补全』来提高其 DuerOS 的对话能力的。
而更进一步的,填槽、上下文替换和主体补全的技术基础都是『序列标注』,这里给出百度的两张 PPT:
根据百度的 PPT,采用双向 LSTM + CRF 做序列标注,是一个商业上可行的方法。
人工接入
选择合适的人工接入时机同样是提高 QA 系统整体表现的方法之一,其核心问题在于平衡用户体验与投入成本。人工接入的越早,用户体验越好,但成本也越高。
这里简单提供蚂蚁金服小蚂答的做法:若系统连续提供给用户三次相同的回答,显示人工接入按钮;若用户连续询问两次客服类问题(比如『我要人工』、『你们客服电话多少』),显示人工接入按钮。
答案优化
QA 系统的另一个重要组成部分是答案库。
答案录入
答案录入的优化至少可以从三个角度来思考:
- 答案形式的多样性
- 答案的个性化程度
- 答案对用户的帮助
答案形式的多样性非常容易理解,比如小蚂答就支持包括文本、链接、图片、视频在内的多种答案形式。
个性化问题在上文解析优化中已有涉及(考虑用户状态的解析优化),上文的分析思路同样可以应用于答案录入,我们可以对不同注册时长、付费金额不同、进入路径不同等等的用户提供不同的个性化答案。
答案对用户的帮助看起来比较抽象,但也很容易理解。通俗的,我个人以『地图级』、『导航级』、『专车级』来为 QA 系统的答案进行分级:
- 『地图级』答案告诉你在什么什么地方可以做什么什么事情,你自己去找,找到了再做。
- 『导航级』答案帮你跳转到完成任务所需的页面,不必找,直接做。
- 『专车级』答案直接为你解决问题,不必找,不必亲自做。
依照文章最初的人机对话系统场景分类,提供『专车级』答案的 QA 系统,可以被称为 VPA 了。
答案更新
对于答案库的优化,在答案完备录入(答案形式足够丰富、针对不同用户提供个性化的回答)的前提下,至少存在两个优化点:
- 发现答案库中标准答案的错误
- 发现答案库中缺失的标准答案
上文解析优化中强化学习方法奖赏机制的设计思路也可以被用来发现答案库中存在的问题,因为大多数时候我们还很难明确的区分用户的负面反馈是针对解析系统还是答案本身。
除了从用户负面反馈中发现问题,针对上面的两个优化点,我们还应该有一些预防机制来提前避免这些问题的发生。
比如第一点『答案库中标准答案存在错误』,如果不是录入人员的素质问题,最大的可能性就来源于答案的时效性,也即我们提供给了用户过期的答案。针对这个问题,我们可以在录入答案时特别添加『临时』标签,以标明该答案具有较强的时效性,需要及时更新。
而针对第二点『答案库中缺失某些问题的答案』,最大的可能性来源于突发事件以及业务的变动。比如系统服务宕机、系统上了新版本或者组织了一些运营活动,我们都应该针对这些可能引发用户疑惑的变动,提前准备一些 FAQ 并录入到答案库之中。
此外,当我们录入新问题及其标准答案的时候,需要注意新录入问题与原解析系统的适配性,以避免出现新录入的问题较难被解析系统解析到的情况。可采用的方法比如在录入新问题的同时,主动录入一些不同的问法作为初始训练语料(网易七鱼云客服的做法)。