构建《冰与火之歌》知识图谱 - bettermorn/KGCourse GitHub Wiki

参考来源

其他参考项目

项目目标

  • 从解决问题入手,边学习理论知识,边完成项目;
  • 了解并实践构建知识图谱的过程;
  • 了解构建知识图谱的相关人工智能理论和技术;
  • 熟练利用各种开源平台、工具和开源代码完成知识图谱

项目背景

  • 构建小说《冰与火之歌》(A song of ice and fire)中的人物、家族、城堡的知识图谱;

主要工作

包括三部分工作:(1)数据爬虫获取(2)数据预处理与关系抽取(3)关系逻辑推理 (4)知识图谱可视化;

1 数据处理、寻找实体

  • 1.1抓取及清理 代码triple_crawler.py
  • 1.2寻找小说文本中的实体 entity_linking.py
  • 1.3实体消减 实体匹配entity matching 或者 实体对齐 entity alignement: tail_matching.py

2 关系抽取

  • 2.1生成备选实体、真实实体以及实体与ID对应
  • 2.2生成包含分词标识的样本句子
  • 2.3标注实体与三元组关系,生成实体对样本
  • 2.4 训练模型和抽取新关系

3 知识推理 补全实体关系

4 聚类实体 与可视化展示

任务描述

1

  • 1.从维基网站上抓取相关的三元组,构成初步的知识图谱。清洗数据,解决网页上的文本存在错误和不对应关系。实体消减

2 关系抽取

准备训练集、测试集和验证集:基于第1步获取的实体及三元组关系,生成数据集,包括

  • 2.1 生成备选实体、真实实体以及实体与ID对应;
  • 2.2 生成包含分词标识的样本句子;
  • 2.3 标注实体与三元组关系,生成实体对样本;
  • 2.4 建立关系抽取模型:基于已有的小说和网站文本,将小说文本转化为三元组的训练集,学习出关系抽取的模型。注:由于网络爬虫获得的关系三元组在小说文本中匹配到的句子样本的数量非常有限,利用数据量比较充足的CCKS人物关系抽取任务中的数据集fine-tune预训练的bert模型,训练模型;
  • 2.5 抽取新的关系:基于小说文本,利用fine-tune的模型(bert),抽取新的关系。

3 推理补全实体关系

4 使用网页的方式展示整个知识图谱。

项目成果

  • 搜集数据、清洗数据、获取知识、构建知识图谱;
  • 使用网页的方式展示整个知识图谱;
  • 熟悉理解开源的知识图谱项目代码,并可以根据自己的需求完成新的知识图谱项目代码

项目内容

  • 项目完成目标 应用知识及在线讲座 使用工具 在线讲解
  • 0 了解项目 如何准备加入此项目?
  • 1 获取数据 爬虫,知识图谱概述 Python ✔️
  • 2 处理数据 知识建模与知识表示 Hanlp ✔️
  • 3 存储知识 知识存储 Jena,gStore ✔️
  • 4 抽取实体 知识抽取:抽取实体 DeepKE ✔️
  • 5 抽取关系 知识抽取:抽取关系 Bert ✔️
  • 6 挖掘知识 知识挖掘:实体链接及规则挖掘 DeepDive ✔️
  • 7 推理知识 知识推理 Java Jena ✔️
  • 8 可视化知识图谱可视化方法 JavaScript HTML ✔️
  • 9 项目总结 项目的收获与提升的地方
  • 获取数据, 生成
  • 处理数据
  • 存储知识
  • 抽取实体
  • 抽取关系
  • 挖掘知识
  • 推理知识
  • 可视化知识

先导知识和能力要求

  • 知识
  1. 熟悉Python编程;
  2. 会使用Anaconda,Spyder;
  3. 了解数据处理的基本方法;
  4. 如果会Java更好;
  5. 如果了解机器学习会更好;
  • 能力
  1. 工程实践能力;
  2. 探索精神

项目的学习材料

  • 阅读以下内容:
  • 国际标准网页;
  • 在线教程;
  • 综述性论文;
  • 知识图谱类书籍;
  • 阅读此项目代码及其他知识图谱项目代码;
  • 观看视频

项目的评价标准

  • 熟悉开源项目的结构;
  • 熟悉开源项目中代码所使用的理论和技术;
  • 可根据自己需求从头搭建一个知识图谱项目

0.如何准备加入此项目?

