Advertisement

基于医疗知识图谱的问答系统

阅读量:

一、项目来源

基于之前在Rasa框架下开发对话系统的经验,在探索是否能完全脱离这一开源工具的过程中

恰巧在Rasa群里看到了

@王乐

前辈分享了一个项目经验:基于知识图谱的医疗诊断知识问答系统。他观看了初步讲解后下载了代码并开始实践,在实践中逐步实现了基础功能模块。当遇到不懂的地方会反复观看讲解视频后逐渐掌握了相关技术。目前他已经能够基本操作该系统,并准备撰写一份学习总结并分享出来。为了进一步提升能力,在此基础上可能会尝试横向拓展应用范围。

为了避免重复或重复提及已有的资源(如项目主页上的视频链接),我在准备总结和分享时会尽量不涉及或不提及这些现有的信息。

因此建议本文和前辈的视频配合食用~

二、项目架构[1]

目前采用的是基础演示版系统。后续工作中可能会引入Redis、Elasticsearch以及TensorFlow Serving等技术组件进行扩展。但从个人角度来看,在当前阶段现有的功能配置已经能够满足基本需求。

本文的介绍也是基于目前的这个Demo进行的,后期会不断更新。

这个项目已实现的功能

  • 闲聊类的单论对话
  • 基于知识图谱的多轮问答

先看一下对话流程,或者也叫文本解析流程,是根据代码逻辑整理出来的:

以用户输入“请问得了心脏病怎么办呢 ”为例:

NLU模块

首先启动程序进行闲聊意图识别,并识别用户的意图类型。具体包括以下几个基本类型:问候语(greet)、道别语(goodbye)、拒绝语(deny)、机器人问候语(isbot)、接受指令(accept)以及诊断性问题(diagnosis)。

  • 当触发前四个主要意图时,则直接进入Chitchat_bot模块,并从预先准备好的回复数据包中随机抽取一条信息返回给用户,结束对话流程;
    • 当触发accept时,则直接进入问题分析阶段;
    • 当触发diagnosis时,则直接进入第2步(医疗辅助模块);

本例中,命中的是diagnosis ,进入 2)Medical_bot

在Medical_bot平台中, 依次进入分类模型2进行意图二次判别(涉及13个医疗类别); 然后运用NER模型对实体进行识别和提取.

意图识别的结果是

复制代码
    {'confidence': 0.8997645974159241, 'intent': '治疗方法'}

实体识别的结果是

