自然语言处理(NLP):20 基于知识图谱的智能问答系统

基于知识图谱的问答系统答即根据一个问题,抽出一条三元组,生成类 sql 语句,知识图谱查询返回答案。本文是基于知识图谱的问答系统,通过 BERT+CRF 做命名实体识别和句子相似度比较,最后实现线上的部署。

针对知识图谱的问题系统,重点解决的几个重要问题。通过本文学习,让你掌握知识图谱涉及的主要内容,通过本文分享,大家搭建快速搭建一个知识图谱的智能问答应该没什么问题了。

  • 知识库创建( 一般情况下,这个工作工作非常大,也非常重要。针对数据一般来自公司、比赛、以及通过爬虫来构建数据知识库)
  • 命名实体识别(一般通过bert_crf,bilstm_crf 等模型来完成,实际工作一般也需要工作增加规则来处理)
  • 实体链接到知识库进行检索(我们识别实体后,如何正确去对应到我们的知识库,也是我们的重点,这块很多思路大家可以提前在nlp 很多比赛都有提及)
  • 基于知识库的问答(一般我们都是基于图数据库来完成的,根据数据量的大小来选择,例如:neo4j、JanusGraph等。如果是简单的知识库关系可以mysql,redis,mongo存储即可)
  • 知识图谱一般垂直领域图谱或者开放领域图谱,持续优化的过程关注在知识库创建上。创建完成,可以直接应用到搜索,推荐,智能客服等对话系统。。。

本文主要研究内容如下

  • 问答 QA 系统简单介绍
    • 数据集介绍(实体间歧义问题、检索模型效果)
    • KBQA整理流程介绍
    • 评价标准回顾
  • 命名实体识别数据准备
    • 数据预处理
    • 数据集准备(切分、ner数据、文本相似度数据、知识库数据)
  • BERT-CRF命名实体识别训练
    • BERT原理
    • BERT-CRF 模型实现NER
    • 在线预测服务
  • 文本语义相似度模型训练
    • 数据可视化
    • BERT分类模型
    • 文本相似度在线服务
  • 知识库构建
    • 知识库介绍
    • 知识库构建
    • 基于知识检索方案
  • 基于知识库的QA系统检索
    • 搭建QA检索服务(依赖NER模型、文本相似度模型、知识库)
    • QA检索服务案例验证
  • 扩展以及回顾
    • 不足以及未来的发展
    • 扩展解决方案思路

1-项目介绍

- 1.1-数据集介绍

NLPCC 全称自然语言处理与中文计算会议(The Conference on Natural Language Processing and Chinese Computing),它是由中国计算机学会(CCF)主办的 CCF 中文信息技术专业委员会年度学术会议,专注于自然语言处理及中文计算领域的学术和应用创新。

数据集来自 NLPCC ICCPOL 2016 KBQA 任务集,其包含 14609 个问答对的训练集和包含 9870 个问答对的测试集。

提供的知识库

  • 6502738 个实体
  • 587875 个属性
  • 43063796 个 实体-实体关系

知识库文件中每行存储即三元组 ( 实体、属性、属性值)

各文件统计如下:

训练集:14609
开发集:9870
知识库:43063796

知识库样例如下:

"希望之星"英语风采大赛|||中文名|||“希望之星”英语风采大赛
"希望之星"英语风采大赛|||主办方|||中央电视台科教节目中心
"希望之星"英语风采大赛|||别名|||"希望之星"英语风采大赛
"希望之星"英语风采大赛|||开始时间|||1998
"希望之星"英语风采大赛|||比赛形式|||全国选拔
"希望之星"英语风采大赛|||节目类型|||英语比赛

原数据中本只有问答对(question-answer)无标注三元组(triple),如下所示

<question id=1>	《机械设计基础》这本书的作者是谁?
<answer id=1>	杨可桢,程光蕴,李仲生
==================================================
<question id=2>	《高等数学》是哪个出版社出版的?
<answer id=2>	武汉大学出版社
==================================================
<question id=3>	《线性代数》这本书的出版时间是什么?
<answer id=3>	2013-12-30

本人所用问答对数据来自该比赛第一名的预处理 https://github.com/huangxiangzhou/NLPCC2016KBQA 。构造 Triple 的方法为从知识库中反向查找答案,根据问题过滤实体,最终筛选得到,也会存在少量噪音数据。该 Triple 之后用于构建实体识别和属性选择等任务的数据集。

问答对样例如下所示(重点增加 triple,这里实体抽取和属性抽取的基本数据-知识抽取问题)

<question id=1>	《机械设计基础》这本书的作者是谁?
<triple id=1>	机械设计基础 ||| 作者 ||| 杨可桢,程光蕴,李仲生
<answer id=1>	杨可桢,程光蕴,李仲生
==================================================
<question id=2>	《高等数学》是哪个出版社出版的?
<triple id=2>	高等数学 ||| 出版社 ||| 武汉大学出版社
<answer id=2>	武汉大学出版社
==================================================
<question id=3>	《线性代数》这本书的出版时间是什么?
<triple id=3>	线性代数 ||| 出版时间 ||| 2013-12-30
<answer id=3>	2013-12-30
==================================================

- 1.1.1-知识库实体间的歧义

