基于知识库的自动问答:seq2seq模型实践


向AI转型的程序员都关注了这个号👇👇👇python

机器学习AI算法工程   公众号:datayx程序员



问题描述

基于知识图谱的自动问答(Question Answering over Knowledge Base, 即 KBQA)问题的大概形式是,预先给定一个知识库(好比Freebase),知识库中包含着大量的先验知识数据,而后利用这些知识资源自动回答天然语言形态的问题(好比“肉夹馍是江苏的美食吗”,“虵今年多大了”等人民群众喜闻乐见的问题)。web


什么是知识库面试

知识库(Knowledge Base),或者叫的比较烂俗点,知识图谱(Knowledge Graph),是以知识为主要单位,实体为主要载体,包含着现实生活中人们对万千事物的认知与各种事实的庞大数据库。通常来讲,知识(或者事实)主要以三元组形式呈现:<头实体,关系,尾实体>,其中实体即人、地点、或特定概念等万物。举例来讲,<虵,改变了,中国> 就是一条简单的三元组示例,其中头尾皆为知识库中固有的实体单元。算法


方法框架数据库

先放个图flask



对着图说:假设要回答“Where was Leslie Cheung born”这个问题,主要分四步:微信

  1. 实体识别(Named Entity Recognition),即把问题中的主要实体的名字从问题中抽出来,这样才知道应该去知识库中搜取哪一个实体的信息来解决问题,即图中把“Leslie Cheung”这我的名抽出来;网络


  2. 实体连接(Entity Linking),把抽取出来的实体名和知识库中具体的实体对应起来,作这一步是由于,因为同名实体的存在,名字不是实体的惟一标识,实体独一无二的编号(id)才是,找到了实体名没卵用,必需要对应到知识库中具体的实体id,才能在知识库中把具体实体找到,获取相关信息。即图中将“Leslie Cheung”映射到“m.sdjk1s”这个 id 上(Freebase 的实体 id 是这个格式的)。这一步会存在一些问题,好比直接搜“姓名”叫“Leslie Cheung”的实体是搜不到的,由于“Leslie Cheung”实际上是某个实体的“外文名”,他的“姓名”叫“张国荣”,以及有时候还会有多个叫“Leslie Cheung”的人。具体解决方式后面再说。app


  3. 关系预测(Relation Prediction),根据原问句中除去实体名之外的其余词语预测出应该从知识库中哪一个关系去解答这个问题,是整个问题中最主要的一步。即图中从“Where was <e> born”预测出“people.person.place_of_birth”(Freebase 的关系名格式,翻译过来就是“出生地”)这个关系应该链接着问题的主要实体“Leslie Cheung”与这个问题的答案。


  4. 找到了实体与关系,直接在知识库中把对应的三元组检索出来,即 “<m.sdjk1s,
    people.person.place_of_birth, m.s1kjds>”,那么这条三元组的尾实体,即“m.s1kjds”就是问题的答案,查询其名字,就是“Hong Kong”。

数据集与工具

源代码与数据下载:

其中 data/origin 目录下是问答数据集的原始数据,鉴于实体识别与连接作起来比较麻烦,因此直接给出中间数据,data/seq2seq 目录下是已经通过前两步,能够直接用于训练 seq2seq 模型的数据。


本文项目代码 方式:

关注微信公众号 datayx  而后回复  问答  便可获取。

AI项目体验地址 https://loveai.tech


数据集:

SimpleQuestions & WebQuestions 学术界问答领域比较喜闻乐见的两个数据集了,至关权威,固然都是英文,别问为何不是中文
另外,知识库用的是  Freebase ,业界最权威的知识库之一了,固然也是英文的,别问为何不是中文

工具:

Pytorch

依照惯例,仍是先上结论

  • 从 tensorflow 转过来发现,pytorch 真好用

  • 问答问题目前的解决方法,框架基本都是上面说那四步,可是具体作法五花八门,模型各式各样,文中所用的 seq2seq 也只是一个简单实践,效果上比较以下图(out-of-state now 是业界目前最好结果,APVA-TURBO 是我最近在作的一篇论文)


