第2章
聊天机器人与自然语言理解
在编写机器人和创建自然语言模型之前,我们先回顾一下自然语言理解(NLU)和机器学习(ML)的基础知识。微软的语言理解智能服务(LUIS)实现了自然语言理解中的一些概念,另一些概念则可以使用Python/R等机器学习工具包,或利用其他服务(比如微软认知服务)实现。本章旨在为读者快速而简单地介绍与自然语言理解相关的基本概念,如果读者已经对相关知识十分熟悉,则可以跳过本章内容直接阅读第3章。我们希望通过本章的学习使读者对NLU的根源及其如何将NLU应用于机器人领域有基础的了解。最后,互联网上有很多对NLU更深入的学习材料,如果读者感兴趣可以阅读我们提供的参考资料。
如果我们决定开发一个集成了NLU的机器人,则在机器人的工程开发中必须保证理解用户语言的系统能做到与人进行持续的交互。以我们在第1章中介绍的用自然语言进行恒温控制的机器人为例,它有4个意图:开关打开、开关关闭、设置模式、设定温度。就设定温度这一意图而言,开发者如何编写能理解用户设定温度意图并且能识别用户语言输入中哪一部分代表温度的系统呢?
一种方法是进行暴力编码(brute-force coding),直接在程序里写死。典型地,我们可以使用正则表达式来对用户语句进行匹配,比如“set temperature to {temperature}”“set to {temperature}”以及“set {temperature}”。我们写完程序并用符合上面正则表达式的语句测试完之后,似乎万事大吉,但此时来了一个新用户,如果他对机器人说的语句是“I want it to be 80 degrees”,那么机器人会无法理解,也就无法与用户进行交互了。于是,我们又增加一条正则表达式“I want it to be {temperature}”。然而,如果又有新的用户对机器人说“lower temperature by 2 degrees”,这时候我们还可以再加两条正则表达式“lower temperature by {diff}”和“increase temperature by {diff}”。但是,用户的输入是多种多样的:lower和increase有很多同义词,温度单位也有摄氏度、华氏度,用户的输入语句可能是多条命令……那么我们怎么处理这么多的变化?
回顾刚才机器人中所支持的交互可以发现,简单粗暴的暴力编码开发方式非常容易产生极其复杂冗长的代码,并且考虑到用户使用自然语言表达的多样性,这个机器人在交互上也一定很差,一点儿都不优雅。如果开发者需要适度地引入这种简单粗暴的方法,那么使用正则表达式无疑是最适合的方式,我们将在第5章介绍Bot框架对正则表达式的支持;如果不采用正则表达式,则开发者应该确保设计的交互模型简单且易于维护。
自然语言理解(NLU)是自然语言处理(NLP)中机器阅读理解任务里的子任务。自然语言理解和自然语言处理密不可分,主要是因为我们会将机器人的智能程度与机器人的交互沟通能力联系起来:如果不管我们说的话多么复杂,机器人都能理解我们的说话内容,那我们自然会觉得机器人很智能。
我们在第1章提到的“命令行”的交互方式自然不属于智能的范畴,因为这种交互方式需要使用固定的输入格式。那么,通过理解用户的语音输入来运行某个Node.js脚本属于智能的范畴吗?通过NLU技术,我们可以构建对某一特定任务有理解能力的模型。这样从表面上看,机器人是具备一些智能的。事实上,我们的计算能力和技术都没有达到可以创建一个匹配人类智能的NLU系统。如果一个问题只有在计算机能像人类一样聪明的情况下才能被解决,那么这个问题就是“AI Hard”问题。我们目前还无法做到使NLU系统达到像人类一样理解自然语言,但我们可以做到创建一个简洁的NLU系统,它能很好地理解某一类事情,并创造出流畅的对话体验。
鉴于近来对机器学习和人工智能的过热追捧,在机器人开发的开始阶段设定正确的期望对我们而言尤为重要。在和客户讨论对话智能时,我也一直向他们强调现实和期望的智能化程度是有差距的。我们每个人只需要想出一种人类可以理解但机器人却无法理解的表达方式来描述某件事情,就可以轻易地击败机器人。开发机器人会存在这样的技术局限性,而且也受限于开发预算和开发周期。只要我们创建的机器人专注于某一类任务,方便了用户的生活,那么我们的开发思路就是正确的。
2.1 自然语言处理的基本概念
NLP领域的开端可以追溯到艾伦·图灵(Alan Turing)时期,特别是图灵测试—一种确定机器是否能被认为具有人类智能的测试。在图灵测试中,测试者向两个被测试者提出一系列问题,被测试者对问题进行回复,其中一个被测试者是人,另一个是计算机。对于两个被测试者的回答,如果测试者无法判断哪个是人哪个是计算机,那么该计算机就通过了图灵测试。尽管目前有一些系统声称能够通过图灵测试,但最终都被认为并不成熟。另外,还有些批评者认为,让机器人做到使人类相信它是人类和理解人类的语言输入是截然不同的两件事。我们要通过图灵测试可能还需要好几年。
自然语言处理领域最著名的成功案例之一是Eliza,Eliza在20世纪60年代中期由心理学家Joseph Weizenbaum开发,它是一个能模拟和人进行对话的聊天机器人,虽然简单但让人感觉很智能。Eliza由一个脚本驱动,该脚本根据输入的关键字为输入计算出一个得分,依据得分的输入匹配一个输出,Eliza的机制与后文Bot框架中的识别器不同。在网上我们能找到用JavaScript实现的Eliza,如图2-1所示。除了Eliza,技术人员还开发过很多相似的系统,也都取得了不同水平的成功。
NLU引擎通常是基于规则的,它们使用结构化的知识表示来进行编码,以便系统在处理用户输入时使用。大约在20世纪80年代,机器学习领域开始取得进展,机器学习比基于规则的方法更接近智能。比如,我们已经在前文探索过用简单粗暴的方式编写NLU引擎和根据多种多样的规则进行冗长烦琐的编码工作。使用机器学习的方法,NLU不需要提前了解所有意图的分类,而只需要在编写NLU引擎时为它提供一些标记了意图名字的样例输入。其中,这些样例称为训练数据集。基于样例输入和标记的意图可以训练出一个能从输入中识别所有意图的模型。训练结束之后,模型就能接收新的输入并为输出的每个意图打分。通常情况下,我们所使用的训练数据越多,模型的性能就越好。这就是机器学习的用武之地:先用高质量的数据来训练模型,然后通过使用该统计模型,系统可以开始对之前尚未遇到的输入进行标签预测。
由于训练数据是打了标签的,因此上述训练方法称为监督学习(supervised learning)。监督学习的表现可以很好地定量分析,因为我们知道真实的标签,并能够将它们与预测的标签进行比较,以获得定量值,这也称为交叉验证。分类和回归问题是两类最适合监督学习的任务,分类就是判断输入i是否属于类别C,典型的分类算法包括支持向量机和决策树。
图2-2展示了一些监督学习的场景。
回归和分类有些相似,但回归关注连续值的预测。比如,某一数据集中包含了纽约肯尼迪国际机场、旧金山国际机场、芝加哥奥黑尔国际机场的温度、湿度、云层覆盖、风速、雨量及当日取消的航班数量,那么可以用该数据集训练一个回归模型,并根据给定的纽约、旧金山、芝加哥的天气数据使用回归模型预测当日航班的取消数量。
除了监督学习,机器学习中还有其他的训练方式,比如无监督学习(unsupervised learning)。无监督学习没有对训练数据打标签,聚类任务是典型的无监督学习,如图2-3所示。
半监督学习(semisupervised learning)顾名思义就是用一部分打了标签的数据和一部分没有标签的数据来训练模型。强化学习(reinforcement learning)是典型的半监督学习,强化学习通过观察以及(基于观察)做出最大化奖励函数的决策来进行学习,如果所做的决策产生了奖励回报则模型被强化,否则模型被惩罚。关于机器学习的学习方法和内容,可以参考其他学习资料。
斯坦福大学计算机系网站上有一个关于深度强化学习的演示页面,如图2-4所示。在该演示中,智能体(agent)需要学习在空间中进行导航,学习过程中智能体从灰色苹果中得到奖励,从黑色苹果中得到惩罚。
需要强调的一点是,能集成自然语言处理和自然语言理解技术的一些广为所知的机器人应用程序在智能方面其实也很浅显。对于IBM Watson在益智问答电视节目《Jeopardy》上做了什么一直存在批评,比如Ray Kurzweil在《华尔街日报》评论称Watson其实并不知道它自己在《Jeopardy》上取得了胜利,理解和分类/抽取信息是两个不同的任务。Ray的评论的确客观,但精心构建的意图和实体模型在特定的狭窄场景中理解人类语言时被证明是非常有效的,机器人所做的正是这种特定场景下对自然语言的理解。
除了意图分类问题,自然语言处理领域关注的任务还包括语音标记、语义分析、机器翻译、命名实体识别、自动摘要、自然语言生成、情感分析等。我们将在第10章介绍多语言机器人及机器翻译。
20世纪80年代,人们对人工神经网络(ANN)的研究兴趣逐渐上升,在后续几十年里,对神经网络的进一步研究产生了很多重要的成果。对于人工神经网络中的神经元,最简单的理解方式是将其视为具有N个权重/输入和一个输出的简单函数。人工神经网络由许多互相连接的神经元组成,它接受一系列输入并产生一个输出,并且可以通过训练神经网络得到最终的权重,人工神经网络的结构如图2-5所示。另外,神经网络的类型有很多,学术界对它们进行了深入研究,比如深度学习的过程就是训练在输入层和输出层之间有许多隐藏层的深度神经网络。
谷歌翻译、AlphaGo以及微软语音识别都通过深度神经网络获得了很好的成果。深度学习的成功是对深度神经网络结构进行研究的结果,目前十分流行的深度神经网络包括卷积神经网络(Convolutional Neural Network,CNN)和循环神经网络(Recurrent Neural Network, RNN)。机器人应用程序中常常包括机器翻译、文本摘要和语言生成等自然语言任务,如果读者想深入了解人工神经网络如何应用于这些自然语言任务,链接中还有许多其他的资源供你学习和探索。
目前,当数据在不同层的神经元之间前向、反向传递时,各层神经网络做了什么?这个问题的答案现在尚不完全清晰,可以看到的例子是谷歌翻译会创建自然语言的中间表达;Facebook创建的AI可以与其他机器人或人类协商,导致AI能“撒谎”。这些事例已被吹捧成人工智能正在接管世界,实际上它们只是训练过程的副作用而已。将来,随着神经网络复杂性的提升,可能产生更多意想不到的行为,这些副作用可能会更诡异、更解释不清。
Microsoft Cognitive Toolkit和Google Tensor Flow等工具包的出现,使开发深度学习模型变得更加容易,同时使人工神经网络模型更加流行。
深度学习技术在自然语言处理领域取得了非常好的效果,尤其是语音识别和机器翻译。比如,微软研究院发布的语音识别系统“在识别对话上可以达到和专业速记员媲美的水
平”;谷歌通过高级深度学习算法将其翻译算法的译错率(在给定的两门语言之间)降低到55%~85%。然而,在意图分类等自然语言理解任务上,深度学习的表现却没有像其现在被炒作的那么好,这是因为深度学习只是机器学习工具包中的一个工具,并不是万能的“灵丹妙药”。
2.2 常见的自然语言处理任务
一般来说,NLP所处理的大部分问题都是NLU任务的一部分,与语言的句法、语义和语篇分析相关。不是NLP领域中的每个任务都与聊天机器人开发相关,其中一些任务是意图分类和实体抽取等高阶任务的基础。
2.2.1 句法分析
句法通常用于获取文本输入并对输入进行分解,与句法分析相关的任务一般比较基础,句法分析的结果不会被机器人直接使用。将语言输入分割成词素(morphemes)以及用某种语法建立表达语言的结构是两种典型的句法分析。另外,词性标注可以用于优化用户的查询。
2.2.2 语义分析
语义分析的任务是在自然语言输入中发现语言的含义。语义分析任务在聊天机器人中有很多具体的应用,包括:
- 命名实体抽取(named entity extraction):给定一段自然语言文本,从中找出相关实体,并标注出其类型(如位置、人),也就是将文本中的词语映射到实体命名和类型上。命名实体抽取是我们开发机器人时计划实现的功能之一。
- 情感分析(sentiment analysis):识别一段自然语言文本的内容整体是积极的、消极的还是中性的。情感分析可以用来识别用户对机器人回复内容的情感感受,重定向到人工回复,或者用于分析用户当前所处状态无法和机器人进行很好的交互。
- 主题分割(topic segmentation):给定一段自然语言文本,将其分解为与主题内容相关的片段,并提取片段的主题。
- 关系抽取(relationship extraction):抽取文本中对象之间的关系。
2.2.3 语篇分析
语篇分析是观察更大的自然语言结构并将它们理解为一个单元的过程。在语篇分析中,我们从文本主体的上下文内得出文本的具体含义。比如,对大量内容进行自动摘要,如公司财务报表。语篇分析在机器人中主要用于指代消解(也叫共指解析,co-conference),指代消解的目的在于自动识别表示同一个实体的名词短语或代词,并将它们归类。比如,在下面一段文本中,“I”指的是Szymon:
2.3 机器人中常见的自然语言理解功能
如果我们打算在机器人开发中运用自然语言理解,则在评估解决方案时需要考虑几个功能。NLU中最简单的基本功能是识别自定义意图和实体的能力,此外以下功能在选择NLU时是必须考虑的:
- 多语言支持(multilanguage support):开发者所集成的NLU系统能够支持多种语言。优化不同语言的经验很好地体现了开发团队对NLU的整体把握能力。
- 包含预建模型:许多系统中包含了与特定域相关的预建意图和实体,供开发者们在开发时使用。
- 预建实体(prebuilt entity):我们希望现有的NLU系统能够轻松地为我们提取许多类型的实体,如数字和日期/时间对象。
- 实体类型(entity type):NLU系统应该能区分不同类型的实体。
- 同义词(synonym):NLU系统应该能将同义词映射到相同的实体上。
- 通过主动学习持续训练模型:NLU系统应该能利用用户的输入作为训练数据,从而不断更新训练模型。
- 应用程序接口(API):虽然NLU系统中实现了一些用户界面供开发者训练模型使用,但同时也应该提供API来执行这些操作。
- 提供导出/导入功能:开发者的模型应该允许以(如JSON等的)开放文本格式被导入/导出。
使用现有NLU服务的替代方案是开发者自己进行开发,如果读者正在阅读本书,那么你可能没有足够的经验和知识来使自己开发的NLU有效工作,这是另外的话题了。一些易于使用的机器学习软件包(如scikit-learn)可能会给开发者留下一种印象—在机器人中加入NLU很容易,其实这需要经过大量的优化、调整和测试才能从通用NLU系统中获得可用的性能指标,这个过程需要花费大量的时间、精力和专业知识。如果开发者对这些技术原理感兴趣的话,网上有大量的材料可以自学。
2.4 云端自然语言理解系统
目前,科技巨头公司将机器学习部署在云上作为服务提供给用户,机器人所需的基本功能都可以通过部署在云端的机器学习服务获得。从实际角度来看,这样做有很多好处:开发人员不必关心为某一问题(比如分类)选择最佳算法,不需要扩展实现,同时云还为开发者提供了有效的用户界面和功能升级,并且优化也是无缝的。如果开发者要创建机器人并需要提供分类和实体抽取功能,则使用基于云的服务是最佳选择。在撰写本书时,以下是一些部署在云端的自然语言理解系统:
- 微软语言理解智能服务(LUIS):LUIS是一个纯语言理解系统,完全独立于对话引擎,它允许开发者自己添加意图和实体,自己选择适合的LUIS版本,在应用程序发布之前进行测试,最后发布到测试端点或生产端点。此外,LUIS还提供了主动学习的功能,保证模型可以不断被训练和更新。
- 谷歌Dialogflow(Api.ai):Dialogflow的前身是Api.ai,它允许开发人员在满足特定条件时创建NLU模型并定义转换流和调用Webhook或云功能。访问对话则是通过API或通过与许多消息通道集成来实现的。
- 亚马逊Lex:亚马逊的Alexa长期以来一直允许开发人员创建意图分类和实体抽取模型。随着Lex的推出,亚马逊为机器人开发中的NLU带来了更好的用户界面。在作者撰写本书时,Lex只有少数几个消息通道,并且同样可以通过API进行调用。和Dialogflow一样,Lex允许开发者使用API访问对话。
- IBM Watson Conversation:Watson Conversation允许开发人员定义意图、实体和云端的对话,对话同样可以通过API访问。在作者撰写本书时,Watson没有预定义的通道连接器,必须由机器人开发人员自己编写代理。
- Facebook Wit.ai:Wit.ai已经推出了很长一段时间,包含定义意图和实体的接口。自2017年7月以来,Wit.ai开始聚焦NLU并移除了机器人引擎部件。此外,Wit.ai与Facebook Messenger生态系统的集成非常紧密。
下一章我们会对NLU做深入探索,届时我们将使用LUIS进行介绍。作为一个纯粹的NLU系统,LUIS具有显著的优势,特别是在Bot框架集成方面。虽然目前NLU领域的基准测试不多,但LUIS是市场上表现最好的NLU系统之一。
2.5 自然语言理解系统的商业产品
一些较大的公司也推出了自己的自然语言理解产品,比如IPsoft的Amelia和Nuance的Nina。商业产品通常经过多年开发,非常先进,一些公司专注于IT或过程自动化,一些公司专注于企业内部使用案例,一些公司专注于特定的垂直行业,一些公司则完全专注于围绕特定用例的预建NLU模型。此外,在某些产品中,我们可能需要通过专有语言编写和实现机器人。
最后,企业所要做的决策是购买NLU服务还是自己构建NLU服务的两难选择。一些提供特定业务解决方案的公司在市场上已经存活了很久,但随着IBM、亚马逊、微软、谷歌和Facebook投入这一领域开发,财务支持较少的公司的发展可能会受阻。我认为会有更多提供特定业务解决方案的公司利用科技巨头提供的产品在专门的NLU和机器人解决方案方面进行创造和创新。
2.6 结束语
我们真正看到了人工智能在NLU领域的普及。多年前,机器人开发人员必须选择一个已经存在的NLU和一个机器学习库来创建一个像现在这样可以直接从云端获得服务并进行使用的系统。现在,创建一个集成了NLU、情感分析和指代消解的机器人非常容易。科技巨头正在挖掘这个空间,为他们的开发者提供工具,为他们自己的平台建立对话体验。
这对于开发者而言是利好消息,因为这意味着竞争将继续推动该领域的创新。随着该领域研究的进展,分类、实体抽取和主动学习的改进将提高NLU系统的性能,机器人开发人员亦可从中获益。