基于知识图谱的智能问答

news/2024/11/9 9:37:03/

基于知识图谱的智能问答

  • 1.问答系统的简单介绍
    • 1.1 问答系统的目标
    • 1.2问答系统框架
  • 2. 项目介绍
    • 2.1数据集介绍
    • 2.2 问题分类
    • 2.3 技术方案
      • 2.3.1 数据准备
      • 2.3.2 数据导入neo4j
  • 3 模型
    • 3.1 JointBERT(分类、实体识别)
      • 3.1.1 数据集构造
      • 3.1.2 模型
    • 3.2 GraphSAGE(图网络完成属性预测)
      • 3.2.1 数据集构造
      • 3.2.3 模型
  • 4. KBQA
  • 5. 问题与总结

1.问答系统的简单介绍

1.1 问答系统的目标

  1. 将数据导入到neo4j数据库
  2. 完成图神经网络并嵌入到问答系统
  3. 给定一个自然语言的问题

    完成三元组的提取
    能回答任意问题的智能系统

    收益小于9968614的公司有哪些
    王青多大
    沈阳惠天热电股份有限公司有可能失信吗

1.2问答系统框架

问答系统

  • 1- 问题分析模块
    问题分析模块主要负责对用户的问题进行处理,如 王青多大
    问题分类:分析出这个问题是由实体查询属性
    ⽣成查询关键词(提问关键词,扩展关键词,…)
    确定提问答案类型(PER, LOC, ORG, TIM, NUM, …)
    确定提问的句法、命名实体、语义表示等等。
  • 2- 问题回答模块(信息检索)
    总的⽬标:如何根据问题的分析结果去缩⼩答案可能存在的范围。这个过程包含
    2.1.信息抽取
    ⽅法描述:从问句中提取关键词语,⽤信息检索的⽅法找出包含候选答案的段落或句⼦,然后基于问答
    类型⽤信息抽取的⽅法从备选答案集中提取出最佳答案。
    检索过程:段落或者句⼦级排序,利⽤不同类型关键词的加权组合
    答案抽取过程:根据问答类型从排序后的段落或句⼦中抽取答案
    2.2.模式匹配
    基本思想:对于某些提问类型(某⼈的出⽣⽇期、原名、别称等),问句和包含答案的句⼦之间存在⼀
    定的答案模式,该⽅法在信息检索的基础上根据这种模式找出答案。因此如何⾃动获取某些类型提问的
    尽可能多的答案模式是其中的关键技术。
    举个例⼦:
    问题⽂本:1968年的今天,加州斯坦福研究所的道格·恩格勒巴特发明了世界上第⼀只⿏标。最初恩格
    勒巴特给⿏标 起的名字叫“显示位置纵横显示器”最初的⿏标不过是⼀个⽊盒拖着⼀根绳⼦。但⼀个“⿏
    标”(Mouse)的⼩名却⻛靡天下。就是这⽆名⿏辈,竟让世界发⽣了天翻地覆的变化。……
    如下给出了⼀个发明家(INVENTOR)型问题的的答案模式及其答案匹配过程:
    问题:⿏标是谁发明的?
    先由问题解析问题类型< Question Type>和问题词< Q_tag>,这个⽅法略过。
    问题类型< Question Type>:发明家(INVENTOR)
    问题词< Q_tag>:⿏标
    我们要求的是答案< A>,然后根据候选句的评分,进⾏排序,返回前n句中匹配到的答案项。
    1.0 < A> 发明 < Q_tag>
    1.0 < Q_tag> 被 < A> 发明
    0.83 < A> 的 发明 < Q_tag>
    0.79 < A> < Q_tag> 的 发明者
    0.50 < A> (< Q_tag>)
    ……
    匹配到的模式:1.0 < A> 发明 < Q_tag>
    匹配到的答案:道格·恩格勒巴特(如上⽂本⿊体加粗⽂字)
  • 2.3- 问答
    给定⾃然语⾔问题,通过对问题进⾏语义理解和解析,利⽤知识库进⾏查询、推理得出答案。 其特点
    是,回答的答案是知识库中的实体。 KBQA问答是我们本项⽬的重点,具体的下个章节论述。
  • 3- 答案⽣成模块
    总的⽬标:如何从可能存在答案的信息块中抽取答案。
    ⼀般搜索引擎返回的是⼀堆⽹⻚,⽽问答系统需要返回的是简短的答案。这样,通过信息检索模块
    搜索出来的相关⽂档就要提交给答案抽取模块来提炼答案。答案可以是⼀句话,或者是⼏句话,也
    可以是⼏个词或者短语。对于那些问时间地点的问题,就可以⽤很短的语句来回答,⽽对于询问原
    因、事件的问题就需要较⻓的语句才能回答。⽐如对于问题“9.11事件的是怎么回事?”就不可能⽤
    ⼀句话就能回答的。所以答案的抽取还需要依据问题的类型。
    最后是⽤户⾏为反馈,就是怎么样根据⽤户的结果去指导我们去做更好对话模型的理解。

