赞
踩
19年参加PyCon大会的PPT~聊的主题是Python的智能问答之路,即怎么用Python快速搭建一套智能问答系统。这次讲解的内容从智能问答简介、QA快速实践、Python开发的利与弊、总结展望这4个方面围绕展开。
首先我们来简单了解一下智能问答。这张图来源于段楠2017年的一篇论文,清晰罗列出了现在业界对智能问答的分类,包括Community QA、KBQA、TableQA、PassageQA、VQA,KBQA是基于知识图谱的问答,所有的知识被组织成三元组的形式,比如<姚明、妻子、叶莉>这个三元组是知识图谱里的一条知识,当用户询问姚明的妻子是谁的时候,我们可以很快定位到答案是叶莉,再比如TableQA,知识是用表格的形式组织的,商家的产品信息用表格的形式存储,当用户询问关于某个产品的具体属性时,我们可以把用户的自然语言转化成SQL查询语句,直接从数据库里定位答案,上述2种问答所依赖的知识都是高度结构化的。而PassageQA就是阅读理解,它是基于文档的问答,我们的问答模型会基于用户的问题,将答案定位在文档的某个段落、或者某句话甚至是某个短语。VQA是基于图像或视频的问答,比如用户问这个女孩儿的脸被什么挡住了,问答模型会告诉我们答案是香蕉。问答的类型是比较多样的,基于不同的场景,解决问题的方式不一样,本文重点介绍的是Community QA。
那么什么是Community QA?
从命名上来看,它是基于社区知识的问答,比如一个读书论坛,底下有人在交流值得一读的人工智能书籍,那么这些对话内容都可以沉淀为知识,我们定义的Community QA就来源于这些场景,在不同的领域,我们通过挖掘、或者收集、标注的方式沉淀了一批知识,他们用问答对的形式组织,在这批知识集合下,用户提问一个领域相关的问题,问答模型会告诉我们答案到底是什么。
更进一步,我们把前面提到的知识进行结构化抽象,一个问答对表示一条领域知识,我们把它叫做一个知识点,同时由于一个语义的问题可能有多种不同的表述方式,因此一个知识点的问题由多个不同的表述组成,这些表述都叫相似问,而一个领域的知识库,就由多个知识点构成,以上是我们对Community QA的知识管理方式,现在有了领域内知识库,用户提问后,我们还需要一个问答模型,这个模型能找到和用户query最匹配的问题,进而给出对应的答案。右侧是一个简单的例子。我们为什么要用这种方式来管理知识,不用图表、也不用表格呢,实际上,知识的管理方式是来源于实际业务场景的,这种方式非常易于维护,多个同义问题用一个知识点管理,也能减轻维护答案工作量,同一知识点下的问题也将会是很好的训练数据。
Community QA的应用场景非常广,早在六年前风靡一时的语音助手开始,QA就开始逐渐应用在我们生活中的各个领域,特别是在客服、营销等领域,重复性对话发生的频率特别高的时候,以及现在市面上很多智能音箱,小爱、roobo、luka等等,都集成了QA的能力在里面。
既然QA这么受欢迎,那么我们应该怎么去快速搭建一套智能问答系统,构建一个问答机器人来帮我们自动回复用户呢?
下面我们对这个任务进行拆解,然后逐一解决。
聚焦智能问答,我们会从业务(解决什么问题)、数据(我们有什么数据来支撑我们完成现在这个任务)、怎么建模(输入输出是什么、工作流大概是什么样子)、用什么语言来开发、选择什么样的模型有更好的效果、评估方式和指标是什么、怎么快速迭代、如何把服务推上线这几个方面来进行拆解。
首先是业务,来看几个具体的例子。
在51talk等英语学习的app上,我们想给小孩报名英文课,但是不清楚课程内容和价格,那我们会问相关的问题,对于商家来讲,我们不仅是提问的人,还是潜在的商机,可能我们仅仅只想问一个问题,但是商家希望能获得我们更多的信息,电话、小孩年纪、上课意向等,进而让我们留存下来最后能成功消费,类似的场景还有很多,我们把这一类应用场景叫营销机器人,它是商务团队的好帮手,能在多个平台自由切换,回答问题标准而及时,最终往往能通过更小的人力投入,获取更多的有效线索。
另一类是更为常见的客服场景,询问产品、询问业务、询问经验,这类场景比较泛,他会衍生在生活中的各个方面,客服机器人相比传统的客服,他永不打烊,回答永远标准,而且面对各种刁钻甚至不友好的问题,都会永远积极正面地给出响应。
同时该类问答机器人进一步深化拓宽到领域,会衍生出某些领域通用的机器人,比如HR领域,相信不同公司的HR,很大程度上都会面临类似的问题,也就是说,垂直领域的问答机器人是可以有效渗透并横向复制给不同企业的。
经过上面具体的例子,我们对问答机器人有了更进一步的了解,需要做什么已经变得很清晰了,怎么做呢,我们应该选择什么语言来做最合适呢?
对比c++、python、java和go的不同特性,每个语言都有自己的优势和适合自己的场景,对于做一个问答机器人,我们选择什么语言开发最合适,需要考虑以下2个因素,首先,开发速度,我们希望能快速地完成整个系统的搭建,其次,我们一开始并不清楚什么方法最优,也就是说我们可能面临多次效果迭代,需要尝试多种模型,那么完备的机器学习工具包,会帮助我们少走很多弯路,所以综合上述考虑,我们最终选择了Python。
选好了工具,我们接下来开始建模,整个工作流分为2个环节,检索+匹配,首先我们基于python工具包ES将问答对入库,然后通过ES检索机制,返回打分较高的top200候选相似问,ES原生检索打分依赖的是命中词汇的频次特征、idf特征等,只是一种文本统计特征的粗筛,并不能保证最相关的排在最前面,所以接下来匹配环节,会计算用户问题和每个候选相似问的语义相似度,返回匹配程度最高的相似问对应的知识点作为对用户的响应,这里语义相关性计算采用的是wmd,最终我们对用户的输入,有了一套完整的问答系统,很显然,这个系统不够好,我们在匹配环节,只用到了wmd这一个模型来衡量问题和候选知识的相关性,wmd是一个通过计算2句话最小距离训练得到的模型,本身泛化能力就不够,而且受模型本身影响,对相似结构的文本语义区分性不够,所以第一次建模的效果达不到我们的上线标准,我们需要继续优化,但从这个建模过程来看,我们只需要借助es和wmd这2个包,基本就完成了我们要做的事情,开发效率非常快。
怎么提高候选相似问排序的准确率,成为我们优化的目标,既然一个wmd不够,那我们是否能抽象多维特征,并对多维特征进行建模,给出多个特征共同作用的排序结果,而我们实际上也是这么做的。
我们基于知识库内的相似问,利用多个模型去构建匹配特征,分了4次迭代,第一次迭代我们只引入了词袋模型,包括杰卡徳,最长公共子串、最小编辑距离、共现、互信息这5维特征,第二次迭代我们引入了词汇/句子的语义特征,包括wmd和w2v距离特征,上述特征都是和知识库无关的,第三次迭代我们引入了知识库信息,我们用fasttext基于知识库训练一个分类模型,然后在训练过程中fine-tune w2v训练得到的词向量,同时引入fasttext相关的label特征和cosine特征,第四次迭代我们引入深度学习训练了一个ESIM模型,并引入transformer新增了2维esim特征,每一次迭代都是我们进一步丰富句子语义表示的过程,这些特征都是经过实验最终筛选留存下来的,那么在这个过程中,python体现了他的什么作用呢?
同时前2次迭代我们没有用到知识库的信息,那我们的词袋模型,基于什么数据进行统计呢,w2v怎么训练得来呢,所以我们除了需要垂直领域的知识库数据外,还需要一些通用领域的数据,我们基于这些数据训练词向量,TM/MI词典,这4个迭代所需要的所有特征计算,python全部都支持的很好,数据抓取用requests,切词用jieba、训练w2v用gensim,以及fasttext、esim、LR等模型,拿制造汽车来类比,我们只需要在对的地方放上对的组件(比如车轮)即可,并不需要去过多关注轮子是怎么造的。python强大的开源工具库,特别是对机器学习算法的支持,帮助我们既快又好地完成了效果迭代。
效果变好了,有多好?肉眼可见显然不能作为一个反馈的指标,所以我们需要去科学地评估这些改进,最终我们选了6个不同领域,每个领域50个知识点,每个知识点12个相似问作训练,3个作评估测试,在此数据集基础上去评估准召和F1,具体数值见下表,可以看到在不卡阈值的情况下,准确率从0.8提升到了0.93。
迭代是一个循序渐进的过程,可能有人会说我怎么知道要用什么特征、选哪个模型呢,从多次迭代的经验来讲,badcase分析很重要,特征的设计一方面来源于你对问题的直观感知,我们需要从多方面来设计方法对句子进行表示,另一方面来源于对模型现有badcase的弥补,同时学术界也在不断更新新的模型,我们需要不断拥抱变化,3年前时兴的技术,到现在被完全替代的可能性是非常大的,一定要与时俱进,经验证bert+多任务学习可以使我们的最终效果提升到0.968。
好了,现在效果可以了,我们准备上线,左右两种架构,我们最终选择的是微服务架构2,左右主要区别在于把特征计算服务独立成子服务,因为特征计算属于计算密集型的,拆分开来既能降低资源占用,又能灵活扩容,还能见缝插针使资源利用最大化,可能有人会说服务太多部署麻烦,其实也不麻烦,所有服务docker化配置管理起来也很方便,最后服务的框架我们选择的是grpc,主要是因为长链接避免重复建立连接造成额外的资源开销,同时grpc长链接更安全。
上述所有内容就是怎么用python快速开发一套智能问答系统并上线的过程,下面我们再来看看python的利弊,优势我前面也提到过了,开发调试很方便迅速,以及强大的开源工具库,这里还要提到一点就是python是胶水语言,他能很方便地集成其它语言,这个功能是很有用的,能弥补python的不足。
那项目进行过程中python有哪些不足,我举了3个例子,1是内存占用过高,python的一切都是对象,一个int在python3里就要占28个字节,而且这里的28还不是全部内容,由右边对int的定义来看,python的int对象仅对应c结构的一个属性,整个int对象是包括各种附加字段,引用指针等内容的,而我们中途需要加载很多词典,比如idf词典、w2v词典、tm词典、互信息词典,一般1g的文件加载进来就5-6g,怎么办呢,这时候胶水语言起作用了,我们用c++封装kv存储,编译成so供python调用,1g的文件存储仅需要1-1.5g,而且c++的unordered_map比python dict的hash map理论上冲突会更少,查找会更快一些。
第二个例子是pb序列化慢,这个也是python胶水语言的一个特性展示,由于我们把服务抽象成了微服务,所以不可避免的需要在特征服务之间传输大量的文本、切词结果等用于计算特征,而10k的数据包单序列化就达到秒级,会导致服务完全不可用,不过好在python本身支持c++插件解析,内部pb解析采用c++机制实现,有效缩短了解析速度。
第三个例子是python的并发机制,总结一下就是因为有GIL锁,没法多线程,多进程会带来切换、调度代价导致cpu利用率不高,而协程往往只在I/O密集型操作中有用,正是因为python的这一特性,我们才需要把CPU密集型的并发任务独立成微服务,通过多线程/协程来调用。
整个智能问答系统搭建的过程中,有非常顺利的时候,也有非常苦恼的时候,但只要方向是对的,结局总不会太差,总结一下就是面对任务首先要理解问题的本质,对问题进行合理的建模,然后评估选择合适的语言工具,由浅入深稳步迭代,形成数据、模型、反馈的闭环,最后就是要持续性学习,拥抱变化,拥抱技术。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。