以“贝拉克·奥巴马”为例,涉及该实体的问答对如下:

<question id=9687>	谁是贝拉克·奥巴马的妻子?
<triple id=9687>	贝拉克·奥巴马 ||| 妻子 ||| 米歇尔·奥巴马
<answer id=9687>	米歇尔·奥巴马

在知识库中查询包含该实体的三元组,结果如下(部分):

贝拉克·奥巴马(美国现任总统) ||| 别名 ||| 贝拉克·奥巴马
贝拉克·奥巴马(美国现任总统) ||| 姓名 ||| 贝拉克·侯赛因·奥巴马
贝拉克·奥巴马(美国现任总统) ||| 妻子 ||| 米歇尔·奥巴马
......
贝拉克·奥巴马 ||| 主要成就 ||| 1996 年伊利诺伊州参议员 美国第 56 届、57 届总统 2009 年诺贝尔和平奖获得者 时代周刊年度风云人物 2008、2011 任期内清除本·拉登
贝拉克·奥巴马 ||| 代表作品 ||| 《我相信变革》《我父亲的梦想》《无畏的希望》
贝拉克·奥巴马 ||| 妻子 ||| 米歇尔·拉沃恩·奥巴马
......
贝拉克·奥巴马(美国第 44 任总统) ||| 血型 ||| ab
贝拉克·奥巴马(美国第 44 任总统) ||| 学院 ||| 西方学院
贝拉克·奥巴马(美国第 44 任总统) ||| 妻子 ||| 米歇尔·拉沃恩·奥巴马

首先,知识库中存在“贝拉克·奥巴马”的多条实体,有可能是多数据来源的融合或其他原因,从而并不能完全保证信息的对齐。我们查看“妻子”这一属性,发现有的是“米歇尔·拉沃恩·奥巴马”有的是“米歇尔·奥巴马”,而我们问答对中给出的答案是“米歇尔·奥巴马”。因此当我们的模型检索到正确三元组时:

贝拉克·奥巴马(美国第 44 任总统) ||| 妻子 ||| 米歇尔·拉沃恩·奥巴马

虽然在实体和属性都映射正确的情况下,最终答案仍可能被判定为错误。

- 1.1.2-问题实体歧义

以“博士来拜”为例,涉及该实体的问答对如下:

<question id=249>	博士来拜是什么年代的作品?
<triple id=249>	博士来拜 ||| 年代 ||| 1461 年
<answer id=249>	1461 年

在知识库中查询包含该实体的三元组,结果如下(部分):

博士来拜(曼特尼亚画作) ||| 别名 ||| 博士来拜
博士来拜(曼特尼亚画作) ||| 中文名 ||| 博士来拜
博士来拜(曼特尼亚画作) ||| 类别 ||| 油画,壁画
博士来拜(曼特尼亚画作) ||| 年代 ||| 1461 年
博士来拜(曼特尼亚画作) ||| 作者 ||| 曼特尼亚
......
博士来拜(维登画作) ||| 别名 ||| 博士来拜
博士来拜(维登画作) ||| 中文名 ||| 博士来拜
博士来拜(维登画作) ||| 类别 ||| 油画
博士来拜(维登画作) ||| 年代 ||| 1455 年
博士来拜(维登画作) ||| 作者 ||| 维登
博士来拜(维登画作) ||| 属地 ||| 慕尼黑画廊藏
......
博士来拜(达·芬奇画作) ||| 别名 ||| 博士来拜
博士来拜(达·芬奇画作) ||| 中文名 ||| 博士来拜
博士来拜(达·芬奇画作) ||| 类别 ||| 油画
博士来拜(达·芬奇画作) ||| 年代 ||| 1481-1482
博士来拜(达·芬奇画作) ||| 作者 ||| 达芬奇
博士来拜(达·芬奇画作) ||| 现藏 ||| 佛罗伦萨乌菲兹美术馆
博士来拜(达·芬奇画作) ||| 规格 ||| 246 x 243 厘米

问句中的问题是:“博士来拜是什么年代的作品?“,涉及到”年代“这个属性,而这幅作品被不同时期的很多人创作过,我们无法从当前问句下得到要询问的是哪位艺术家的创作年代。因此该问题的涉及的实体具有歧义性,同样的,当模型检索到我们认为的正确实体和正确属性后,依然有可能会被判定为错误答案。

- 1.1.3-检索模型的效果影响

在知识库中相关实体三元组数量过多的情况下,对检索模型的效果、效率也是个挑战

在具有 4300W 条三元组的知识库中,同一个实体会检索出大量(几十、几百条)的相关三元组,而且在存在上述两个歧义性问题的情况下,识别的效果和效率都是很大的问题。以上的两个问题在实体识别实验部分和属性抽取部分的影响较小,但在实体链接知识库检索最终答案三元组的部分会有较大的影响。

- 1.2-KBQA 整体流程

query-> 实体识别模型+属性抽取模型-> 知识库检索

