医药知识图谱自动问答系统实现,包括构建知识图谱、基于知识图谱的流水线问答以及前端实现。实体识别(基于词典+BERT_CRF)、实体链接(Sentence-BERT做匹配)、意图识别(基于提问词+领域词词典)。
在构建医药知识图谱和自动问答时,参考了项目^1。在构建医药知识图谱和问答系统上做了如下优化:
在建好知识图谱和问答系统后,增加前端交互和KG展示,用的是echarts的力引导图。实现参考项目^4。
neo4j-community-4.1.4 % bin/neo4j start
medical_knowledge_graph_app-master % python med_kg/manage.py runserver
img 功能界面图
kg/prepare_data 爬虫文件
kg/data/medical_rebuild.json 最终处理好的数据
kg/build_medicalgraph.py 创建neo4j图数据库
med_kg/el_model 实体链接模型
med_kg/el_model/embedding 疾病/药物/症状词典的词嵌入表示
med_kg/el_model/entity_linking.py 实体链接脚本
med_kg/med_kg django框架的视图和配置文件
med_kg/templates django框架的模版
med_kg/static 前端bootstrap文件
med_kg/ner_model 命名实体识别模型
med_kg/ner_model/models 命名实体识别模型模型代码
med_kg/ner_model/data 训练模型的数据
med_kg/ner_model/losses 训练模型的损失函数
med_kg/ner_model/outpus/1101medselfner-finetune 精调(训练好)的模型
med_kg/ner_model/prev_trained_model 放pytorch的预训练模型
med_kg/util 工具,冷启动
med_kg/Model 与neo4j图数据库交互的脚本
med_kg/MedModel 自动问答
med_kg/MedModel/question_classifier.py 意图识别脚本
med_kg/MedModel/question_parser.py 把识别出的提及词和意图转为查询语句的脚本
med_kg/MedModel/answer_search.py 查询图数据库返回答案
med_kg/MedModel/dict 领域词典
‘*’ 号表示原项目基础上变化的项
实体类型 | 中文含义 | 实体数量 | 举例 |
---|---|---|---|
Check | 诊断检查项目 | 3,353 | 支气管造影;关节镜检查 |
Department | 医疗科目 | 54 | 整形美容科;烧伤科 |
Disease | 疾病 | 8,807 | 血栓闭塞性脉管炎;胸降主动脉动脉瘤 |
Drug | 药品 | 3,828 | 京万红痔疮膏;布林佐胺滴眼液 |
Food | 食物 | 4,870 | 番茄冲菜牛肉丸汤;竹笋炖羊肉 |
Producer | 药品大类 | 17,201 | 通药制药青霉素V钾片;青阳醋酸地塞米松片 |
Symptom* | 疾病症状 | 4,377 | 乳腺组织肥厚;脑实质深部出血 |
Total | 总计 | 44,111 | 约4.4万实体量级 |
‘*’ 号表示原项目基础上变化的项
实体关系类型 | 中文含义 | 关系数量 | 举例 |
---|---|---|---|
belongs_to | 属于 | 8,844 | <妇科,属于,妇产科> |
common_drug | 疾病常用药品 | 14,649 | <阳强,常用,甲磺酸酚妥拉明分散片> |
do_eat | 疾病宜吃食物 | 22,238 | <胸椎骨折,宜吃,黑鱼> |
drugs_of | 药品在售药品 | 17,315 | <青霉素V钾片,在售,通药制药青霉素V钾片> |
need_check | 疾病所需检查 | 39,422 | <单侧肺气肿,所需检查,支气管造影> |
no_eat | 疾病忌吃食物 | 22,247 | <唇病,忌吃,杏仁> |
recommand_drug | 疾病推荐药品 | 59,467 | <混合痔,推荐用药,京万红痔疮膏> |
recommand_eat | 疾病推荐食谱 | 40,221 | <鞘膜积液,推荐食谱,番茄冲菜牛肉丸汤> |
has_symptom* | 疾病症状 | 99,492 | <早期乳腺癌,疾病症状,乳腺组织肥厚> |
acompany_with | 疾病并发疾病 | 12,029 | <下肢交通静脉瓣膜关闭不全,并发疾病,血栓闭塞性脉管炎> |
Total | 总计 | 294,149 | 约30万关系量级 |
属性类型 | 中文含义 | 举例 |
---|---|---|
name | 疾病名称 | 喘息样支气管炎 |
desc | 疾病简介 | 又称哮喘性支气管炎... |
cause | 疾病病因 | 常见的有合胞病毒等... |
prevent | 预防措施 | 注意家族与患儿自身过敏史... |
cure_lasttime | 治疗周期 | 6-12个月 |
cure_way | 治疗方式 | "药物治疗","支持性治疗" |
cured_prob | 治愈概率 | 95% |
easy_get | 疾病易感人群 | 无特定的人群 |
问句类型 | 中文含义 | 问句举例 | 说明 |
---|---|---|---|
disease_symptom | 疾病症状 | 乳腺癌的症状有哪些? | 不同类实体间关系 |
symptom_disease | 已知症状找可能疾病 | 老流鼻涕是什么毛病? | 不同类实体间关系 |
disease_cause | 疾病病因 | 为什么有的人会失眠? | 实体属性 |
disease_acompany | 疾病的并发症 | 失眠有哪些并发症? | 同类实体间关系 |
disease_not_food | 疾病需要忌口的食物 | 失眠的人不要吃啥? | 不同类实体间关系 |
disease_do_food | 疾病建议吃什么食物 | 耳鸣了吃点啥? | 不同类实体间关系 |
food_not_disease | 什么病最好不要吃某事物 | 哪些人最好不好吃蜂蜜? | 不同类实体间关系 |
food_do_disease | 食物对什么病有好处 | 鹅肉有什么好处? | 不同类实体间关系 |
disease_drug | 啥病要吃啥药 | 肝病要吃啥药? | 不同类实体间关系 |
drug_disease | 药品能治啥病 | 板蓝根颗粒能治啥病? | 不同类实体间关系 |
disease_check | 疾病需要做什么检查 | 脑膜炎怎么才能查出来? | 不同类实体间关系 |
check_disease | 检查能查什么病 | 全血细胞计数能查出啥来? | 不同类实体间关系 |
disease_prevent | 预防措施 | 怎样才能预防肾虚? | 实体属性 |
disease_lasttime | 治疗周期 | 感冒要多久才能好? | 实体属性 |
disease_cureway | 治疗方式 | 高血压要怎么治? | 实体属性 |
disease_cureprob | 治愈概率 | 白血病能治好吗? | 实体属性 |
disease_easyget | 疾病易感人群 | 什么人容易得高血压? | 实体属性 |
disease_desc | 疾病描述 | 糖尿病是什么? | 实体属性 |
disease_getprob(todo) | 患病概率 | 糖尿病的患病率有多高? | 实体属性 |
(1)提及识别:基于词典的匹配+基于BERT_CRF的NER,取二者较长的作为提及词。
(2)实体链接:基于SBERT的语义匹配,存储好词典的embedding,提及词和领域词典匹配,相似度top20的候选实体中结合重叠字,相似度top20的候选实体且与提及次的重叠字大于等于提及词长度的一半,认为是目标实体。
(3)意图识别:基于提问词+领域词典。比如提问“眼睛干涩是什么毛病?”中识别出提及词“symptom:眼睛干涩”以及疾病提问词“毛病”。则认为提问意图是symptom_disease:已知症状找可能疾病。
结合BERT和领域词典匹配两种方法得到query中的症状提及"鼻黏膜肿胀"。
用SBERT句对匹配得到症状提及"鼻黏膜肿胀"的目标实体"鼻粘膜肿胀"。
识别出问句中的一个或多个提及词,链接到对应的一个或多个kg实体,结合意图识别的结果返回query答案。
出现这个bug:
RuntimeError: Attempting to deserialize object on a CUDA device but torch.cuda.is_available() is False. If you are running on a CPU-only machine, please use torch.load with map_location=torch.device('cpu') to map your storages to the CPU.
参考^5,把./site-package/torch/serialization.py的load函数,用def load(f, map_location='cpu', pickle_module=pickle, **pickle_load_args):
代替def load(f, map_location=None, pickle_module=pickle, **pickle_load_args):