复制代码
 [{'entities': [{'type': 'disease', 'word': '心脏病'}], 'string': '请问得了心脏病怎么办呢'}, {'entities': [{'recog_label': 'dict', 'type': 'disease', 'word': '心

    
 脏病'}], 'string': '请问得了心脏病怎么办呢'}]

前面这两步相当于任务型对话机器人中的NLU模块

DST模块

3) 得到意图和实体之后,先用实体填充槽位

这里探讨一下NLU与DST之间的联系与区别

自然语言理解模块旨在识别用户的意图类别的同时完成实体识别与标记过程,在此基础之上提供了精准的语言分析服务。其中列举了部分识别结果片段

复制代码
    {'entities': [{'type': 'disease', 'word': '心脏病'}], 'string': '请问得了心脏病怎么办呢'}

在本项目中,在知识图谱构建过程中识别实体及其类型(type),并确定相关的字段名称(word);然而目前尚未完成数据填充内容,在这一步骤仅完成了实体识别阶段的工作

DST模块 根据对话历史确定每个槽位对应的槽位值。

复制代码
 "治疗方法":{

    
     "slot_list" : ["Disease"],
    
     "slot_values":None,
    
     "cql_template" : ["MATCH(p:疾病) WHERE p.name='{Disease}' RETURN p.cure_way",
    
                     "MATCH(p:疾病)-[r:recommand_drug]->(q) WHERE p.name='{Disease}' RETURN q.name",
    
                     "MATCH(p:疾病)-[r:recommand_recipes]->(q) WHERE p.name='{Disease}' RETURN q.name"],
    
     "reply_template" : "'{Disease}' 疾病的治疗方式、可用的药物、推荐菜肴有:\n",
    
     "ask_template" : "您问的是疾病 '{Disease}' 的治疗方法吗?",
    
     "intent_strategy" : "",
    
     "deny_response":"没有理解您说的意思哦~"
    
     },

表示该记录类型代表了'治疗方案'这一核心概念,在槽位列表中仅有一个字段名为'Disease'(后续将详细阐述这一形式)。

在每一轮对话过程中, DST 模块会在每一轮对话开始时回顾所有已进行的对话记录,随后系统会识别出哪个候选文本能够适配到预定义槽位列表中的某一个特定位置,这一过程被称作追踪(Dialogue State Tracking)

在这个项目的实施过程中, 该步骤主要是通过系统性地遍历槽位列表以及结合实体识别的结果来实现功能匹配的.

PL模块

4) 然后根据意图置信度确定回复策略,这里分了三种简单的情况:

  • 大于等于 0.8 时,请依据识别到的意图访问Neo4j(知识图谱)以获取相关信息并返回给用户。
  • 介于 0.4 至 0.8 之间时,请向用户提供进一步的问题澄清。
  • 小于 0.4 时,请告知用户当前无法处理此类型的问题,并建议他们查阅相关资料或访问帮助中心获取更多信息。

由DST模块与PL模块构成任务型对话机器人中的对话管理(DM)模块,在该项目中界限并不十分清晰,在此情况下主要实现逻辑集中于modules.py文件中的semantic\_parser函数内。

由DST模块与PL模块构成任务型对话机器人中的对话管理(DM)模块,在该项目中界限并不十分清晰,在此情况下主要实现逻辑集中于modules.py文件中的semantic\_parser函数内。

学术界与工业界都有许多人致力于这一领域的问题探讨,在当前的研究热点中,其中一个主要的研究方向是通过强化学习的方法来进行策略的选择相关研究已有深入的成果

实现上述过程,需要完成以下几步工作

1)构建知识图谱作为底层数据支撑

用于构建知识图谱的数据集源自liuhuanyong在QABasedOnMedicaKnowledge eGraph项目中使用的医疗数据集。

一共8种实体 :药品、菜谱、食物、检查、科室、药企、疾病、症状,共计4万余个

11种实体关系

疾病与不可食用食物的关系
疾病适宜摄入的食物的关系
疾病推荐食用的食物的关系
疾病通用使用的药品的关系
疾病热门使用的药品的关系
疾病检查的重要依据
科室与其相关科室的关系
厂商生产该药物的企业与其产品的关系
症状与其临床表现之间的联系
病症可能导致的其他病症
涉及的科室与该疾病的临床定位有关联

对于缺乏知识图谱构建经验的同学而言,在面对结构化数据集的情况下,请不要低估或被吓倒于构建知识图谱这一项看似复杂又具挑战性的任务;其难点主要体现在……

  • 数据采集环节 ,从非结构化的文本资料 中获取系统化的数据元素 ,例如通过自然语言处理技术从网页内容中识别并提取实体信息(NER)及其间的关联规则
    • 构建图谱模型时 ,需完成概念建模(实体定义)、属性抽象(属性建模)以及关联规则设定(关系定义),这要求具备较深厚的专业领域知识以确保模型的科学性与完整性

在该项目中所涉及的数据集合具有结构性特点,在这一过程中涉及的所有实体、属性及关系都已经明确设定好。因此无需过于担心这一步骤的难度。

在实际业务领域中,搭建知识图谱的难易程度因具体的业务场景而异,并非通用标准适用。

2)分类模型1