复习知识和工具

  • Anaconda, 使用Spyder,使用conda安装依赖库,建立虚拟环境
  • Python语法,
  • 用pip安装Python库,了解各种常用库

代码运行环境

Python3.7

代码依赖的平台和工具

参考开源项目的代码结构


|

  • |----bert_pretrain bert预训练模型
  • |----core 核心代码,预训练
  • |----datasets 下载的数据集ccks_IPRE and GOT 样本数据包括训练集、验证集以及测试集
  • |----entity_linking_res
  • |----graphs_json 可视化数据
  • |----img 静态图片
  • |----models bert模型 bert.py bertEntityEncoder.py
  • |----processed_data 处理过的数据
  •      |--------asoiaf_after_inference.ttl: 推理补全后的三元组
    
  •      |--------asoiaf.ttl
    
  •      |--------candidate_entity_replacement_list_v5.jsonl
    
  •      |--------candidate_entity_replacement_list_v6.jsonl
    
  • |----raw_data 原始数据,存储小说文本
  • |----snapshot 存储训练模型后生成的关系三元组
  • |----triple_crawler.py 抓取数据,清理数据,并将数据存储到jena上
  • |----entity_linking.py 抽取文本实体
  • |----tail_matching.py 实体消解 生成 candidate_entity_replacement_list_v5.jsonl
  • |----entity_clustering.py 聚类实体
  • |----process_crawled_triples.py 处理抽取到并初步清洗后的candidate_entity_replacement_list_v5.jsonl和asoiaf.ttl,生成
  •    literal_vocabulary和ent2id.json
    
  • |----preprocessor.py 解析小说文本,分词(hanlp) 生成preprocessed_data.jsonl
  • |----tag_entity.py 对解析好的文件标注实体与三元组关系
  • |----notransfer_main.py 训练模型

1.搜集数据

关键理论和技术

  • 知识表示 三元组
  • 知识表示的各种形式
  • 获取及解析网页数据

1.1抓取及清理 代码triple_crawler.py

输入

冰与火之歌中文维基地址

处理过程

*提取三元组,增加关系 get_info_main *清洗三元组 clean_triples()

方法说明

  • 注意:需要启动fuseki,运用jena数据库, 1). 安装fuseki 2).建立store “mkdir store” 3).运行命令启动fuseki fuseki-server --loc=store --update /testds,参考链接知识图谱工具信息
  • 将三元组存入jena数据库的通用方法是 sparql_add_triple(s, p, o)
  • get_info("艾德·史塔克", "https://asoiaf.huijiwiki.com/wiki/%E8%89%BE%E5%BE%B7%C2%B7%E5%8F%B2%E5%A1%94%E5%85%8B", "character") 从某个链接获取包含属于某个类别的某个名字的相关信息,并存入实体关系实体三元组
  • get_all_literal("literal_vocabulary", mode="w", encoding="utf-8", errors="ignore") 从jena数据库里获取文本写入文件literal_vocabulary
  • refine_literals() 找出对应实体的literal,存入jena 数据库 花费时间较长
  • get_index_main() 获取页面索引,并存入文件triples/{category_name}_index 和 triples/{category_name}_index.pkl
  • get_info_main() 获取三元组,并将其存入文件triples/incremental files/asoiaf.ttl 花费时间较长
  • to_simplified_chinese("triples/incremental files/asoiaf.ttl", "triples/incremental files/asoiaf-s.ttl") 转换为简体中文
  • 访问jena数据库链接,上传ttl文件(triples/incremental files/asoiaf.ttl)到jena数据库
  • clean_triples() 清理三元组,使用jena数据库去掉secondary entity,将jena数据库数据存入文件triples/incremental files/asoif.ttl
  • add_firstname_last_name() 增加姓名,存入jena数据库
  • change_relation_name("r:王后", "r:配偶")  改变关系的名称,存入jena数据库
    
  • sparql_all2file() 将jena数据库数据存入文件triples/incremental files/asoif.ttl

输出

  • triples/incremental files/asoif.ttl 和 triples/incremental files/asoiaf.ttl
  • 尾实体 Tail entity 存在问题:无法与现有实体匹配

1.2寻找小说文本中的实体 entity_linking.py

关键理论和技术

  • 知识表示 匹配尾实体

输入

json形式的小说文本文件:processed_data/preprocessed_data.jsonl

处理过程

  • 将匹配到的实体添加到句子的json结构中去,
  • 将processed_data/preprocessed_data_with_entity_v2.jsonl里的实体存储到文件中