简单的 seq2seq 效果还不错,虽然跟学术界目前最好成绩有很大差距,可是还不错。后来我又加入了一些好比 KB embedding,turbo training 等一言难尽的补丁上去,变成如今的 APVA-TURBO 模型,在 WebQuestions 上已经快领先 8 个点了,可是文章里不提了,太乱了,直接发一个论文连接,感兴趣的能够深刻研究


The APVA-TURBO Approach To Question Answering in Knowledge Base. Yue Wang, Richong Zhang, Cheng Xu and Yongyi Mao. Published 2018 in COLING


https://www.aclweb.org/anthology/C18-1170/


下面正式开编,详细讲一下用 seq2seq 模型作问答问题的过程以及 pytorch 的实现,我的浅见


1 数据处理(包括实体识别与连接)

先贴一下数据集的原始数据形态,拿 SimpleQuestions 的数据贴一下,WebQuestions 的数据要比这个丑陋一些,就不提了。数据量方面,SimpleQuestions 的 train/test 是 75910/21687 ,WebQuestions 是 3778/2032



SimpleQuestions 的原始数据中,每一行一个数据,分四列,中间用“\t”隔开,四列分别是头实体id,关系,尾实体id与问句内容

1.1 实体识别

首先训练实体识别模型,目标是给一个问题,能把问题中的实体名(entity mention)找到,方法就是喜闻乐见的 BIO 序列标注方法,模型用简单 LSTM 能够解决,或者再堆个 CRF 加强效果,序列标注在上一篇文章说过,“B” 即实体名的开始单词,“I” 为实体名的中间单词(或结尾词),“O” 为不是实体名的单词,输入一串单词序列,输出一串长度相同的由 BIO 组成的字母序列


训练数据有了,开始训练模型,不是主要内容不细说了,放一个模型图



这里 char-BiGRU 是从字母维度上的的 word embedding,以及 CRF layer,都是为了加强效果,简单作能够都省略

1.2 实体连接

找到了实体名,而后就是对应到 KB 中的具体实体。这一步作法比较简单,可是对最终效果的影响仍是比较大的,包括在 KB 中能不能找到对应的实体,以及找到多个实体怎么排序的问题。直接说方法,首先收集 KB 中全部实体的名称(包括“name”“外文名”“别名”等等的),而后构建单词到实体 id 的反向 map 表,举个例子



这里 Leslie 能够连接到两个实体,由于两个实体的名字中都含有 Leslie 这个单词。注意每个括号里的数字,表明词(或词组)连接到这个实体的打分,计算方式就是这个词组的单词个数除以这个实体完整实体名的单词个数。

这里打分也能够适当考虑实体的知名度进去,好比“Leslie Cheung Kwok-wing”这个实体知名度更高,“Uncle Leslie”没怎么据说过,因此用户提这个问题更有多是问关于前者的,因此前者的打分也要适当提升一些。具体操做方式能够很灵活,不细说了。

1.3 关系预测(seq2seq模型)

终于进入正题了。通过以前两步的数据处理,如今的数据基本是这个样子



上面是输入下面是指望输出,输入中每条数据就是一个问句,由若干个单词组成的序列,其中已经把实体名拿走,用“<e>”这个标记词进行替换。输出是一个关系名,虽然因为 Freebase 的关系格式定义,一个关系名由三个用“.”拼接的单词组成,可是这里只把他当成一个完整的单词看待。其实关系预测本质上就是一个文本分类问题,给定全部的关系列表,输入一个文本,分类到一个最可能的关系上。

在这一步结束后,获得了预测出的关系名,再加上上一步实体连接获得的具体实体,就能从知识库中找到三元组,找到答案,从而解决问题了。下面具体讲关系预测的模型及实现代码细节。

2 模型搭建

先上一个模型图


最简单的没有任何添加剂的纯自然的 seq2seq 模型,即 encoder-decoder 模型(固然也能够再加 attention 什么的上去,就不提了),左边(绿色)是一个双向 GRU(或 LSTM)(双向即两层,一层正向走一层反向走,而后把两层的最后结果加到一块儿,只用单向也能够,区别不大)做为 encoder,能把整个问题压缩成一个向量 u,右边是一个单向 GRU ,把向量 u 解压缩成一个关系,或关系序列,_GO 是表示序列开始生成的标记词,_EOS 是表示序列生成完毕的标记词。下面详细说一下为何会是关系序列。这也是原本一个简单的多分类任务为何不用简单的 RNN 分类模型而用 seq2seq 这种序列生成模型的缘由。

