Statsbot 团队特别邀请了数据科学家 Dmitry Persiyanov,希望由他解释如何利用神经对话模式解决这一问题,并借助机器学习技术构建聊天机器人。
通过自然语言与机器交互属于通用型人工智能方案的基本要求之一。这一 AI 研究领域被称为对话系统、口语对话系统或者是聊天机器人。在这类场景下,机器需要能够结合对话背景为用户提供翔实的答案,而且在理想情况下应实现与人类无异的沟通效果。
但在实践当中,最后一项要求往往很难达成。不过幸运的是,只要机器人能够切实提供帮助并且具备一定幽默感,人类用户就完全能够接受这样的对话方式。目前的对话系统主要分为两大类:面向目标型(例如 Siri、Alexa 以及 Cortana 等等)以及通用对话型(微软 Tay 机器人)。前者负责通过自然语言帮助人类用户解决日常问题,而后者则负责与人类交流以应对更为广泛的话题。
在今天的文章当中,我将对基于深层神经网络的通用型对话系统进行比较式概述。具体来讲,我将对其主要架构类型以及改进方法作出说明,同时提供与之相关的论文、教程以及实现指南链接。
希望这篇文章能够成为各位有志利用机器学习技术创建自有聊天机器人方案的朋友们的理想切入点。如果大家认真通读本篇文章,相信能够对训练自有对话模型的相关任务胸有成竹——准备好了吗?我们马上进入正题。
首先,我会以递归神经网络(简称 RNN)与单词嵌入作为起点,这意味着大家必须了解二者的概念与工作原理,进而跟上文章的讨论思路。如果大家对它们还不太熟悉,我在文末附上了相关教程,各位请各取所需、不用客气~
通用型对话模型主要分为两大类——生成式模型与选择式(或者叫排名式)模型。另外,目前也存在不少混合式模型。但最为常见的解决思路在于,这些模型会根据对话语境构想几条回应语句,并预测与情境相符的潜在答案。通过下图,大家可以明确了解此类系统的工作原理。
在本篇文章中,当我提及“网络消费单词序列”或者“将单词传递至 RNN”时,我所指的是将单词嵌入传递至网络——而非对单词 ID 进行传递。
在深入探讨之前,我们首先需要聊聊对话数据集的表现形式。以下提到的全部模型皆进行配对训练(情境与回复)。其中的情景表现为回复之前的数个句子(也可能是单个句子)。该语句被视为从词汇中所获得的一条标记序列。
为了便于理解,下面来看表格内容。我们从两位对话者的交流内容中提取出三份样本:
嗨!
你好。
您多大年纪了?
22 岁。你呢?
我也是!巧了!
这里需要注意每句末的“eos
某些模型可能利用其它来自数据的元数据信息,例如对话者身份、性别以及情绪等。现在,我们开始讨论生成式模型。
在这里我们从最简单的对话模型起步,相关信息请参阅《神经对话模型》论文。
为了进行对话建模,该篇论文部署了一套序列到序列(简称 seq2seq)框架,其在神经机器翻译领域快速兴起并拥有相当出色的对话问题解决效果。这套架构包含两套配备有不同参数集的 RNN。我们将左侧的 RNN(对应 A-B-C 标记)称为“编码器”,而右侧的(对应
其中的编码器 RNN 一次构想一条情境标记序列,并对其隐藏状态进行更新。在完成对整体情境序列的处理之后,其会生成一项最终隐藏状态——此状态将包含情境意识并被用于生成答案。
解码器的目标在于从编码器处获取情境表达并借此生成答案。为了实现这一目标,编码器 RNN 当中需要维持一个处于词汇之上的 softmax 分类层。在每一时间步长当中,该层会获取解码器的隐藏状态,并立足其词汇表中的所有单词输出一条概率分布结果。
以下为回复内容的生成方式:
利用最终编码器隐藏状态(h_o)对解码器隐藏状态进行初始化。
将
从 softmax 层(使用 h_1)进行首词汇(w_1)取样(或者选取最大概率)。
将此单词作为输入内容进行传递,更新隐藏状态(由 h_1 至 h_2)并生成新单词(w_2)。
重复第 4 步,直到
解码器当中生成的回复,不过目前表达为公式而非单词形式。在这里,w_t 为时间步长 t 上的采样单词 ; theta 为解码器参数,phi 为密集层参数,g 代表密集层,p-hat 则为时间步长 t 条件下的词汇概率分布。
我们在生成回复时使用 argmax,其将在利用同一情景(其中 argmax 为恒定,但采样内容为随机)之下始终给出同样的答案。
以上描述的流程只是模型的推理部分,除此之外还有模型的训练部分,且后者的实现方式略有不同——在每个解码步骤当中,我们需要使用正确单词 y_t 而非生成的单词(w_t)作为输入内容。换句话来说,在训练过程中,解码器会消费正确的回复序列,但移除其中的最后一个标记并添加
解码器推理阶段示意图。上一时间步长的输出结果作为当前时间步长的输入内容。我们的目标是在每个时间步长中最大程度提升下一正确单词的概率。更简单地讲,我们要求该网络通过提供正确的前缀以预测序列中的下一单词。训练过程以最大可能性方式进行,而这会带来经典的交叉熵损失:
在这里,y_t 为时间步长 t 中的正确回复单词。
现在我们对序列到序列框架已经建立起基本认知。那么,我们该如何为此类模型添加更多生成能力?这里通常使用以下方法:
向编码器或 / 及解码器 RNN 中添加更多层。
使用双向编码器。考虑到正向生成结构,我们无法在解码器中实现这种双向特性。
尝试使用嵌入。大家可以对单词嵌入进行预初始化,或者配合模型本身从零开始学习单词嵌入。
使用更为先进的回复生成规程——beamsearch。其基本思路并非“主动”生成回复(例如利用 argmax 生成下一单词),而是考虑长单词链的可能性并从中作出选择。
实现编码器或 / 及解码器的卷积化。由于能够实现高效并行,卷积网络的速度往往远高于 RNN。
使用关注机制。关注概念最早出现在一系列神经机器翻译论文当中,且目前已经成为一种非常流行且强大的技术手段。
在每一时间步长当中将最终编码器状态传递至解码器。解码器只能查看一次编码器状态,随后可能将其遗忘。因此,最好的办法是将编码器状态连同单词嵌入一同传递至解码器处。
不同的编码器 / 解码器状态大小。我在之前提到的模型要求编码器与解码器拥有同样的状态大小(因为我们会利用编码器最终状态对解码器状态进行初始化)。大家可以添加一个映射(密集)层以将编码器的最终状态映射为初始解码器状态,从而回避这一要求。
使用字符——而非单词或字节对编码——来构建词汇表。字符级别的模型之所以值得肯定,是因为其词汇量较小因此运行速度更快,且能够理解词汇表中不存在的单词。字节对编码(简称 BPE)则兼有二者的优势。其基本思路在于立足单一序列找到使用频率最高的标记对,并将二者合并为同一标记。
下面,我将整理出各类高人气实现方案的相关链接,大家可以利用其训练自己的对话模型。不过需要强调的是,大家在使用生成式模型时有可能遇到几种常见问题。
泛型响应
通过最大可能性方式训练出的生成式模型往往倾向于作出最为泛用的回复预测内容,例如“好的”、“不”、“是的”以及“我不知道”等等。大家可以参阅以下资料了解如何解决这些问题:
在模型推理阶段变更目标函数 ;
在将 seq2seq 模型训练为强化学习代理时,如何引入人工指标并利用其充当奖励机制.
回复不一致 / 如何整合元数据
使用 seq2seq 模型时的另一大问题,在于其往往会在意义相同但表达不同的情境下给出不一致的回复内容:
目前最引人关注的处理方式在于“基于角色的神经对话模型”。作者为每段发言赋予对话者身份,并借此生成答案——其中不仅考虑到编码器状态,同时亦引入对话者嵌入因素。而对话者嵌入会在初始阶段即与模型本身一同进行学习。
通过这种方式,大家即可利用手头拥有的不同元数据对模型进行扩充。举例来说,如果您知晓对话的时态(过去 / 现在 / 将来),则可借此推理时间并使用正确的时态生成回复内容。另外,您亦可在拥有相关训练数据集的情况下,有效调整回复方的个性(性别、年龄、情绪等)或者回复属性(时态、情绪、问题 / 非问题等)。
在文章开头,我曾提到过要为大家提供与 seq2seq 模型实现方案相关的各类框架选项,下面马上开始。
TensorFlow
谷歌官方实现方案
两套实现方案,大家可以借此配合 PyTorch 进行尝试(PyTorch 属于翻译类 seq2seq 方案,但您也可以利用其代码进行对话建模)。
利用 seq2seq 进行翻译 (您也可以利用其代码处理对话数据)。
由 IBM 公司提供的实现方案。
Keras
高人气实现方案加出色 API。
论文与指南
一篇关于序列到序列聊天机器人的指南文章。
关注机制
Bahdanau 的关注实现方式。
Luong 的关注实现方式。
领先方案: 利用多标头关注 + 前馈网络处理机器翻译任务。
教程:RNN 中的关注机制。
字节对编码论文。
ConvS2S 论文。
说完了生成式模型,接下来我们开始讨论选择式神经对话模型的工作原理(此类模型通常被简称为 DSSM,即深度语义相似性模型)。不同于估算概率 p(回复|情景 ; w),选择式模型需要学习另一项类似函数——sim(回复、情景 ; w),其中的回复内容为来自一套预定义潜在答案池的元素之一(详见以下示意图)。总体来讲,该网络会将情景与一条候选答案作为输入内容,而后返回二者之间适用性的置信度结果。
选择式(或称为排名式,或 dssm)网络由两项“塔式”因素组成:其一为情景,其二为回复。每项塔式因素都可能拥有您所需要的架构。塔式因素提取输入内容并将其嵌入至语义向量空间(示意图中的 R 与 C 向量)内。接下来,其计算情景与回复向量间的相似性,即使用余弦相似度公式
C^T*R/(||C||*||R||)。在推理阶段,我们可以计算给定情景与全部可能答案之间的相似度,并从中选择相似度最高的答案。为了训练选择式模型,我们使用三元损失函数。三元损失函数通过三项因素定义,即情景、回复_正确、回复_错误(context、reply_correct、reply_wrong),即:
选择式模型中的三元损失函数。其与 SVM 当中的最大边界损失非常类似。那么 reply_wrong 是什么?其亦被称为“负”样本(reply_correct 相应被称为‘正’样本),且在最简单的情况下,其为答案池中的随机回复。因此,通过尽可能降低这一损失值,我们将能够对非正确绝对值进行排名的方式获得相似度函数。不过需要注意的是,在推理阶段,我们只需要比较所有回复的评分结果并选择评分最高的选项。大家可以点击此处通过微软项目页面深入了解 DSSM 的更多相关信息。选择式模型的开源实现方案不像生成式模型那么丰富,但大家仍然可以点击此处参阅在 TensorFlow 上实现选择式模型教程。
大家可能会问,我们为何要从数据集中提取随机样本?为什么不使用更为复杂的采样模式呢?问得好。如果进一步观察,大家就会意识到三元组的数量为 O(n3),因此最重要的是选择负属性,因为我们无法对全部数据集内容进行处理(毕竟属于大数据)。
举例来说,我们可以从池中提取 K 随机负回复,对其进行评分,而后将评分最高的选项作为负选项。这种模式被称为“难分样本”挖掘。如果大家希望了解更多细节信息,请点击此处参阅《深度嵌入学习中的采样机制》论文。
说到这里,我们已经了解了生成式模型与选择式模型的工作原理。不过哪种类型更适合您的实际需求?以下表格也许能够帮助大家作出正确的选择。
最重要的问题之一,在于如何评估神经对话模型。目前我们可以使用多种自动化指标以通过机器学习技术进行聊天机器人评估:
选择式模型的精度 / 记忆 / 准确度
生成式模型的困惑 / 损失值
机器翻译的 BLEU/METEOR 评分
不过最近的部分研究工作表明,上述指标与人类在特定情景下对回复内容的适当性判断并无关联。
举例来说,假设您面对的问题为“Statsbot 是否在阐述我们处理数据的方式?”而数据集内存在“当然是。”这条回复。但您的模型却在这样的情景下给出了其它回复内容,例如“绝对是的。”以上提到的各项指标都会给这样的答案打出很低的评分,但我们可以看到,这条答案跟数据集中的选项一样正确无误。
因此,目前最为适合的方法是利用目标指标对模型进行人工评估,而后再选择最理想的模型选项。没错,这看起来是种成本高昂的处理方式(您需要使用 Amazon Mechanical Turk 等服务进行模型评估),但就当下而言,我们还没有其它更好的解决办法。无论如何,整个研究业界也选择了这样的处理思路。
最后,我们已经准备好构建起最为强大且睿智的对话模型——即通用人工智能了,对吧?如果真是如此,那么像苹果、Amazon 以及谷歌这样的技术巨头为何坐拥成千上万研究人员,肯定已经将其部署在个人助理产品当中了。但尽管已经在这方面投入巨量资源,但神经对话系统仍没有做好立足开放领域与人类用户交谈,并为其提供丰富 / 有趣 / 实用答案的准备。不过在另一方面,神经对话系统已经在特定封闭领域(例如技术支持或者问答系统)带来部分成功案例。
递归神经网络
终极教程:内附大量示意图与代码片段。
最引人入胜的教程之一,包含设计实验以及良好的注解信息。
单词嵌入
文本分类器算法。
终极指南:图文详解嵌入机制。
TensorFlow 教程与代码示例。
乍一看来,对话模型似乎很难掌握——事实也确实如此。因此,我建议大家认真阅读本文中列出的各参考资料。另外,感兴趣的朋友还可以点击此处获取一套包含对话系统相关基础文献的资源池。
当做好实践准备之后,大家可以首先挑选一些简单的架构,同时配合流行数据集或者您自己熟悉的数据集(Twitter、Reddit 之类都可以),并借此进行对话模型训练。
原文链接:
https://blog.statsbot.co/chatbots-machine-learning-e83698b1a91e