输出

processed_data/entity2sentence_v2.pkl 注:耗时较长,8GB 内存2.6 GHz Dual-Core Intel Core i5 ,需4.5小时 实体

1.3实体消减(匹配) 实体对齐 tail_matching.py

实体对齐或者实体匹配是指三元组中实体与现有句子中实体匹配

功能介绍

抓取、清洗后的三元组中存在一些没能与现有实体匹配的literal实体。为便于三元组匹配到句子,将literal的实体替换成现有的实体。例如e:托曼·拜拉席恩 r:父亲 "詹姆·兰尼斯特(事实)".中的尾实体"詹姆·兰尼斯特(事实)"替换为现有的人物实体e:詹姆·兰尼斯特。这样在寻找三元组对应的句子时就不用直接匹配"詹姆·兰尼斯特(事实)",而是可以匹配e:詹姆·兰尼斯特的名、别名等。

输入

  • jena数据库中所有tail实体为literal的三元组
  • 所有实体对应名称的列表

处理过程

  1. 从图谱中找出tail需要匹配为实体的那些三元组
  2. 找出实体的共现次数
  3. 选取出可替换的实体

具体方法

记需要替换尾实体的三元组为s r o。现有的所有实体集合记为$E$

  1. o与$E$中每个实体计算相似度 o与某一实体$e$的相似度为:o与e.name​的莱文斯坦比 + o与e.name的最长公共子串长度/(len(o)+len(e.name))
  2. s与$E$中每个实体计算相似度 s与某一实体$e$的相似度为:s.name与e.name的莱文斯坦比 + s.name与$e.name$的最长公共子串长度/(len(s.name)+len(e.name))
  • 注:Levenshtein距离,是编辑距离的一种。指两个字串之間,由一个转成另一个所需的最少编辑操作次数。允许的编辑操作包括:
  • 将一个字符替换成另一个字符
  • 插入一个字符
  • 刪除一个字符
  • 应用于DNA分析、拼写检查、语音辨识、抄袭检测
  1. 将上述两个相似度都大于0.4的实体都记录下来作为候选实体。假如有三元组没有两个相似度都大于0.4的候选实体,则找出1个两个相似度都大于0.1的实体作为候选实体。再没有的话则该三元组不考虑进行尾实体的替换。
  2. 每个候选实体e都去文本中计算和头实体s的共现次数
  3. 根据上述计算,对于一个三元组,可以得到一组候选实体,每个候选实体有三个特征值:与o的相似度;与s的相似度;与s的共现次数
  4. 利用每个候选实体的三个特征值,找出候选实体中的skyline点。经过这一步筛选候选实体数量统计如下:
  5. 为了在上面的skyline实体中进一步选出一个用于替换的实体,我们考虑寻找skyline实体中的lower bound。 具体方法是将skyline实体分别按照三个属性值进行排序,并找出在这三个排序中都处于前k个的实体。通过不断降低k的值,直到剩下一个实体即为用于替换的实体 假如上述做法没能找出唯一一个实体用于替换,则考虑只使用与o的相似度;与s的共现次数两个属性计算lower bound 若仍不能找出唯一一个替换实体,则使用与o的相似度最大的那个skyline实体进行替换
  6. 通过1-7步得到的替换实体记录在文件candidate_entity_replacement_list_v6.jsonl中,每一行为一个三元组,用字典表示。keys、r、o分别是原来三元组的主谓宾,candidate_entity为选出来替换o的实体
  7. 第7步选出的替换实体中仍有一部分是错误的。因此我们也将每个三元组第6步选出的skyline实体记录到文件candidate_entity_replacement_list_v5.jsonl,到句子里匹配三元组的时候,可以认为匹配到任意一个skyline实体都是匹配到了o 中间文件:candidate_entity_by_editing_dist_and_cooccur_v4.jsonl candidate_entity_by_editing_dist_v8.jsonl
  • 注:Skyline的解释:给定一组多维的数据点,Skyline算子从中筛选出在所有维度上都不被其他点支配的数据点;Skyline算子的处理过程称之为Skyline计算.Skyline算子使得用户可以较小规模的Skyline结果集上选择自己感兴趣的对象,而无须关心那些已经被过滤掉的对象.因此, Skyline计算在多目标决策、数据可视化分析、用户偏好查询等方面应用广泛

输出

processed_data/candidate_entity_replacement_list_v6.jsonl 并将数据存到jena里 程序运行时间2小时左右