2. 项目介绍

2.1数据集介绍

数据中包含公司的主键、名称、分红方式、所处行业、债券类型等,也包含公司主要职位的人物名称,还有公司与公司之间的关系。

经过分析之后,我们建立的图谱中内容如下

  • 实体:公司、人物、行业、分红方式、违规类型、债券类型。
  • 公司的属性:名称、收益。
  • 人物的属性:名称、年龄。
  • 其他实体的属性只有:名称。
  • 公司与公司之间的关系有:供应商、客户、公担保。
  • 人物与公司之间的关系有:监事、董事。
  • 公司与行业的关系:属于。
  • 公司与分红方式的关系:属于。
  • 其他类似。
  • 将属性公司的所处行业属性按照关系来处理,便于之后进行查询。
    数据集简介

2.2 问题分类

KBQA问题可以分为事实类问题、是非类问题、对比类问题、原因方法类问题等。我们这里只回答事实类问题。

  • 事实类问题又分为:查询实体、查询属性、查询关系。
  • 查询实体:收益大于1000的公司有哪些;王青多大
  • 查询属性:沈阳惠天热电股份有限公司的分红方式什么
  • 查询关系:沈阳惠天热电股份有限公司的供应商; 沈阳惠天热电股份有限公司的供应商的供应商
  • 引入图神经网络完成属性预测:沈阳惠天热电股份有限公司有可能失信吗

其中查询关系又分为一跳和多跳。

项目目标1:能够识别这4类问题,给出正确答案。
项目目标2:引入召回、排序功能,彻底解决名称不匹配的可能性
项目目标3:引入生成式聊天机器人

2.3 技术方案

  • 1 输入问句
  • 2 通过联合模型JointBERT完成问句分类,实体识别,属性识别
  • 3 如果需要预测,则调用图神经网络完成属性预测
  • 4 输出答案

我们已知关系有:董事、理事、违规类型、供应商、客户等9种。

对于一跳关系查询:秦皇岛兴龙房地产集团有限公司的董事,这个处理和查询属性类似:使用AC自动机匹配得到关系,使用模板:match (s:company)-[p:{p}]->(o) where s.name=’{subject}’ return o.name 查询。

对于多跳关系查询:秦皇岛兴龙房地产集团有限公司的供应商的分红方式。这就要求先找到 ”秦皇岛兴龙房地产集团有限公司的供应商“查询得到答案: 重庆广建装饰股份有限公司。然后将问题替换为”重庆广建装饰股份有限公司的分红方式“。对于该问题要先分类,然后再按照不同类型问题的模板去查询。当前对于这个问题应该属于第三类查询关系,并且是一跳关系。按照模板处理。

2.3.1 数据准备

原始数据
原始数据存在excel中,是以属性的方式存储的。将其拆分为公司、人物、行业等excel。
在这里插入图片描述

2.3.2 数据导入neo4j

#######################
#  导入节点
######################
def import_company():# 组件-公司名-有无失信行为df = pd.read_csv('company_data/公司.csv')# 提取组件和公司名eid = df['eid'].valuesname = df['companyname'].valuesnodes = []data = list(zip(eid, name))for eid, name in tqdm(data):# 加入了额外属性, 收入profit# 这个例子中是随机数profit = np.random.randint(100000, 100000000, 1)[0]# 创建节点, 并加入属性,如再加入公司人数# node = Node('company', name=name, profit=int(profit), eid=eid, people_num=1000)node = Node('company', name=name, profit=int(profit), eid=eid)nodes.append(node)graph.create(Subgraph(nodes))

3 模型

3.1 JointBERT(分类、实体识别)

采用JointBERT的思想:
使用[CLS]完成意图识别、使用last_hidden_state完成实体识别、使用[CLS]+[SEP]完成属性识别

3.1.1 数据集构造

创建意图识别(4类)、实体识别(BIO标记法)、属性识别(多分类)的数据集