该分类模型的主要目标是实现多意图识别任务。通过分析用户的query类型是否属于闲聊范畴来判断其对应的意图归属。作为本项目的初始阶段,该识别任务被视为第一次层次的意图划分。为了提高识别效果,在该阶段我们采用了LR算法与梯度提升决策树(GBDT)相结合的混合学习策略。

3)分类模型2

首先启动分类模型2,在系统中解析出包括定义、病因、治疗周期以及预防措施在内的13项医疗诊断目标。该系统采用基于预训练语言模型的多意图分类方法进行分析。

4)NER模型

在Medical_bot系统中,第二阶段主要依赖NER(命名实体识别)模型来识别和提取医疗领域相关的实体信息。即系统会从用户的输入数据中自动识别并提取出与知识图谱相匹配的实体名称。在此前讨论的基础上,在本项目的研究范围内共有8个主要的知识点。

然而,在大型项目环境中(如电商网站、社交平台等),实体数量级达上万级别(甚至更多)。传统的匹配算法在遇到不匹配情况时需进行回溯操作(即当当前路径无法满足条件时需要返回并尝试其他可能),导致运行效率较低。相比之下,在理想情况下(假设所有状态均为终态节点且不存在冲突),AC自动机具有线性时间复杂度O(n)(其中n表示用户输入字符串的长度)。

为此, 我们可以采用AC自动机配合NER(Named Entity Recognition)技术, 从用户输入中识别并提取所有涉及知识库实体的候选子串或最长候选子串. 在提取完成后, 综合AC自动机匹配结果与NER识别结果中的Top n高评分实体, 进行后续的链接操作.

本项目采用的就是AC自动机提取所有子串+NER实体识别的方式。

三、项目运行

为了方便大家实践,我把自己的代码上传到GitHub了

具体地址如下:KBQA-study 该资源相较于原先的代码实现进行了优化

  • 在代码中增加了注释说明
    • 更换了部分函数名称并调整了参数设置
      在与微信用户的沟通中使用itchat实现了初步的互动功能;然而由于本人无法直接连接自己的微信账号,在进一步探索过程中决定采用Sanic这一轻量级框架开发一个网页交互界面;尽管如此但我原本希望将该系统扩展至Telegram但由于时间限制目前这一计划仍处于搁置状态;值得注意的是具体的技术实现细节并非当前工作的核心重点 算法优化才是现阶段的关键任务。

我的运行环境:

Win10+16GB内存+Pycharm

要运行这个项目你需要做以下几项工作

第一步,下载需要的数据和模型

数据是必不可少的资源,在后续的研究过程中可以自行构建模型;模型在后期阶段能够被用来训练个人模型;获取下载链接请访问GitHub主页。

下载好后,把数据放到对应的文件夹下

目前在本环境中已安装了除Bert预训练文件外的其他内容。该文件体积较大。如需获取,请访问网络平台下载。

目前在本环境中已安装了除Bert预训练文件外的其他内容。该文件体积较大。如需获取,请访问网络平台下载。

第二步,构建知识图谱

1) 在自己电脑上安装Neo4j

参考:

2) 打开一个CMD,输入neo4j.bat console,启动服务

3) 在Pycharm中运行 build_kg 文件夹下的build_kg_utils.py 构建知识图谱

  • 这个过程耗时较长, 个人电脑通常需要约两小时完成. 若内存空间有限, 建议关闭不必要的程序或服务项.
    • 将系统中涉及的相关路径和账号参数进行本地化设置, 确保配置适合本地环境运行.

第三步,启动服务

1)启动意图识别模型服务和NER模型服务

启动命令在下面两个文件中

  • run_intent_recog_service.bat
  • run_ner_service.bat

通过快捷方式启动这两个文件并执行它们,在Linux系统中将它们转换为shell脚本后再执行,并完成操作后自动退出。

为何我的电脑在双击时总是闪退?如果你也有类似的经历,请尝试以下方法。