KBQA 实现业务流程:

  • 输入问句 query
  • 通过实体识别模型检测问句中的实体,得到 mention(采用 BERT+CRF 进行实体抽取,可以看成中文命名实体识别问题)
  • 通过检索模型在知识库中检索 mention,得到候选集(K 个候选实体的所有三元组,通过类 sql 去知识库检索)
  • 通过属性抽取模型在候选集中挑选最合适的属性,得到唯一三元组
    • 规则匹配:如果前 n 个三元组有某个三元组的属性是 query 问题字符串的子集(相当于字符串匹配),将这个三元组的答案作为正确答案返回
    • 语义匹配:采用 BERT,多个结果与 query 进行相似度匹配进行打分
  • 输出答案

- 1.3-评价标准

  • 命名实体识别和属性映射评价标准

召回率 (Recall),精确率 (Precision) ,F1-Score。

  • 对话系统的评价指标可以分为客观评价指标和主观评价指标。

其中客观评价指标又可以分为:

  • 词重叠评价指标:(包括 BLEU、ROUGE、METEOR)
  • 词向量评价指标:(包括 Greedy matching、Embedding Average、Vector Extrema、perplexity 困惑度)

2-命名实体识别数据准备

- 2.1-数据预处理

清洗训练数据、测试数据、知识库过滤属性,去除‘-’,‘•’,空格等噪音符号;同时把每一行lower()转成小写。

https://github.com/huangxiangzhou/NLPCC2016KBQA

- 2.2-数据集准备

- 2.2.1-数据集切分

‘nlpcc-iccpol-2016.kbqa.testing-data’,‘nlpcc-iccpol-2016.kbqa.training-data’

-> 合并-> 按照比例切分 train,dev、test

  • 输入数据 ‘nlpcc-iccpol-2016.kbqa.testing-data’,‘nlpcc-iccpol-2016.kbqa.training-data’ 如下
<question id=6> 《高等数学一(微积分)》是哪一门课的通用教材?
<triple id=6> 高等数学 ||| 书名 ||| 高等数学一(微积分)
<answer id=6> 高等数学一(微积分)
==================================================
<question id=7> 有谁知道万达广场英文怎么说?
<triple id=7> 万达广场 ||| 外文名 ||| amoy wanda plaza
<answer id=7> amoy wanda plaza
  • 比例切分 train,dev、test
<question id=1> 《机械设计基础》这本书的作者是谁?
<triple id=1> 机械设计基础 ||| 作者 ||| 杨可桢,程光蕴,李仲生
<answer id=1> 杨可桢,程光蕴,李仲生
==================================================
<question id=2> 《高等数学》是哪个出版社出版的?
<triple id=2> 高等数学 ||| 出版社 ||| 武汉大学出版社
<answer id=2> 武汉大学出版社

- 2.2.2-构建实体识别训练数据: 实体识别

通过 NLPCC2016KBQA 中的原始数据,构建用来训练 NER 的样本集合。构造 NER 训练集,实体序列标注,训练 BERT+CRF。其中:LOC 表示其他类型,最终我们可是识别 BIO 标签即可

《O
线 B-LOC
性 I-LOC
代 I-LOC
数 I-LOC
》O
的 O
i O
s O
b O
n O
码 O
是 O
什 O
么 O
?O

最终我们的数据保存 train.txt,dev.txt,test.txt 三个文件
另外,我们需要文本长度分析

最要考虑 bert 模型,需要我们指定 seq_length,即句子的最大长度序列。

train.txt,dev.txt,test.txt -> 统计句子的长度-> seq_length = 64 合适。

- 2.2.3-构建属性识别训练数据: 属性识别

query-> 实体识别模型-> 获取实体名称-> 知识库检索-> 返回多个三元组

注:三元组组成(实体,属性名称,属性数值)

问题:究竟哪个三元组是我们需要的呢?

解决方案

  • query 去掉识别的实体后的内容,通过字符串匹配三元组属性名称
  • query 去掉识别的实体后的内容,和 三元组列表中的每个属性进行一个相似度打分,然后进行排序,最终得到一个最合适的答案。可以转换成一个二分类的问题。

那么接下来我们面临的问题。

  • 正样本: 当前 query 就是我们的正样本
  • 负验证:我们可以随机选择一部分属性名称,然后凭接 query 后构成我们的负样本

一个 sample 由“问题+属性+Label”构成,原始数据中的属性值置为 1。

原始的输入样本

<question id=1> 《机械设计基础》这本书的作者是谁?
<triple id=1>  机械设计基础 ||| 作者 ||| 杨可桢,程光蕴,李仲生
<answer id=1>  杨可桢,程光蕴,李仲生

通过采样构建的 属性分类样本数据

《机械设计基础》这本书的作者是谁?  作者 1
《机械设计基础》这本书的作者是谁?imdb 链接 0
《机械设计基础》这本书的作者是谁?  周点击    0
《机械设计基础》这本书的作者是谁?  建校时间   0
《机械设计基础》这本书的作者是谁?  主讲 0
《机械设计基础》这本书的作者是谁?  注意 0

当前我们完成了实体识别+属性识别-> 就可以直接去知识库中锁定唯一的答案了。

- 2.2.4-知识库搭建: 实体-属性名称-属性数值

entity,attribute,answer
机械设计基础,作者,杨可桢,程光蕴,李仲生
高等数学,出版社,武汉大学出版社
线性代数,出版时间,2013-12-30

例如:
query = 《机械设计基础》这本书的作者是谁?

query -> 实体识别模型-> 机械设计基础