问题BIO意图属性
收益小于5684719的公司有哪些O O O O O O O O O B-LOC I-LOC O O O0profit
景明琪多大B-LOC I-LOC I-LOC O O1age
诸城外贸有限责任公司的债券类型是啥B-LOC I-LOC I-LOC I-LOC I-LOC I-LOC I-LOC I-LOC I-LOC I-LOC O O O O O O O2other
中铁高新工业股份有限公司有可能失信吗B-LOC I-LOC I-LOC I-LOC I-LOC I-LOC I-LOC I-LOC I-LOC I-LOC I-LOC I-LOC O O O O O O3other

3.1.2 模型

JointBERT

class JointBERT(BertPreTrainedModel):def __init__(self, config, args, intent_label_lst, slot_label_lst, attribute_label_lst):super(JointBERT, self).__init__(config)self.args = argsself.num_intent_labels = len(intent_label_lst)self.num_slot_labels = len(slot_label_lst)self.num_attribute_labels = len(attribute_label_lst)self.bert = BertModel(config=config)     # Load pretrained bertself.intent_classifier = IntentClassifier(config.hidden_size, self.num_intent_labels, args.dropout_rate)self.slot_classifier = SlotClassifier(config.hidden_size, self.num_slot_labels, args.dropout_rate)self.attribute_classifier = ObjectClassifier(config.hidden_size, self.num_attribute_labels, args.dropout_rate)if args.use_crf:self.crf = CRF(num_tags=self.num_slot_labels, batch_first=True)def forward(self, input_ids, attention_mask, token_type_ids, intent_label_ids, attribute_label_ids=None, slot_labels_ids=None):outputs = self.bert(input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)  # sequence_output, pooled_output, (hidden_states), (attentions)# last_hidden_state: [batch_size, seq_len, hidden_size]sequence_output = outputs[0]   # [last_hidden_state]# pooler_output: [batch_size, hidden_size]pooled_output = outputs[1]     # [CLS]slot_logits = self.slot_classifier(sequence_output)    # [batch_size, seq_len, hidden_size] --> [batch_size, seq_len, num_slot]intent_logits = self.intent_classifier(pooled_output)  # [batch_size, hidden_size] --> [batch_size, num_intent]# total_loss = intent_loss + self.args.slot_loss_coef * slot_losstotal_loss = 0# 1. Intent Softmaxif intent_label_ids is not None:if self.num_intent_labels == 1:intent_loss_fct = nn.MSELoss()intent_loss = intent_loss_fct(intent_logits.view(-1), intent_label_ids.view(-1))else:intent_loss_fct = nn.CrossEntropyLoss()intent_loss = intent_loss_fct(intent_logits.view(-1, self.num_intent_labels), intent_label_ids.view(-1))total_loss += intent_loss# 2. Slot Softmaxif slot_labels_ids is not None:if self.args.use_crf:slot_loss = self.crf(slot_logits, slot_labels_ids, mask=attention_mask.byte(), reduction='mean')slot_loss = -1 * slot_loss  # negative log-likelihoodelse:slot_loss_fct = nn.CrossEntropyLoss(ignore_index=self.args.ignore_index)# Only keep active parts of the lossif attention_mask is not None:active_loss = attention_mask.view(-1) == 1active_logits = slot_logits.view(-1, self.num_slot_labels)[active_loss]active_labels = slot_labels_ids.view(-1)[active_loss]slot_loss = slot_loss_fct(active_logits, active_labels)else:slot_loss = slot_loss_fct(slot_logits.view(-1, self.num_slot_labels), slot_labels_ids.view(-1))total_loss += self.args.slot_loss_coef * slot_loss# 3. Object# 为了导入subject 的信息,先做一次预测,求取出 subject token  ---> word_embedding  ---> plus to sequence_outputif attribute_label_ids is not None:# slot_preds_ids: [batch_size, seq_len, num_slot_labels]slot_preds_ids = slot_logits.detach().cpu().numpy()slot_preds_ids = np.argmax(slot_preds_ids, axis=2)# 将slot_preds_ids 转换为 subject_preds_idssubject_preds_ids = slots_ids_2_subject_ids(slot_preds_ids)# subject_input_index = [[input_ids[batch][start:end+1] for start, end in line] for batch, line in enumerate(subject_preds_ids)]attribute_logits = self.attribute_classifier(sequence_output)# compute Object lossif attribute_label_ids is not None:if self.num_attribute_labels == 1:attribute_loss_fct = nn.MSELoss()attribute_loss = attribute_loss_fct(attribute_logits.view(-1), attribute_label_ids.view(-1))else:attribute_loss_fct = nn.CrossEntropyLoss()attribute_loss = attribute_loss_fct(attribute_logits.view(-1, self.num_attribute_labels), attribute_label_ids.view(-1))total_loss += attribute_lossoutputs = ((intent_logits, slot_logits, attribute_logits),) + outputs[2:]  # add hidden states and attention if they are hereoutputs = (total_loss,) + outputs# outputs: (total_loss), ( (last_hidden_state, pooler_output), (outputs[2:]) )return outputs  # (loss), logits, (hidden_states), (attentions) # Logits is a tuple of intent and slot logits