在PyCharm环境中启动两个终端窗口,并依次执行批处理脚本文件run_intent_recog_service.batrun_ner_service.bat中的相应命令

一般是报错了才会闪退,可以用这种方法查看报错信息,进行修改

2)启动知识图谱服务

如果你搭建好了知识图谱,并且未被关闭,则无需执行此步骤;如果服务被关闭,则需重新启动。

打开一个CMD,输入neo4j.bat console,启动服务

3)启动主程序

我自己新建了一个local.py的文件,在里面写了sanic的服务代码

你可以先尝试使用微信版本:

Pycharm 中打开1个Terminal,输入:python itchat_app.py

如果遇到连接问题时无法登录,请运行命令:python local.py;随后打开浏览器访问以下地址:[http://你的IP:12348/swagger/#/default](https://link.zhihu.com/?target=http%3A//192.168.0.224%3A12348 swagger %2F#/默认页面);即可通过此方式与机器人进行互动。

四、项目总结

就项目当前实现的程度而言,主要涉及到以下知识点

1)知识图谱的构建

  • 从结构化数据集中解析出所有的实体与关联信息,并生成三元组表示。
    • 在Neo4j平台中进行节点实例与边实例的创建,在这一步骤中,请确保您熟悉Neo4j的一些基本操作指令。

2)文本分类

文本分类在本项目中主要体现在两次意图识别上:

  • 第一次意图识别:通过LR算法与GBDT结合的多模型融合策略来判断用户的闲聊类别
  • 第二次意图识别:基于BERT语言模型与TextCNN结合的深度学习架构来实现对具体医疗诊断类别的识别

如果以学习的态度对待,则不能停留在项目中现有的内容层面。既然文本分类既是NLP入门任务也是该领域的重要分支,在完成好当前工作的同时还可以在本项目的基础上进行横向拓展。基于本项目的数据集尝试其他模型架构,并观察效果如何;也可以尝试其他领域的相关数据集进行研究分析。从而进一步掌握并巩固文本分类这一核心任务的知识和技能。

3)序列标注

  • 命名实体识别

本项目的命名实体识别部分主要运用了BiLSTM+CRF模型,并在此基础上作为辅助手段进行了改进。

  • 槽位填充

通常会在任务型机器人中进行槽位填充操作。其目的是用于从用户处获取相关信息。具体流程首先是识别意图中的各个槽位内容,并通过分析用户的输入数据进行实体识别工作。随后系统能够提取相应的槽位值,并将其纳入后续处理流程。需要注意的是这一过程本质上是一种序列标注问题。

之前阅读的各种资料大多多是阐述理论知识,并未涉及具体实现细节,在本次项目中算是对其中一些实现环节有了大致了解。研究的重点主要集中在config.py中的配置设置以及位于modules.py中的语义解析逻辑部分。回想起来,我曾使用过Rasa框架,在其domain文件中发现了一些相似的模式。整个domain文件实际上相当于一个大型字典结构,在存储意图类型和槽位信息方面功能显著。

看一下这个项目是怎么实现多轮问答的,以下内容节选自config.py 文件:

复制代码
 semantic_slot = {

    
     "定义":{
    
     "slot_list":["Disease"],
    
     "slot_values":None,
    
     "cql_template": "MATCH(p:疾病) WHERE p.name='{Disease}' RETURN p.desc",
    
     "reply_template": "'{Disease}'是这样的:\n",
    
     "ask_template": "您问的是 '{Disease}' 的定义吗?",
    
     "intent_strategy": "",
    
     "deny_response": "很抱歉没有理解你的意思呢~"
    
     },
    
     "病因":{
    
     "slot_list" : ["Disease"],
    
     "slot_values":None,
    
     "cql_template" : "MATCH(p:疾病) WHERE p.name='{Disease}' RETURN p.cause",
    
     "reply_template" : "'{Disease}' 疾病的原因是:\n",
    
     "ask_template" : "您问的是疾病 '{Disease}' 的原因吗?",
    
     "intent_strategy" : "",
    
     "deny_response":"您说的我有点不明白,您可以换个问法问我哦~"
    
     },
    
     "预防":{
    
     "slot_list" : ["Disease"],
    
     "slot_values":None,
    
     "cql_template" : "MATCH(p:疾病) WHERE p.name='{Disease}' RETURN p.prevent",
    
     "reply_template" : "关于 '{Disease}' 疾病您可以这样预防:\n",
    
     "ask_template" : "请问您问的是疾病 '{Disease}' 的预防措施吗?",
    
     "intent_strategy" : "",
    
     "deny_response":"额~似乎有点不理解你说的是啥呢~"
    
     },
    
 }