有时候仅靠一个关系(一跳)并不能找到最终答案,好比“张国荣曾在哪一个国家留学”,为了回答这个问题须要输出两个关系(两跳),第一跳是从“张国荣”经过“毕业院校”这个关系找到“英国里兹大学”这个实体,第二跳是从“英国里兹大学”经过“所属国家”这个关系找到“英国”这个最终答案。因此原来“张国荣出生在哪里”这个问题对应的输出序列是“出生地,_EOS”,而“张国荣曾在哪一个国家留学”对应的输出序列就变成了“毕业院校,所属国家,_EOS”,须要输出的关系序列长度是不同的,这也是 seq2seq 模型解决问答问题的优点所在。


Encoder

好了,编完了,下面上代码,首先是 Encoder


source_vocab_size 是全部数据中涉及到的单词词表大小,hidden_size 是单词被压缩成的词向量维度,设 batch 的大小为 B,batch 内每一个输入序列长度为 S,首先是形状 S*B 的张量进来,而后通过 embedding 获得 S*B*D 的张量,而后直接进 GRU ,获得结果 outputs 以及 hidden,这里由于使用了双向 GRU 因此 outputs 出来是 S*B*2D 的,hidden 出来是 2*B*D 的,须要压缩一下,outputs 在模型后面没有用到能够无所谓。这里再细说一下这个 pack_padded_sequence 的做用,这个函数机制真的是让我只想双击666

对于使用了 batch 的 GRU(或LSTM)来讲,要求输入的 batch 中的每个序列长度相同。可是一个 batch 里的问题有长有短,怎么可能都相同呢,因此就须要用一个没有意义的标记词(“_PAD”)把全部问题填充(Padding)到相同的长度,举个例子


在这个大小为 3 的 batch 里 ,后两个问题由于长度不足都被 padding 到了 5 个单词,可是在推到 GRU 里运行的时候,咱们只但愿它们前面有效的单词进去就能够了,后面的 _PAD 填充过多时会严重影响最后出来的效果,bucket 机制或许能够适当解决这个问题,可是 pytorch 提供的这个 pack_padded_sequence 很是完美,它能够自动保证 _PAD 不会真正进入到 GRU 中影响效果,只须要你事先把 input_seqs 先按长度从大到小排列一下,而后把排序后每一个序列的真正长度 input_lengths 传进来,好比这个例子里 input_lengths 就是 [5,4,3],而后包装好放进 GRU 里, GRU 运行完了再用 pad_packed_sequence 这个函数解包一下,就 OK 了


Decoder


Decoder 也比较简单,可是跟上面 Encoder 有个很大的区别就是这里 Decoder 一次只处理一个单词,假设指望输出序列长度是 M,须要运行 M 次,而上面 Encoder 是一次就把长度为 N 的序列都处理完。Decoder 不能这么作的缘由是在它的下一次输入是上一次输出,只有先运行一遍获得第一个单词才能再去获得第二个单词,而不像 Encoder 一开始就知道整个输入序列。


run_epoch

encoder 和 decoder 搭完了,下面就是怎么把他们拼起来了,一个 S*D 的 batch 来了,先跑 encoder,获得 1*S*D 的 encoder_hidden,就是模型图中最重要的 u,而后设最长输出序列长度为 t,分 t 次运行 decoder 模型,一次输入一个单词,最初的输入单词为标记词“_GO”,并将 做为初始隐层塞到 decoder 里。


先定义好参数优化器 optimizer,这里使用随机梯度降低算法(SGD),而后每输入一个 batch,运行一次 run_epoch 函数,计算一次 loss,更新一次参数,而后结束,返回此次 loss 的值;当 TRAIN=False,也就是测试的时候,不计算 loss 也不更新参数,直接对比真实输出与指望输出,返回准确度。