2.处理数据为模型训练的数据集

关键理论和技术

  • 知识表示 三元组
  • 标注实体
  • 远距离监督
  • 中文分词技术

2.1生成备选实体、真实实体以及实体与ID对应 process_crawled_triples.py

输入

  • preprocessed_data/candidate_entity_replacement_list_v5.jsonl
  • preprocessed_data/asoiaf.ttl

处理过程

深度处理,生成需要在文本分词时特别标注的实体,使得一个实体的不同表达能够被映射到统一的id上

输出

  • preprocessed_data/literal_vocabulary包含candidate entity true entity
  • preprocessed_data/ent2id.json

2.2生成包含分词标识的样本句子 preprocessor.py

输入

raw_data/*.xhtml

处理过程

解析、并利用Hanlp中的NLPTokenizer进行分词,分词过程中注意向词典内加入上一步处理的得到的candidate entity与true entity使其能够在样本生成时被标出;总计68064条样本句子,每一行代表一个样本,具体格式如下: {"text": "小说中的一段话(按xhtml中的

标签计算为一段话)", "hanlp_tokens": hanlp分词list, "hanlp_pos": hanlp分词标识(如nr, true_entity等词语类型), "meta": {"source": "句子来源文件名", "chapter": "句子来源章节名", "id": 顺序分配}}

输出

processed_data/preprocessed_data.jsonl,作为entity_linking的输入文件

2.3标注实体与三元组关系,生成实体对样本

标注实体与三元组关系tag_entity.py

输入

asoiaf.ttl

处理过程

标注实体与三元组关系,与实体对样本生成。在该部分尝试了删除句子中的停用词的操作,但后来发现目前大部分的中文关系抽取的方法并没有对停用词进行处理,而且删除停用词可能会影响语义的连贯性,于是最终操作是并没有过滤停用词的。 对一句话中的所有识别到的nr(Hanlp中的人名标识)、true_entity以及candidate_entity三种类型的词语进行排列组合,使得每个样本只有一对实体。沿袭远距离监督的思想,如果这个实体对在网络爬虫爬到的关系三元组中存在对应的关系,将该样本标记为对应到的三元组关系。按照这样的思想,共得到了92592条实体对样本,其中, 840条被标注为有三元组关系的(共25种关系被匹配到,包括其反向关系,如父亲(e1,e2)与父亲(e2,e1)),91752条为没有找到网络数据匹配的三元组关系的(这部分为重点希望再抽取到新的三元组关系的),最终按照7:1:2的比例生成训练集,验证集以及测试集,存储于中。文件中每一行代表一个样本,一个实体对样本的格式如下: {"text": "小说中的一段话(按xhtml中的

标签计算为一段话)", "hanlp_tokens": hanlp分词list, "hanlp_pos": hanlp分词标识(如nr, true_entity等词语类型), "meta": {"source": "句子来源文件名", "chapter": "句子来源章节名", "id": 顺序分配}, "token": 过滤的hanlp分词list, "filtered_pos": 过滤的hanlp分词标识, "ents": [[实体name文本, 实体标识(true_entity/candidate_entity/nr*\), 分词list中index], [实体name文本, 实体标识(true_entity/candidate_entity/nr*\), 分词list中index]], "label": 关系标签id, "h": {"name": 头实体文本, "pos": [头实体起始位置, 头实体结束位置], "tag": 头实体标识(true_entity/candidate_entity/nr*\)}, "t": {"name": 尾实体文本, "pos": [尾实体起始位置, 尾实体结束位置], "tag": 尾实体标识(true_entity/candidate_entity/n

输出样本文件

  • datasets/GOT/corpus_train.jsonl
  • datasets/GOT/corpus_dev.jsonl
  • datasets/GOT/corpus_eval.jsonl
  • datasets/GOT/relatin2id.jsonl
  • datasets/GOT/tagged_corpus.jsonl 注:运行时间半小时左右

2.4.训练模型 notransfer_main.py

鉴于网络爬虫获得关系三元组能够在小说文本中匹配到的句子样本的数量非常有限; 先利用数据量比较充足的CCKS人物关系抽取任务(https://biendata.com/competition/ccks_2019_ipre/)中的数据集fine-tune预训练的bert模型,使其具备关系抽取的能力; 小说文本用fine-tune好的bert模型测试,抽取相关人物关系 训练集为:datasets/CCKS-IPRE文件夹下的相应train文件,决定所抽取的关系类型数量以及名称 训练模型:python notransfer_main.py

关键理论和技术

  • 知识抽取之关系抽取
  • Bert预训练模型
  • 知识表示 三元组

输入

datasets/CCKS-IPRE/train

处理过程

  • pretrain.py 预训练 test.py 测试
  • use random seed: 42
  • loading datasets/ccks_IPRE/train.json data
  • 1利用CCKS人物关系抽取任务中的数据集fine-tune预训练的bert模型,做关系抽取;
  • 2基于权力的游戏小说文本,利用调好的模型测试,查看其能够抽取到的相关人物关系 参考(https://biendata.com/competition/ccks_2019_ipre/ 利用训练好的bert模型,生成关系三元组

输出

考虑到Hanlp本身识别到的nr词语不一定是真正的人物实体,只关注自己爬取到的true_entity及其相关变体candidate_entity。 snapshot/source_True_pred_notNoneCCKS_triples.jsonl 对小说文本进行CCKS-IPRE任务所定义的人物关系的发现 snapshot/source_True_pred_notNoneCCKS_triples_notNR.jsonl 只发生在true_entity或candidate_entity之间的三元组记录

常见问题

Error no file named ['pytorch_model.bin', 'tf_model.h5', 'model.ckpt.index'] found in directory ./bert_pretrain/bert-base-chinese or from_tf set to False 解决方法:

运行 convert_tf_checkpoint_to_pytorch.py 参考 https://github.com/huggingface/transformers/issues/2110 需要安装tensorflow Please download bert_model.ckpt.data-00000-of-00001 from https://storage.googleapis.com/bert_models/2018_11_03/chinese_L-12_H-768_A-12.zip and then put this file in the folder of bert-base-chinese. And then use the script named as 'convert_tf_checkpoint_to_pytorch.py' in the folder of OpenKG-for-Game-of-Thrones/bert_pretrain/ convert_tf_to_pytorch to generate the file called pytorch_model.bin.

The command for this generation is showed as follow:

export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12
python convert_tf_checkpoint_to_pytorch.py \
  --tf_checkpoint_path $BERT_BASE_DIR/bert_model.ckpt \
  --bert_config_file $BERT_BASE_DIR/bert_config.json \
  --pytorch_dump_path $BERT_BASE_DIR/pytorch_model.bin

关系抽取的评价指标

参考https://www.biendata.xyz/competition/ccks_2019_ipre/evaluation/ 评价指标 本次任务的评价指标包括精确率(Precision, P)、召回率(Recall, R)和F1值(F1-measure, F1),分为 Sent-Track 和 Bag-Track 两个部分,每部分按F1值分别排名。只统计预测结果中非NA的数目(如果NA关系预测错误,也会计入到评价指标中计算)。

  1. Sent-Track预测结果评价:

给定测试集结果,表示类别预测正确的句子数目,表示系统预测的句子数目,表示标准结果的句子数目。

计算公式如下: Sent-Track 2. Bag-Track预测结果评价:

给定测试结果,表示类别预测正确的包的数目,表示系统预测的包的数目,表示标准结果的包的数目。 计算公式如下: Bag

2.5 抽取新关系

关键理论和技术

输入

处理过程

输出

3.推理知识

关键理论和技术

  • 归纳推理 基于规则的推理

输入

  • 定义规则
  • 三元组数据

处理过程

应用推理规则,处理三元组,增加新的三元组数据

输出

asoiaf_after_inference.ttl

4.聚类实体和可视化知识图谱

4.1 聚类实体 entity_clustering.py

输入

asoiaf.ttl 或者 asoiaf_after_inference.ttl

处理过程

  • 获取entity2id和id2entity
  • 构造邻接矩阵
  • 聚类
  • 聚类知识图谱中的实体,计算page rank
  • 先使用pagerank对图谱中的实体网络进行节点重要性的计算,得到每个实体的重要性。同时对实体网络进行谱聚类,得到实体的分类。

输出

graphs_json/GOT_graph_{Category}.json

4.2 可视化知识图谱

关键理论和技术

  • JavaSript d3 HTML 展示实体

输入

graphs_json/GOT_graph_{Category}.json

处理过程

  • 用JavaScript HTML展示web页面

输出

web页面

5.存储数据 Jena

关键理论和技术

  • 知识存储
  • 知识存储技术

输入

ttf文件

处理过程

输出

6.项目总结

⚠️ **GitHub.com Fallback** ⚠️