其中一项是关于医疗诊断的定义、病因及预防措施的系统性研究方案;每个方案都包含一个详细的数据库(字典),其键值对精准记录了与该诊断方案相关的各类信息;以"定义"这一项为例:

  • 槽位列表
复制代码
    "slot_list":["Disease"]
  • 槽值:被填充之后,value是一个字典,存着槽位列表中出现的槽位-槽位值
复制代码
    "slot_values":None
  • 图谱查询语句
复制代码
    "cql_template": "MATCH(p:疾病) WHERE p.name='{Disease}' RETURN p.desc",
  • 回复模板
复制代码
    "reply_template": "'{Disease}'是这样的:\n",
  • 澄清话术:意图置信度在0.4-.8之间是,会用此模板进行问题澄清
复制代码
    "ask_template": "您问的是 '{Disease}' 的定义吗?",
  • 回复策略
复制代码
    "intent_strategy": "",
  • 意图识别失败回复话术
复制代码
    "deny_response": "很抱歉没有理解你的意思呢~"

注意,在每个意图中都有一个'Disease'槽位,在开始阶段填入之后就可以持续地进行多轮对话,并且由于槽位填充机制能够继承上一阶段的信息

4)模型发布

分类模型2和NER模型各自采用接口方式进行服务提供。基于此,我们能够更好地了解各模型的发布情况。

该项目的核心内容是槽位填充环节,在此前对Rasa框架有实际操作经验的基础上,我对任务型对话机理有了更深入的掌握,并对其中涉及的人工智能技术设计不得不赞叹其创新性。

本项目可扩展的地方

在算法层面分析中,在NLP领域的主要任务中

目前主要采用知识图谱构建基础数据库,并对回答结果进行存储。建议将文本生成功能整合进来,在合理安排时间点,在必要时利用NLG模型自动生成并返回给用户相应的问题解答内容。至于具体调用NLG模型的时间节点,则由操作者自行决定。

下面介绍的是句子匹配 问题及其相关技术。这一概念也被称作句子关系判断 ,其核心在于通过选择合适的场景和数据集进行训练,并将它们整合应用到实际问题中去解决。具体的解决方案可以在以下文献中找到详细说明:21个经典深度学习句间关系模型|代码&技巧

这样看来, 一个问答项目就涵盖了知识图谱NLP四大任务, 对于学习者而言, 这是一个非常有帮助的实践机会

暂时写到这里,希望能帮助到有需要的人

如果文中有什么错误,欢迎指出来~

谢谢~

参考

  1. ^https://arxiv.org/abs/2105.04387



依托医疗知识图谱构建的互动平台知乎

GitHub - DeqianBai/KBQA-study: 以医疗知识图谱为基础构建的问题-答案系统

GitHub - z814081807/DeepNER: 本项目基于DeepNER框架,在天池中医药说明书实体识别挑战赛中取得冠军项目地位;采用先进的中文命名实体识别技术;结合BERT-CRF 与 BERT-SPAN 和 BERT-MRC三种模型实现精准识别;并基于Pytorch平台开发

分享吧

分享吧

分享吧

全部评论 (0)

还没有任何评论哟~