3.2 GraphSAGE(图网络完成属性预测)

仅可预测公司实体是否可能存在失信

3.2.1 数据集构造

eidcompanynameindustryassignviolationsbonddishonesty_y
06fc37e2-8bf5-4e36-adc2-387f6a96a4ad江苏联赢激光有限公司不分配信息披露虚假或严重误导性陈述1
003ffe3f-d012-40b6-9cd6-ba94cf235ae2重庆江骏房地产开发有限公司寿险公司业绩预测结果不准确或不及时企业债0

3.2.3 模型

在这里插入图片描述
GraphSAGE 是Graph SAmple and aggreGatE的缩写,其运行流程如上图所示,可以分为三个步骤

对图中每个顶点邻居顶点进行采样
根据聚合函数从聚合邻居顶点蕴含的信息
得到图中各顶点的向量表示供下游任务

class GraphSAGE_MODEL(torch.nn.Module):def __init__(self, args, in_channels=31, hidden_channels=64):super(GraphSAGE_MODEL, self).__init__()# in_channels   # 初始特征的维度# out_channels  # 分类self.args = argsself.out_channels = args.num_classesself.conv1 = SAGEConv(in_channels, hidden_channels)self.conv2 = SAGEConv(hidden_channels, hidden_channels)self.conv3 = SAGEConv(hidden_channels, hidden_channels)self.lin = torch.nn.Linear(3 * hidden_channels, self.out_channels)# 每层的聚合方式def set_aggr(self, aggr):self.conv1.aggr = aggrself.conv2.aggr = aggrself.conv3.aggr = aggrdef forward(self, data):x0, edge_index, edge_weight = data.x, data.edge_index, data.edge_attrx1 = F.relu(self.conv1(x0, edge_index, edge_weight))x1 = F.dropout(x1, p=0.2, training=self.training)x2 = F.relu(self.conv2(x1, edge_index, edge_weight))x2 = F.dropout(x2, p=0.2, training=self.training)x3 = F.relu(self.conv3(x2, edge_index, edge_weight))x3 = F.dropout(x3, p=0.2, training=self.training)x = torch.cat([x1, x2, x3], dim=-1)x = self.lin(x)return x

4. KBQA

主要包含内容:

  • 调用训练好的ner_bert 模型(文本分类、实体提取、属性名提取),完成文本分类
    • 属性查实体
              # 属性 查 实体op, num = get_op(text)cypher = f'match (n:{subject_type}) where n.{attribute}{op}{num} return n.name'print(cypher)res = graph.run(cypher).to_ndarray()
      
    • 实体查属性
              # 实体 查 属性cypher = f'''match (n:{subject_type}) where n.name='{subject}' return n.{attribute}'''print(cypher)res = graph.run(cypher).to_ndarray()
      
    • 实体、关系查询实体(多跳问答)
              # 实体、关系 查询实体# 实体 subject# 关系抽取  这里 可用 spo 方法, 同时抽取 ner 和 relationpredicate = []for end_index, original_value in ac_relation.iter(text):start_index = end_index - len(original_value) + 1print('关系:', (start_index, end_index, original_value))assert text[start_index:start_index + len(original_value)] == original_valuepredicate.append(original_value)for i, p in enumerate(predicate):cypher = f'''match (s:company)-[p:`{p}`]->(o) where s.name='{subject}' return o.name'''print(cypher)res = graph.run(cypher).to_ndarray()object = res[0][0]if i == len(predicate) - 1:breaknew_index = text.index(p) + len(p)new_question = object + str(text[new_index:])print('new question:', new_question)res = kbqa(new_question)break
      
    • 预测是否可能失信
      • 调用图神经网络
                # 预测是否可能失信assert subject_type == "company", "Subject not a company if you want to pre_dishonesty"from utils import pre_dishonestyres = pre_dishonesty(args, subject)
        

5. 问题与总结

