目录
引言
中文医学知识图谱(Chinese Medical Knowledge Graph, CMeKG)是利用自然语言处理与文本挖掘技术,基于大规模医学文本数据,以人机结合的方式研发的中文医学知识图谱。
此项目中主要模型工具包括:医学实体识别和医学关系抽取。项目源码地址
一、模型定义与下载
由于依赖和训练好的的模型较大,将模型放到了百度网盘中,链接如下,按需下载。
命名实体识别(Named Entity Recognition,NER),是指识别文本中具有特定意义的实体,主要包括人名、地名、机构名、专有名词等,以及时间、数量、货币、比例数值等文字。即用专有名词(名称)标识的事物,一个命名实体一般代表唯一一个具体事物个体,预测文本中具有特定意义的实体。
NER:链接:https://pan.baidu.com/s/16TPSMtHean3u9dJSXF9mTw 密码:shwh
关系抽取(Relation Extraction, RE)是指若有两个存在着关系的实体,将两个实体分别成为主体和客体,那么关系抽取就是在非结构或半结构化数据中找出主体与客体之间存在的关系,并将其表示为实体关系三元组抽取(主体Subject,谓语Predicate,客体Object),即通过NER得到了实体之后,预测任意两个实体存在怎样的关系。
RE:链接:https://pan.baidu.com/s/1cIse6JO2H78heXu7DNewmg 密码:4s6k
二、依赖库和配置文件
依赖库代码如下 import:
import gc # 用于释放不再使用的内存资源
import json # 用于处理 JSON 格式的数据
import random # 用于模型训练时数据集的随机化
import re # 用于文本数据的预处理,去除特殊字符或提取特定模式的信息
import time # 用于记录训练时间
from itertools import cycle # 用于循环遍历数据集,确保每个样本都能被处理到
import numpy as np # 通常与PyTorch一起使用,用于处理数值数据和数组
import torch # 提供张量操作、模型定义、梯度计算等功能
import torch.nn as nn # PyTorch中的神经网络模块,用于定义和训练神经网络模型
# 来自 Hugging Face Transformers 库的模块,用于处理基于 BERT 模型的自然语言处理任务。BertTokenizer 用于对文本进行分词,BertModel 是预训练的 BERT 模型,而 AdamW 是一种优化器,常用于调整模型参数以最小化损失函数。
from transformers import BertTokenizer, BertModel, AdamW
import warnings
warnings.filterwarnings('ignore') # 去掉红色的FutureWarning警告提示
配置文件代码如下 config:
class config:
"""
配置类,包含模型训练和运行时的参数
"""
batch_size = 1 # 批处理大小(根据自己电脑配置进行修改)
max_seq_len = 256 # 最大序列长度256个字符
num_p = 23 # 关系种类数(数据中自定义)
learning_rate = 1e-5 # 学习率
EPOCH = 2 # 训练轮次
# 文件路径
PATH_SCHEMA = "/predicate.json" # 关系种类文件路径
PATH_TRAIN = '/train_example.json' # 训练数据文件路径
PATH_BERT = "/bert_model/config.json" # BERT模型文件夹路径
PATH_MODEL = "/model_re.pkl" # 训练好的关系抽取模型文件,包含了模型参数、优化器参数等
PATH_SAVE = '/save' # 模型保存路径
tokenizer = BertTokenizer.from_pretrained("/bert_model/vocab.txt")
id2predicate = {} # 关系id到名称的映射
predicate2id = {} # 关系名称到id的映射
三、数据训练过程
训练数据过程代码如下:
def run_train():
"""
训练数据过程
"""
load_schema(config.PATH_SCHEMA) # 调用load_schema()函数,读取predicate.json
train_path = config.PATH_TRAIN # 表示训练数据的路径,读取train_example.json
all_data = load_data(train_path) # 加载训练数据,返回包含数据和标签的列表。调用load_data()函数,读取train_example.json所有数据
random.shuffle(all_data) # 打乱训练数据的顺序,以增加模型的泛化性能
idx = int(len(all_data) * 0.8) # 计算训练集和验证集的分割点,8:2划分训练集和验证集,idx = 19
train_data = all_data[:idx] # 获取训练集,即前80%的数据,随机的19个训练集
valid_data = all_data[idx:] # 获取验证集,即剩余20%的数据,剩下的5个验证集
# train训练
train_data_loader = IterableDataset(train_data, True) # 创建可迭代的数据加载器,用于训练模型,调用IterableDataset()函数
num_train_data = len(train_data) # 获取训练数据的数量,num_train_data = 19
checkpoint = torch.load(config.PATH_MODEL) # 加载预训练的模型的检查点,包含了模型参数、优化器参数等,读取model_re.pkl
model4s = Model4s() # 创建用于预测主体的模型,调用Model4s()函数
model4s.load_state_dict(checkpoint['model4s_state_dict']) # 加载预训练主体预测模型的参数
model4po = Model4po() # 创建用于计算主体之间关系的模型,调用Model4po()函数
model4po.load_state_dict(checkpoint['model4po_state_dict']) # 加载预训练关系计算模型的参数
# 模型学习与迭代的权重衰减策略
param_optimizer = list(model4s.named_parameters()) + list(model4po.named_parameters())
no_decay = ['bias', 'LayerNorm.bias', 'LayerNorm.weight']
optimizer_grouped_parameters = [
{'params': [p for n, p in param_optimizer if not any(nd in n for nd in no_decay)], 'weight_decay': 0.01},
{'params': [p for n, p in param_optimizer if any(nd in n for nd in no_decay)], 'weight_decay': 0.0}
]
lr = config.learning_rate
optimizer = AdamW(optimizer_grouped_parameters, lr=lr) # 构建模型学习与迭代的权重衰减策略,配置优化器AdamW
optimizer.load_state_dict(checkpoint['optimizer_state_dict']) # 加载预训练优化器的参数
checkpoint = train(train_data_loader, model4s, model4po, optimizer) # 调用train()函数,,并获取训练后的检查点
del train_data # 删除训练数据变量,释放内存
gc.collect() # 释放不再使用的内存
model_path = config.PATH_SAVE # 保存训练后的模型检查点
torch.save(checkpoint, model_path)
print('saved!')
model4s.eval() # 将模型设置为评估模式,用于验证
model4po.eval()
f1, precision, recall = evaluate(valid_data, True, model4s, model4po) # 调用 evaluate() 函数对验证集进行评估,计算 F1 值、精确度和召回率
print('f1: %.5f, precision: %.5f, recall: %.5f' % (f1, precision, recall))
1、关系类别加载过程
列出来所有的关系及其对应的id,代码如下
def load_schema(path):
"""
列出来的所有关系的数量和类别(自己做项目可以自定义predicate.josn文件)及其对应的id
"""
with open(path, 'r', encoding='utf-8', errors='replace') as f:
# 从文件中加载关系数据,data为一个字典,包含关系类别和对应数量
data = json.load(f) # data = {'相关疾病': 12410, '相关症状': 10880, '临床表现': 94657, '检查': 8543, '用法用量': 10914, ...}
# 获取关系类别列表,predicate为所有关系类别的集合
predicate = list(data.keys()) # predicate = ['相关疾病','相关症状', '临床表现', '检查', '用法用量',...]
# 创建一个字典,用于将关系类别predicate映射为对应的id
prediction2id = {} # prediction2id = {'相关疾病': 0,'相关症状': 1, '临床表现': 2, '检查': 3, '用法用量': 4,...]
# 创建一个字典,用于将id映射回关系类别predicate
id2predicate = {} # id2predicate = {0: '相关疾病',1: '相关症状', 2: '临床表现', 3: '检查',4: '用法用'量,...}
# 遍历关系类别列表
for i in range(len(predicate)): # 将关系类别映射为id,建立关系类别到id的映射,i = 22
prediction2id[predicate[i]] = i # 将关系类别映射为id,建立关系类别到id的映射
id2predicate[i] = predicate[i] # 将id映射回关系类别,建立id到关系类别的映射
num_p = len(predicate) # 获取关系类别的数量,即总共有多少种关系,num_p = 23
config.prediction2id = prediction2id # 将关系类别到id的映射存储在配置文件中
config.id2predicate = id2predicate # 将id到关系类别的映射存储在配置文件中
config.num_p = num_p # 将关系类别的数量存储在配置文件中
2、数据加载过程
加载数据代码如下:
def load_data(path): # 定义了加载数据的函数,接受一个文件路径参数,path = 'train_example.json'
"""
加载数据:把输入数据和spo三元组放到字典当中
"""
text_spos = [] # 初始化一个空列表,用于存储每个样本的文本和对应的spo三元组
with open(path, 'r', encoding='utf-8', errors='replace') as f:
data = json.load(f) # 从文件中加载JSON格式的数据,存储在data变量中
# data =
# [
# {
# "text": "12小时尿沉渣计数的相关疾病:单纯型尿路感染,妊娠合并急性膀胱炎,慢性肾炎,狼疮性肾炎,急性膀胱炎12小时尿沉渣计数的相关症状是高血压,男子性功能障碍,蛋白尿,血尿,水肿,排尿困难及尿潴留,尿频伴尿急和尿痛",
# "spo_list": [
# [
# "12小时尿沉渣计数",
# "相关疾病",
# "单纯型尿路感染"
# ],
# [
# "12小时尿沉渣计数",
#

博客围绕中文医学知识图谱展开,介绍主要模型工具为医学实体识别和医学关系抽取。阐述模型定义与下载方式,给出依赖库和配置文件代码。详细说明数据训练各过程及代码,最后展示程序运行结果,包括加载模型、提取命名实体及其关系等。
最低0.47元/天 解锁文章
1214