这里计算 loss 用了 masked_cross_entropy 这个函数。

他这个 loss 计算有一个很大的好处是什么呢,这就又涉及到 padding 的问题了,刚才说输入序列须要 padding,而且经过 pack_padded_sequence 避免了 _PAD 带来的影响,而输出序列也须要 padding,也须要一种措施避免影响,仍是举个例子


在这个大小为 3 的 batch 中,最长输出序列 t=3,后两条数据由于长度不足被加入了 _PAD 标记词,可是计算 loss 并更新参数的时候,咱们只但愿计算除 _PAD 之外的位置上的 loss,并不想关心 _PAD 上的 loss,由于没有意义,且会给效果带来影响。masked_cross_entropy 这个函数就经过一个 mask 矩阵把 _PAD 位置上的 loss 过滤掉了,很是流弊。具体再也不细说了,能够看源码。


3 训练及测试

终于一切基础都搭完能够开始训练了,也没啥能够说的,直接放代码吧


一共训练 num_epoch 轮,每轮经过 get_batch 这个函数制做一个 batch,运行一次 run_epoch 函数,更新一次模型,而后每隔 print_every 轮进行一次测试并打印结果,每隔 save_every 轮保存一次模型。get_batch 这个函数具体细节不写了,能够看源码。


问答问题目前的解决方法,框架基本都是上面说那四步,可是具体作法五花八门,模型各式各样,文中所用的 seq2seq 也只是一个简单实践,效果上比较以下图。简单的 seq2seq 效果还不错,虽然跟学术界目前最好成绩有很大差距,可是还不错。

原文地址 https://zhuanlan.zhihu.com/p/34585912




阅读过本文的人还看了如下文章:


《美团机器学习实践》_美团算法团队.pdf


2019最新《PyTorch天然语言处理》英、中文版PDF+源码


《21个项目玩转深度学习:基于TensorFlow的实践详解》完整版PDF+附书代码


《深度学习之pytorch》pdf+附书源码


PyTorch深度学习快速实战入门《pytorch-handbook》


【下载】豆瓣评分8.1,《机器学习实战:基于Scikit-Learn和TensorFlow》


《Python数据分析与挖掘实战》PDF+完整源码


汽车行业完整知识图谱项目实战视频(全23课)


李沐大神开源《动手学深度学习》,加州伯克利深度学习(2019春)教材


笔记、代码清晰易懂!李航《统计学习方法》最新资源全套!


《神经网络与深度学习》最新2018版中英PDF+源码


将机器学习模型部署为REST API


FashionAI服装属性标签图像识别Top1-5方案分享


重要开源!CNN-RNN-CTC 实现手写汉字识别


yolo3 检测出图像中的不规则汉字


一样是机器学习算法工程师,你的面试为何过不了?


前海征信大数据算法:风险几率预测


【Keras】完整实现‘交通标志’分类、‘票据’分类两个项目,让你掌握深度学习图像分类


VGG16迁移学习,实现医学图像识别分类工程项目


特征工程(一)


特征工程(二) :文本数据的展开、过滤和分块


特征工程(三):特征缩放,从词袋到 TF-IDF


特征工程(四): 类别特征


特征工程(五): PCA 降维


特征工程(六): 非线性特征提取和模型堆叠


特征工程(七):图像特征提取和深度学习


如何利用全新的决策树集成级联结构gcForest作特征工程并打分?


Machine Learning Yearning 中文翻译稿


蚂蚁金服2018秋招-算法工程师(共四面)经过


全球AI挑战-场景分类的比赛源码(多模型融合)


斯坦福CS230官方指南:CNN、RNN及使用技巧速查(打印收藏)


python+flask搭建CNN在线识别手写中文网站


中科院Kaggle全球文本匹配竞赛华人第1名团队-深度学习与特征工程



不断更新资源

深度学习、机器学习、数据分析、python

 搜索公众号添加: datayx  

长按图片,识别二维码,点关注



机器学习算法资源社群

不断上传电子版PDF资料

技术问题求解

 QQ群号: 333972581  

长按图片,识别二维码




海淘美妆

本文分享自微信公众号 - 机器学习AI算法工程(datayx)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索