本文是用机器学习打造聊天机器人系列的第三篇,经过阅读本文你将对聊天机器人的实现有一个大体的思路。html
本项目基于chatterbot0.8.7来开发,但不只于此。让咱们先对chatterbot作一个简单的了解。python
ChatterBot是一个基于机器学习的口语式对话引擎,基于python编写,能够基于已有的会话集合返回匹配问题的响应。ChatterBot的非侵入式语言设计,使得咱们能够在其上训练任何语言的对话模型。程序员
首先,安装chatterbot0.8.7版本:算法
pip install ChatterBot==0.8.7
建立一个chat bot实例:sql
from chatterbot import ChatBot chatbot = ChatBot("Ron Obvious")
训练你的机器人:mongodb
from chatterbot.trainers import ListTrainer # 对话语料对,一问一答 conversation = [ "Hello", "Hi there!", "How are you doing?", "I'm doing great.", "That is good to hear", "Thank you.", "You're welcome."] trainer = ListTrainer(chatbot) trainer.train(conversation)
获取响应,"Thanks!"在上面的语料对中是没有的,可是其默认使用的Levenshtein distance算法能让引擎从问答对中选出一个相近的回答:数据库
response = chatbot.get_response("Thanks!") print(response) # 将输出You're welcome.
ok,若是你也已经获得了上面的正确输出,你可能想说,就这么简单?其实若是从简单体验一下的角度来讲,就是这么简单。可是若是你想作一个像那么回事的聊天机器人出来,那么还有一段路要走,好比Levenshtein distance算法其实过于简单了,会致使一些答非所问的状况,除此以外,还有一些其余咱们须要完善的地方,具体会在下一个话题中讨论。app
的确,这里面是有一些问题的:框架
没错,咱们要解决的主要问题就是上面列出的2个问题,归纳来讲就是2个方面,一个是性能,另外一个是智能。虽然问题只有2个,可是解决起来确是要花费一番功夫的。
首先,让咱们来分析一下性能的问题:
一、chatterbot默认采用sqlite数据库,sqlite是一个关系型数据库,很是轻量,无需配置和部署,可是当数据量比较大的时候,写性能相对mongodb等nosql数据库仍是有差距的,对于咱们的场景,因为不存在强事务要求,因此建议切换到mongodb数据库,你会发现训练速度会有较大的提高;
策略:chatterbot除了支持sqlite,还支持mongodb,因此能够经过修改配置的方式切换到mongodb数据库,示例以下:机器学习
chat = ChatBot( bot_name, database=bot_name, database_uri=current_app.config['DATABASE_URI'], storage_adapter="chatterbot.storage.MongoDatabaseAdapter")
二、chatterbot将全部问答对存储在一块儿,好比在mongodb中,是存储在一个集合里的,这样匹配问题的时候,就要和全部的问答对数据比较一遍,若是数据量很大的话,效率确定是很慢的;
策略:将问答对分类存储,好比在mongodb中,不一样类型的问答对存储在不一样的集合里,这一步称为意图分类,因此咱们须要经过另外的算法来肯定输入句子的意图类别,而后在指定类别下去判断句子和哪些问题更为近似,而后返回对应的回答。这样作的好处是方便维护,大致量的问答对被拆分到各个对应的类别下,分别匹配,体量天然会减小不少,而且某一类型的问答对的数据量增长,对其余类型问答对的响应速度没有直接的影响。
三、chatterbot区分问题和答案是根据句子是否出如今in_response_to属性下的text属性中来判断的,这致使须要先查询出in_response_to下的全部text,而后根据text再查出全部属于问题的句子,这样的查询效率是很低的;
策略:在准备问答对语料的时候,分别对问题和答案进行标识,好比用Q和A作前缀,这样存储到数据库中后,查询的时候就能够用Q来直接匹配出问题,而不须要屡次查询数据库。
四、chatterbot默认采用Levenshtein distance算法将当前输入的问题和数据库里每个问答记录进行比较,具体作法是先查出全部的问答句子,而后for循环进行一一比较,选择出最类似的句子作为响应返回,效率天然不会高。
策略:改成使用词向量进行比较,具体在下面的智能度策略中有介绍。
ok,咱们再来聊聊如何提高chatterbot的智能度:
一、采用余弦类似度算法代替Levenshtein distance算法
Levenshtein distance算法只是单纯的计算一个句子变成另外一个句子须要通过的最小的编辑步骤,并无考虑句子中词汇自己的含义,因此它并能识别出"苹果"比起"香水"来讲和"香蕉"在语义上靠的更近。而余弦类似度是指比较两个向量之间的余弦类似度,向量固然分别是输入句子的句向量和数据库中全部问题句子的句向量,而句子转为向量的方式是采用的word2vec,该方法在后续讲原理的部分会具体介绍,这里咱们只须要知道词向量模型能够将词转为对应的向量,这些向量在空间中呈现一种语义上的关系,好比用词向量表示咱们的词的时候,会发现 King的向量-Man的向量+Woman的向量=Queen的向量。
那么句子又是怎么转成向量的呢?这里咱们采用了平均向量的方法,就是先对句子分词,而后将词向量相加再除以向量的个数。至于为何余弦值能够表示两个向量的类似度,咱们一样也会在原理的部分进行介绍。
二、采用向量化并行计算策略代替for循环比对
有了句子的向量表示后,咱们就能够采用一些并行计算的方式来代替for循环,具体的操做是将全部数据放到一个矩阵中一块儿计算,CPU虽然远比不上GPU的并行计算速度,可是比起for循环的方式仍然能够带来几十到几百倍计算速度的提高。在此也体现了chatterbot的优秀设计,使得咱们能够在不更改源代码的状况下就替换掉原有的匹配算法,具体见代码篇的介绍。
到此,咱们解释了为何须要基于chatterbot再作一些事情,以及如何作,如今咱们来看看一个问题从输入到给出回复具体经历了哪些步骤:
用户提问后,由意图推测组件接收问题,组件内部进行特征提 取后,传给意图分类器去预测问题所属的类别(好比:这是一个关于 “电影演员”的问题,或关于“电影上映时间”的问题),接着问题会传递到语义 理解模块,并自动触发合适的语义理解实例去尝试匹配问题对应的 答案,这里说的语义理解就是在指定的意图分类下,去匹配具体的问题,好比“你以为功夫类电影谁演的好?”,或者“爱情片什么时间段上映比较合适?”等。整个过程主要是采用词向量模型构造问题句子的特征向量,经过贝叶斯算法进行意图分类,以及 采用余弦类似度算法计算问题和答案的匹配分数。此时引擎会根据 匹配分数结合阈值进行分析,从而决定是直接返回答案,仍是降级处理,因此有些场景下可能会返回多个候选答案,候选答案会根据分数降序排列。
前面说的都是如何根据输入的问题给与合适的回复,本篇主要讨论如何调教机器人说你想听的回复,具体流程以下:
用户提问后,若是系统没能给出满意的答案,用户能够经过新增问答对、修订答案 2 种方式来进行反馈,当系统给出多个候选答 案,可是正确答案没有排在首位时,用户能够经过标注最佳答案来 进行反馈。能够按期让问答引擎自主学习用户的反馈,从新训练意 图分类器并更新问答语料库,当用户本身或其余用户再次问到相同 含义的问题时便可获得相应的答案。
因为咱们能够本身调教机器人,因此你能够将其调教成仅属于你本身的独一无二的性格😏。
下一篇《用机器学习打造聊天机器人(四) 代码篇》将展现打造聊天机器人的相关代码实现及说明。
ok,本篇就这么多内容啦~,感谢阅读O(∩_∩)O。
本博客内容来自公众号“程序员一一涤生”,欢迎扫码关注 o(∩_∩)o