query-> 属性识别模型-> 分类问题?文本相似比较( # TODO)

3-BERT-CRF 命名实体识别

- 3.1-BERT 原理介绍

BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding

BERT上下文表示和其他预训练语言模型

he Illustrated BERT, ELMo, and co.

图片图片

  • MRPC(Microsoft Research Paraphrase Corpus,也有的成其为 MSRP)是一些句子对,有的是同义的,有的是不同义的
  • CoNLL 2003 是进行 NER 经典的一个数据集

- 3.2-BERT+CRF 模型

pytorch BiLSTM+CRF代码详解

pytorch中bilstm-crf部分code解析

最通俗易懂的BiLSTM-CRF模型中的CRF层介绍

Bidirectional LSTM-CRF Models for Sequence Tagging(论文翻译)

pytorch lstm crf 代码理解

- 3.3-实体识别模型训练

标签: [“O”, “B-LOC”, “I-LOC”] 。

另外,我们把 BIO 编码格式数据转换为平台的统一标准,然后直接借助平台统一进行模型的训练,看看效果如何。

- 3.3.1-标准数据转换

上述数据处理生成三个文件

  • seq.in 每行表示一个完整的句子,然后以空格分割
《 机 械 设 计 基 础 》 这 本 书 的 作 者 是 谁 ?
《 高 等 数 学 》 是 哪 个 出 版 社 出 版 的 ?
  • seq.out 对应每个单词的 TAG,空格分割
O B-LOC I-LOC I-LOC I-LOC O O O O O O O O O O O O O
B-LOC I-LOC I-LOC O O O O O O O O O
  • slot_label.txt NER 标签的类型,这里增加 PAD 和 UNK 两个特殊的标签
PAD
UNK
O
B-LOC
I-LOC

- 3.3.2-标准数据可视化分析

针对业务数据可视化,我们这里借助pyecharts,seaborn ,matplotlib来完成。对此不熟悉的同学可以参考。
《 pyecharts 数据可视化》
《 seaborn 数据可视化》

  • 句子数量整体分析

图片

  • 句子长度分析

我们可以设置 seq_length = 64 做为 bert 模型的 max_seq_length 超参数

图片图片

  • 数据集标签分布

图片

图片

图片

- 3.3.3-模型训练

python3 main.py  \
--model_name_or_path ../pretrained_models/bert-base-chinese/ \
--task  NLPCC2016KBQA \
--model_type  bert \
--model_dir kbqa_bert_zh_model  \
--do_train  --do_eval --use_crf   \
--num_train_epochs  3 \
--train_batch_size 128 \
--eval_batch_size 64  \
--max_seq_len 60 \
--dropout_rate 0.9 

模型的效果如下所示,整个感觉训练效果还不错

dev:

06/05/2020 21:04:54 - INFO - train - loss = 0.3480187522040473

06/05/2020 21:04:54 - INFO - train - sementic_frame_acc = 0.9718463553033609

06/05/2020 21:04:54 - INFO - train - slot_f1 = 0.9731967748964916

06/05/2020 21:04:54 - INFO - train - slot_precision = 0.9717145343777197

06/05/2020 21:04:54 - INFO - train - slot_recall = 0.9746835443037974

test:

06/05/2020 21:05:09 - INFO - train - loss = 0.36994590636376024

06/05/2020 21:05:09 - INFO - train - sementic_frame_acc = 0.9704555705908886

06/05/2020 21:05:09 - INFO - train - slot_f1 = 0.970283656010806

06/05/2020 21:05:09 - INFO - train - slot_precision = 0.9685393258426966

06/05/2020 21:05:09 - INFO - train - slot_recall = 0.9720342805593144

- 3.4-预测

- 3.4.1-在线服务启动

我们通过 gpu 下训练的模型,也可以直接运行在 cpu 下。

python3 api.py \
--model_name_or_path ../pretrained_models/bert-base-chinese/ \
--task  NLPCC2016KBQA   \
--model_type  bert  \
--model_dir kbqa_bert_zh_model \
--use_crf 

注意:model_name_or_path 和 model_dir 换成自己预训练模型路径和模型文件路径

预测效率对比:gpu 单条记录预测 13ms 左右,cpu 大概 60ms(和服务器配置有关系)。对于 cpu 下推理速度慢的问题我们也可以针对模型进行优化(比如:albert-tiny…)

**在线预测命令行如下: **

我们抽查的原始数据

<question id=8> 王平的出生日期是哪一年呀?
<triple id=8>  王平 ||| 出生日期 ||| 1954 年
<answer id=8>  1954 年

在线服务预测,希望 query = xxx. 模型可以识别出" 王平" 这个实体

curl http://127.0.0.1:8000/predict \
-H "Content-Type:application/json" \
-X POST \
--data '{"text": "王平的出生日期是哪一年呀?","lang":"zh"}'  

返回的结果

$ curl http://127.0.0.1:8000/predict -H "Content-Type:application/json" -X POST --data '{"text": "王平的出生日期是哪一年呀?","lang":"zh"}'  
{
  "errno": 0, 
  "errmsg": "success", 
  "time": 13, 
  "data": [
    {
      "word": "王", 
      "tag": "B-LOC"
    }, 
    {
      "word": "平", 
      "tag": "I-LOC"
    }, 
    {
      "word": "的", 
      "tag": "O"
    }, 
    {
      "word": "出", 
      "tag": "O"
    }, 
    {
      "word": "生", 
      "tag": "O"
    }, 
    {
      "word": "日", 
      "tag": "O"
    }, 
    {
      "word": "期", 
      "tag": "O"
    }, 
    {
      "word": "是", 
      "tag": "O"
    }, 
    {
      "word": "哪", 
      "tag": "O"
    }, 
    {
      "word": "一", 
      "tag": "O"
    }, 
    {
      "word": "年", 
      "tag": "O"
    }, 
    {
      "word": "呀", 
      "tag": "O"
    }, 
    {
      "word": "?", 
      "tag": "O"
    }
  ]
}

后台日期服务器的数据(是我们正确识别出来的实体)

127.0.0.1 - - [05/Jun/2020 21:09:19] “POST /predict HTTP/1.1” 200 -

text = 王平的出生日期是哪一年呀?

seq_len = 13

0 王 B-LOC

1 平 I-LOC

2 的 O

3 出 O

4 生 O

5 日 O

6 期 O

7 是 O

8 哪 O

9 一 O

10 年 O

11 呀 O

12?O

- 3.4.2-批量数据核查

提供一批 问题列表,调用在线 api.py 中提供的服务,查看效果怎么样?

我们的数据,一定不能参与模型训练的数据,然后拿过来进行测试。

4-文本语义相似度模型

图片

关于属性映射我们看下提供的数据:

《机械设计基础》这本书的作者是谁?  作者 1
《机械设计基础》这本书的作者是谁?imdb 链接 0
《机械设计基础》这本书的作者是谁?  周点击    0
《机械设计基础》这本书的作者是谁?  建校时间   0
《机械设计基础》这本书的作者是谁?  主讲 0
《机械设计基础》这本书的作者是谁?  注意 0

- 4.1-数据集处理

  • 原始预料数据
0《机械设计基础》这本书的作者是谁? 作者 1
1《机械设计基础》这本书的作者是谁?imdb 链接 0
2《机械设计基础》这本书的作者是谁? 周点击 0
3《机械设计基础》这本书的作者是谁? 建校时间 0
4《机械设计基础》这本书的作者是谁? 主讲 0
5《机械设计基础》这本书的作者是谁? 注意 0

针对每行的句子的含义说明如下:

  • id: 表示句子唯一标识
  • text_a:句子1
  • text_b:句子2
  • label:句子1和句子是否相关 (0-不同;1-相同)
  • 数据离散化数据

图片

- 4.2-数据可视化分析

  • 句子标签数量分布

图片

  • 句子对的长度可视化分析

句子的最大的长度我们可以设置 64

图片图片

- 4.3-BERT 分类模型训练

python sim_main.py --data_dir ./data/ \
--task_name NLPCCKBQA2016 \
--num_train_epochs 2 \
--pre_train_model ../pretrained_models/bert-base-chinese \
--max_seq_length 64 \
--do_train \
--train_batch_size 64 \
--eval_batch_size 64 \
--gradient_accumulation_steps 4 \
--output  ./NLPCCKBQA2016_bert_zh_model 
  • data_dir:训练预料数据
  • pre_train_model : BERT 中文预训练的模型
  • output:训练完成模型保持路径
  • max_seq_length:表示 bert 模型输入句子最大的长度 (通过数据分析获得)
  • train_batch_size、eval_batch_size: 批量进行数据的处理
  • task_name:表示我们计算任务的名称,对应数据集加载方法
  • num_train_epochs 训练的迭代次数

模型训练完成后,我们看看在验证集上的效果(当前数据好坏影响非常大。)

15:10:17 - INFO - __main__ -     acc = 0.981087
15:10:17 - INFO - __main__ -     Precision = 0.920916
15:10:17 - INFO - __main__ -     Recall = 0.969807
15:10:17 - INFO - __main__ -     f1_score = 0.944730
15:10:17 - INFO - __main__ -     Evaluating EPOCH = [2/2] global_step = 684 eval_loss = 0.082648 eval_acc = 0.981087
best_acc =  0.9810874704491725

这里仅仅进行2次迭代,我们发现效果非常不错,f1_score = 94%

- 4.4-文本相似度在线服务

在线服务预测,希望 query = 丽江子馨小院客栈离车站多远啊?. 模型可以识别出" 丽江子馨" 这个实体。 那么这个时候会检索出该实体名称相关的列表(一个三元组结构),然后我们需要检索出 query 对应具体的那条记录(可以看成文本相似度问题-> 转为二分类问题求相似)

  • 启动在线服务应用服务
python3 api.py  \
--model_dir  ./NLPCCKBQA2016_bert_zh_model/best_sim.bin \
--bert_model ../pretrained_models/bert-base-chinese/ \
--max_seq_length 64
  • model_dir 训练好文本相似度的模型
  • bert_model 预训练模型的路径
  • max_seq_length  模型文本最大的句子长度(数据分析获取)
  • 测试案例1:API服务文本相似度调用(同一个含义案例)
curl [http://127.0.0.1:8000/v1/predict](http://127.0.0.1:8000/v1/predict)  \
> -H "Content-Type:application/json" \
> -X POST \
> --data '{"text_a": "丽江子馨小院客栈离车站多远啊?","text_b":"汽车站"}' 

{

  "errno": 0, 

  "errmsg": "success", 

  "time": 50, 

  "data": {

    "text_a": "丽江子馨小院客栈离车站多远啊?", 

    "text_b": "汽车站", 

    "result": "相同", 

    "prob": "95.13%"

  }

}
  • 测试案例2:API服务文本相似度调用(不是同一个含义的案例)
 curl [http://127.0.0.1:8000/v1/predict](http://127.0.0.1:8000/v1/predict)  \
> -H "Content-Type:application/json" \
> -X POST \
> --data '{"text_a": "丽江子馨小院客栈离车站多远啊?","text_b":"组织门派"}' 

{

  "errno": 0, 

  "errmsg": "success", 

  "time": 28, 

  "data": {

    "text_a": "丽江子馨小院客栈离车站多远啊?", 

    "text_b": "组织门派", 

    "result": "不同", 

    "prob": "96.12%"

  }

}

5-知识库导入数据库,并抽取三元组

- 5.1-知识库导入数据库

- 5.1.1-三元组数据格式

本篇知识问答实战来源 NLPCC2016 的任务:Open Domain Question Answering;其包含 14,609 个问答对的训练集和包含 9870 个问答对的测试集。并提供一个知识库,包含 6,502,738 个实体、587,875 个属性以及 43,063,796 个三元组。

图片

图片图片

- 5.1.2-MySQL 安装以及数据表设计

  • MySQL 安装以及使用

https://www.jianshu.com/p/2906abd8fd47

https://downloads.mysql.com/archives/community/

https://www.jianshu.com/p/2a23264b63d8

https://blog.csdn.net/memory6364/article/details/82426052

https://blog.csdn.net/skh2015java/article/details/80156278

我们这里设置:root/12345678

  • 知识库表设计
create databases KB_QA;
use KB_QA;
CREATE TABLE `nlpcc_qa` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `entity` text CHARACTER SET utf8,
  `attr_name` text CHARACTER SET utf8,
  `attr_value` text CHARACTER SET utf8,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1

字段说明:
entity : 实体

attr_name: 属性名称

attr_value: 属性数值

- 5.1.3-数据导入知识库

我们直接把知识库: 实体-属性名称-属性数值 (三元组) 倒入 mysql 数据库中。

注意: 数据比较大,考虑 4000 万+ 条数据比较大,在进行 mysql 插入数据操作可以进行批量进行插入 。

我们看下知识库的数据:kbqa.kb

空气干燥 ||| 别名 ||| 空气干燥
空气干燥 ||| 中文名 ||| 空气干燥
空气干燥 ||| 外文名 ||| air drying
空气干燥 ||| 形式 ||| 两个
空气干燥 ||| 作用 ||| 将空气中的水份去除
罗育德 ||| 别名 ||| 罗育德
罗育德 ||| 中文名 ||| 罗育德
  • 通过命令行导入数据(注:如果数据出现不支持的数据特殊字符会出现错误)
load data local infile '/data01/tt/kbqa.kb' \
into table nlpcc_qa \
CHARACTER SET 'utf8' \
fields terminated by '|||' enclosed by '"' \
ignore 0 lines \
(entity,attr_name,attr_value);
  • 通过程序批量数据导入
'''
知识库数据-批量导入
'''
import pymysql
api_server_host = 'localhost'
def connect():
    conn = pymysql.connect(
        user="root",
        password="12345678",
        host=api_server_host,
        port=3306,
        db="KB_QA",
        charset="utf8"
    )
    return conn
def execute_insert():
    conn = connect()
    cursor = conn.cursor()
    # 打开文件,读取所有文件存成列表
    with open("kbqa.kb", "r", encoding='utf-8') as file:
        """
            kbqa.kb 知识库格式如下(4000万+数据大概15分钟内就可以完成):
            空气干燥 ||| 别名 ||| 空气干燥
            空气干燥 ||| 中文名 ||| 空气干燥
            空气干燥 ||| 外文名 ||| air drying
            空气干燥 ||| 形式 ||| 两个
            空气干燥 ||| 作用 ||| 将空气中的水份去除
        """
        # 可以选择readline或者read的方式,但下面的代码要有所变化
        data_list = file.readlines()
        # 遍历列表
        count = 0
        for t in data_list:
            t = t.strip()
            text = t.split("|||")
            # sql语句
            sql = "insert into nlpcc_qa(entity,attr_name,attr_value) values (%s,%s,%s)"
            # 参数化方式传参
            try:
                cursor.execute(sql, [text[0], text[1], text[2]])
                if count % 100000 == 0:
                    print('commit......count={}'.format(count))
                    conn.commit()
            except Exception as e:
                # 这里错误数据直接忽略-考虑考虑错误的数据放入一个文本,然后check
                # print("Error: unable to fecth data: %s ,%s" % (repr(e), sql))
                pass
            # 显示操作结果
            count = count + 1

    # 统一提交
    conn.commit()
    # 关闭游标 
    cursor.close()
    # 关闭连接
    conn.close()
if __name__ == '__main__':
    execute_insert()

导入后的数据效果如下

图片

- 5.2-返回分数最高的三元组

  1. query = 高等数学出版社是是哪家?

  2. 然后通过 NER 识别: 高等数学

  3. 知识库过程 :根据高高等数学的实体名称去查询,获取多条记录

    sql = "select * from nlpcc_qa where entity = ‘高等数学’

结果如新:

高等数学 出版社 武汉大学出版社

高等数学 书名 高等数学一(微积分)

我们都指导,根据 query,我们的答案是 “武汉大学出版社” ,那么技术解决方案:

query 和 出版社

query 和书名

上述对应的 <question,attr_name> 进行相似度比较,然后获取正确的答案。

- 5.3-预测

NER 模型和文本相似度模型

NER 模型: kbqa_bert_zh_model/pytorch_model.bin

文本相似度模型: NLPCCKBQA2016_bert_zh_model/best_sim.bin

训练好上述两个模型后,就可以直接使用了,这里提供对应的服务供调用(先可以单独提供一个api的web 服务,同时加载两个模型,实际这样效率会高点)

  • 服务对应:8080 端口
python3 api.py \
--model_name_or_path ../pretrained_models/bert-base-chinese/ \
--task  NLPCC2016KBQA   \
--model_type  bert  \
--model_dir kbqa_bert_zh_model \
--use_crf 
curl http://127.0.0.1:8000/predict \
-H "Content-Type:application/json" \
-X POST \
--data '{"text": "王平的出生日期是哪一年呀?","lang":"zh"}' 
  • 服务对应:8081 端口
python3 api.py  \
--model_dir  ./NLPCCKBQA2016_bert_zh_model/best_sim.bin \
--bert_model ../pretrained_models/bert-base-chinese/ \
--max_seq_length 64
curl http://127.0.0.1:8001/v1/predict  \
-H "Content-Type:application/json" \
-X POST \
--data '{"text_a": "王平的出生日期是哪一年呀","text_b":"出生日期"}' 

6-基于知识库QA检索

通过前面内容,已经提供了满足QA 检索的服务,下面我们按照下面的过程就可以提供服务了.

  • query = xxxxx
  • query->调用NER 模型,返回多个元组列表
  • 多个元组列表-> 依次通过文本相似度模型进行打分,提取相关度最高的三元组为符合条件的内容,然后抽取predicate.
  • 根据实体名称subject + 关系predicate-> 知识库检索答案

- 6.1-搭建QA检索服务

下面是上述步骤的完整代码过程如下

import requests
import json
import pymysql
aheaders = {'Content-Type': 'application/json'}
api_server_host = 'localhost'
def connect():
    conn = pymysql.connect(
        user="root",
        password="12345678",
        host=api_server_host,
        port=3306,
        db="KB_QA",
        charset="utf8"
    )
    return conn
def close(conn):
    if conn:
        conn.close()
def execute_sql(conn, sql):
    cursor = conn.cursor()
    try:
        cursor.execute(sql)
        results = cursor.fetchall()
    except Exception as e:
        print("Error: unable to fecth data: %s ,%s" % (repr(e), sql))
    finally:
        cursor.close()
    return results
def get_ner_list(json_data):
    '''
     curl http://127.0.0.1:8000/predict \
        -H "Content-Type:application/json" \
        -X POST \
        --data '{"text": "王平的出生日期是哪一年呀?","lang":"zh"}'
    '''
    url = "http://{}:8000/predict".format(api_server_host)
    response = requests.post(url, headers=aheaders, data=json.dumps(json_data))
    json_ner_result = json.loads(response.text)
    entities = []  # 实体列表
    entity = []  # 每个实体临时变量
    for data in json_ner_result['data']:
        word = data['word']
        tag = data['tag']
        if tag != 'O':
            entity.append(word)
        else:
            if len(entity) > 0:
                entities.append("".join(entity))
                entity = []
    if len(entity) > 0:
        entities.append("".join(entity))
    return entities
def get_similarity(text_a, text_b):
    """
         curl http://127.0.0.1:8001/v1/predict  \
         -H "Content-Type:application/json" \
         -X POST \
         --data '{"text_a": "王平的出生日期是哪一年呀","text_b":"出生日期"}'
    """
    url = "http://{}:8001/v1/predict".format(api_server_host)
    input_json = {'text_a': text_a, 'text_b': text_b}
    response = requests.post(url, headers=aheaders, data=json.dumps(input_json))
    json_sim_result = json.loads(response.text)
    if json_sim_result['data']['result'] == '相同':
        return json_sim_result
    else:
        return None
def search(query):
    print('query = ',query)
    json_ner = {
        "text": query,
        "lang": "zh"
    }
    # 1. ner模型获取实体名称
    entities = get_ner_list(json_ner)
    # 2. 实体名称-> 知识库检索 得到三元组
    conn = connect()
    #
    for entity in entities:
        print('entity = ',entity)
        sql = "select * from nlpcc_qa where entity = '{}'".format(entity)
        data_list = execute_sql(conn, sql)
        print('*********** 识别实体名称: [{}] 检索的三元组列表 文本相似度比较***********'.format(entity))
        max_sim_text = ''
        max_prob = 0.
        for index, spo in enumerate(data_list):
            text_a = json_ner['text']
            text_b = spo[2]
            json_sim_result = get_similarity(text_a, text_b)
            if json_sim_result:
                print(json_sim_result['data'])
                prob = json_sim_result['data']['prob']
                prob = float(prob.split('%')[0])
                if prob > max_prob:
                    max_prob = prob
                    max_sim_text = json_sim_result
        # 最终的结果
        print('*********** 识别实体名称: [{}] 检索的三元组列表 文本相似度比较 最终结果***********'.format(entity))
        predicate = max_sim_text['data']['text_b']
        print('predicate = ',predicate)
        # 3。 entitiy + predicate -> 知识库检索给出最终的答案
        print('*********** 识别实体名称: [{}] , 关系: [{} ] 知识库检索答案 ***********'.format(entity,predicate))
        sql = "select * from nlpcc_qa where entity = '{}' and attr_name = '{}' ".format(entity,predicate)
        data_list = execute_sql(conn, sql)
        print('*********** 知识库检索答案 结果如下 ')
        for data in data_list:
            entity = data[1]
            attr_name = data[2]
            attr_value = data[3]
            print('search result: {} - {} - {}' .format(entity,attr_name,attr_value))
    #
    conn.close()

if __name__ == '__main__':
    #query = "谁知道中华人民共和国环境保护部的职能是什么?"
    query = "奥巴马毕业哪个大学"
    search(query)

- 6.2-案例分析


  • 案例测试1: query = 谁知道中华人民共和国环境保护部的职能是什么?

图片


  • 案例测试2: query = 北京大学的地址在哪里?

图片


  • 案例测试3:query = 杨幂有多重?

图片


  • 案例测试4:query = 中国的国土面积是多少

图片


  • 案例测试5:query = 奥巴马毕业哪个大学

图片

7-总结

我们在上述内容基础上,提出一些可以优化的知识点,供参考。

  • 知识库需要不断更新,知识库可以导入 图数据库,快速检索
  • 关于命名实体识别部分可以增加规则,提升效果(基于知识库过滤所有的实体,检索过程通过AC自动机快速检索)
  • 文本相似度文本,可以把识别的实体进行隐藏,重新训练模型查看效果
  • 根据query 识别出的实体,在知识库检索目前是精确匹配,也可以考虑基于语义进行匹配,提供知识库检索的召回内容

有任务疑问可以交流学习

8-参考

【参考文献】

【1】基于该数据集实现的论文

http://www.doc88.com/p-9095635489643.html

【2】NLPCC 比赛数据集下载页面

      [http://tcci.ccf.org.cn/conference/2017/taskdata.php](http://tcci.ccf.org.cn/conference/2017/taskdata.php)   

      [http://tcci.ccf.org.cn/conference/2016/pages/page05_evadata.html](http://tcci.ccf.org.cn/conference/2016/pages/page05_evadata.html) 

【3】InsunKBQA_一个基于知识库的问答系统_周博通_孙承杰_林磊_刘秉权

http://www.doc88.com/p-9095635489643.html

【4】 基于知识库的问答:seq2seq 模型实践

https://zhuanlan.zhihu.com/p/34585912

【5】基于 BERT 预训练的中文命名实体识别 TensorFlow 实现

https://blog.csdn.net/macanv/article/details/85684284

【6】FastBERT:又快又稳的推理提速方法(大家可以尝试FastBERT 模型)

https://zhuanlan.zhihu.com/p/127869267

【7】 其他内容

https://gitee.com/ngadminq

https://blog.csdn.net/ai_1046067944/article/details/86707784

http://www.doc88.com/p-9095635489643.html

https://blog.csdn.net/weixin_46133588/article/details/104700425

已标记关键词 清除标记
本课程隶属于自然语言处理(NLP)实战系列。自然语言处理(NLP)是数据科学里的一个分支,它的主要覆盖的内容是:以一种智能与高效的方式,对文本数据进行系统化分析、理解与信息提取的过程。通过使用NLP以及它的组件,我们可以管理非常大块的文本数据,或者执行大量的自动化任务,并且解决各式各样的问题,如自动摘要,机器翻译,命名实体识别,关系提取,情感分析,语音识别,以及主题分割等等。 一般情况下一个初级NLP工程师的工资从15万-35万不等,所以掌握NLP技术,对于人工智能学习者来讲是非常关键的一个环节。 【超实用课程内容】 课程从自然语言处理的基本概念与基本任务出发,对目前主流的自然语言处理应用进行全面细致的讲解,包括文本分类,文本摘要提取,文本相似度,文本情感分析,文本特征提取等,同时算法方面包括经典算法与深度学习算法的结合,例如LSTM,BiLSTM等,并结合京东电商评论分类、豆瓣电影摘要提取、今日头条舆情挖掘、饿了么情感分析等过个案例,帮助大家熟悉自然语言处理工程师在工作中会接触到的常见应用的实施的基本实施流程,从0-1入门变成自然语言处理研发工程师。 【课程如何观看?】 PC端:https://edu.csdn.net/course/detail/25649 移动端:CSDN 学院APP(注意不是CSDN APP哦) 本课程为录播课,课程2年有效观看时长,大家可以抓紧时间学习后一起讨论哦~ 【学员专享增值服务】 源码开放 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化 下载方式:电脑登录https://edu.csdn.net/course/detail/25649,点击右下方课程资料、代码、课件等打包下载 通过第二课时下载材料
相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页