1、仅限于提问已经存在与知识库的问题
1、提取的实体(slot_pred --> subject)来自输入语句txt, 有可能导致和数据库中实体名称不能匹配,如公司名字应该说全名
2、三任务联合训练在简单数据集(如本项目,以公司为主题的数据集)上能达到很好的效果,这是因为数据集简单,提问简单,但是如果是复杂数据集,其可能存在其他的问题
3、GNN模块存在较大的问题
  a) 数据集的制作存在问题,OneHot编码的方式简单的使用了pd.get_dummies,考虑能否往embedding反向转变
  b) 准确率有待提高

结果

text:收益小于9968614的公司有哪些
question type: 0
match (n:company) where n.profit<9968614.0 return n.name
[[‘广东欧昊集团有限公司’]
[‘浙江天工建设集团有限公司’]
…]


text:绍兴仁昌酱园有限公司的收入
question type: 1
match (n:company) where n.name=‘绍兴仁昌酱园有限公司’ return n.profit
[[16399117]]


text:沈阳惠天热电股份有限公司的分红方式什么
question type: 2
match (s:company)-[p:分红方式]->(o) where s.name=‘沈阳惠天热电股份有限公司’ return o.name
[[‘现金分红’]]


text:沈阳惠天热电股份有限公司有可能失信吗
question type: 3
the node: 沈阳惠天热电股份有限公司, --> 0

展望
1、引入召回、排序功能,彻底解决名称不匹配的可能性
2、引入生成式聊天机器人


http://www.ppmy.cn/news/917735.html

相关文章

自动问答系统流程

一个自动问答系统可分为问句处理和答案检索两大部分。 在一个面向电影领域知识的问答系统中&#xff0c;把所有数据存放在mysql数据库中&#xff0c;用非结构数据库neo4j&#xff08;也称图形属性数据库&#xff09;构造电影图谱&#xff0c;在电影图谱的基础上进行答案检索。…

问答机器人介绍

问答机器人介绍 1. 问答机器人 【回答一个确定的问题】 在前面&#xff0c;对问答机器人介绍过&#xff0c;这里的问答机器人是在分类之后&#xff0c;对特定问题进行回答的一种机器人。至于回答的问题的类型&#xff0c;取决于我们的语料。 当前我们需要实现的问答机器人…

在线问答系统html模板,问答系统网站模板

充值模块 会员积分:支持设置会员积分及积分累计升级,并获得购买折扣; 会员充值:支持会员充值到账号,用于购买商品,下载点数等开通; 微信 公共号:添加多个公共号,方便管理及推送信息; 自定义菜单:能够自定义微信端导航菜单; 信息推送:自定义推送信息,自动回复功能; 多…

java中文问答系统_基于知识图谱的问答系统

基于知识图谱的问答系统 发布时间:2018-06-10 21:27, 浏览次数:561 基于知识图谱的问答系统 一.准备工作: 1.下载好java8,并用mysql创建好数据库–重点在于存储数据 2.spark安装–用来进行提问问题的分类算法的编写 3.进行neo4j–用来存储mysql对应的数据库的关系–重点在于存…

视觉问答项目

视觉问答项目 1. 项目地址 本笔记项目包括如下&#xff1a; MCAN(Deep Modular Co-Attention Networks for Visual Question Answering)用于VQA的深层模块化的协同注意力网络 项目地址&#xff1a;MCAN_paper代码地址&#xff1a;MCAN_code murel(Multimodal Relational Rea…

QA智能问答

是基于检索的还是基于生成式回答的是开放领域的还是限定领域的 问答系统分为开放领域和限定领域的智能问答系统 面向学生的智能聊天机器人 包含以下两个部分 问答模块聊天对话模块解决学生提出的问题与学生闲聊基于规则实现基于深度学习实现数据库为15个关于新生的问题公开…

2021问答年终总结

2021年&#xff0c;CSDN问答团队为大家交付了2071个需求&#xff0c;以始为终&#xff0c;我们一直致力于帮助IT技术人解决问题。 截止今天&#xff0c;每天CSDN新增的问题中&#xff0c;50%的问题在10分钟内被回复&#xff0c;25%的问题在5分钟内被回复。 &#xff08;图表注…

医疗问答机器人项目部署

医疗问答机器人项目部署 文章目录 医疗问答机器人项目部署1. 拉取TensorFlow镜像2. 配置系统环境2.1 更换软件源2.2 下载vim2.3 解决vim中文乱码问题2.4 安装Neo4J图数据库2.5 安装网络工具包 3. 运行项目3.1 拷贝项目到容器中3.2 安装项目所需的工具包3.3 导入数据3.4 打开实体…