数据描述
数据集是关于医疗诊断的,json格式存储,一个样本如下,分别包含text和spo_list,spo_list包含一个或多个对象。spo_list里的predicate是要提取的关系,subject是头实体,object是尾实体。
{"text": "慢性胰腺炎@ 自身免疫性胰腺炎的 JPS 诊断标准 要求必须在超声、CT 和/或 MRI 中发现以下影像学诊断结果: * 主胰管狭窄伴管壁不规则改变以及 * 弥漫性或局灶性胰腺肿胀, 上述影像学表现需同时合并1项下述改变: * 自身抗体:血清γ球蛋白、IgG、IgG4升高或自身抗体阳性(例如抗核抗体和类风湿因子) * 组织学:特征性胰腺小叶间纤维化及胰管周围淋巴细胞和浆细胞浸润,偶尔可见淋巴滤泡。慢性胰腺炎@ 应用上述诊断标准时,应注意排除胰腺或胆管恶性肿瘤。",
"spo_list": [
{"Combined": true,
"predicate": "鉴别诊断",
"subject": "自身免疫性胰腺炎",
"subject_type": "疾病",
"object": {"@value": "胆管恶性肿瘤"},
"object_type": {"@value": "疾病"}},
{"Combined": true,
"predicate": "影像学检查",
"subject": "自身免疫性胰腺炎",
"subject_type": "疾病",
"object": {"@value": "超声"},
"object_type": {"@value": "检查"}},
{"Combined": true,
"predicate": "影像学检查",
"subject": "自身免疫性胰腺炎",
"subject_type": "疾病",
"object": {"@value": "CT"},
"object_type": {"@value": "检查"}}]
}
数据量为1.4+万,44类关系。
模型架构
关系抽取的思路是将任务转化成分类任务来做,首先将label抽取出来,然后采用分类模型训练,然后根据输入文本预测对应的关系。采用ALBERT预训练模型+bert4keras框架。
实体识别的思路是采用MRC方式,构建query+passage,来预测start和end位置。框架是ELECTRA预训练模型+bert4keras。
bert4keras用的是0.8.4版本。
数据预处理
关系抽取属于多标签分类任务,一个样本对应一个多标签labels。处理完的一个样本如下所示,由text + fengefu + label组成,label用id表示,训练的时候再根据fengefu拆分数据。
样本1:慢性胰腺炎@ 自身免疫性胰腺炎的 JPS 诊断标准 要求必须在超声、CT 和/或 MRI 中发现以下影像学诊断结果: * 主胰管狭窄伴管壁不规则改变以及 * 弥漫性或局灶性胰腺肿胀, 上述影像学表现需同时合并1项下述改变: * 自身抗体:血清γ球蛋白、IgG、IgG4升高或自身抗体阳性(例如抗核抗体和类风湿因子) * 组织学:特征性胰腺小叶间纤维化及胰管周围淋巴细胞和浆细胞浸润,偶尔可见淋巴滤泡。慢性胰腺炎@ 应用上述诊断标准时,应注意排除胰腺或胆管恶性肿瘤。fengefu25 28
实体识别属于MRC任务,query需要自己构建,passage就是text。实体识别的数据和关系抽取有所不一样,关系抽取的一个样本就是一对多的关系,而实体识别的样本对应多个关系,关系还可以重复,但相同关系的头实体和尾实体都不一样。所以将具有多个关系的样本转化成多个样本,而将这个关系作为先验知识放在query中,所以实体识别的任务的数据集将比关系抽取大很多。上述样本处理完如下所示,由query +fengefu+text+fengefu+start_id+end_id
样本2:根据鉴别诊断关系,找出疾病fengefu慢性胰腺炎@ 自身免疫性胰腺炎的 JPS 诊断标准 要求必须在超声、CT 和/或 MRI 中发现以下影像学诊断结果: * 主胰管狭窄伴管壁不规则改变以及 * 弥漫性或局灶性胰腺肿胀, 上述影像学表现需同时合并1项下述改变: * 自身抗体:血清γ球蛋白、IgG、IgG4升高或自身抗体阳性(例如抗核抗体和类风湿因子) * 组织学:特征性胰腺小叶间纤维化及胰管周围淋巴细胞和浆细胞浸润,偶尔可见淋巴滤泡。慢性胰腺炎@ 应用上述诊断标准时,应注意排除胰腺或胆管恶性肿瘤。fengefu7 225fengefu715 231
样本3:根据影像学检查关系,找出疾病、检查 fengefu慢性胰腺炎@ 自身免疫性胰腺炎的 JPS 诊断标准 要求必须在超声、CT 和/或 MRI 中发现以下影像学诊断结果: * 主胰管狭窄伴管壁不规则改变以及 * 弥漫性或局灶性胰腺肿胀, 上述影像学表现需同时合并1项下述改变: * 自身抗体:血清γ球蛋白、IgG、IgG4升高或自身抗体阳性(例如抗核抗体和类风湿因子) * 组织学:特征性胰腺小叶间纤维化及胰管周围淋巴细胞和浆细胞浸润,偶尔可见淋巴滤泡。慢性胰腺炎@ 应用上述诊断标准时,应注意排除胰腺或胆管恶性肿瘤。fengefu7 130 7 195fengefu15 136 15 199
关系抽取步骤
step1:将样本1的数据按照分隔符切分,按照tuple(text,label)的格式写成list。
step2:将list输入子类dataGenerator。bert4keras的DataGenerator可以数据输出为适应bert格式的数据生成器,包含(token_id,segment_id,mask_id)。
step3:加载ALBERT预训练模型。
step4:在albert模型后面接全连接层,单元数为类别个数44,注意激活函数为sigmoid。
step5:用keras的compile函数打包模型参数,并且用fit_generator函数训练,在每个epoch结束时输出f1_score。
step6:预测就是按照分类任务的套路做。
实体识别步骤
step1:将样本2、3的数据按照分隔符切分,按照tuple(query,text,start_idx,end_idx)的格式写成list。
紫色部分便是实体。头实体和尾实体分别同onehot向量表示,每个样本结尾都有结束标志符。query部分都将不参与loss计算。
step3:加载ELECTRA预训练模型。
step4:在electra模型后面接两个全连接层,start和end各接一个,单元数分别为2。每个位置的都将看成是一个二分类,多少个text_id便有多少个二分类。
step6:定义f1_score,首先,因为start和end位置是分别预测的,先将两个合并起来;然后,加总预测值和实际值都为1的个数,分别除以预测值和实际值为1的个数,得到precision,recall,进而得到f1。
step7:用keras的compile函数打包模型参数,并且用fit_generator函数训练,在每个epoch结束时输出f1_score,precision,recall。
step8:分别对start位置和end位置,然后将text中对应的实体提取出来。
问题
关系抽取和实体识别是分成两个任务来做的,二者不存在什么交互关系。实践结果中,关系分类f1_score可以达到60%,实体识别80%多。关系分类f1_score的结果不是很好,查看了类别的样本数量分布,发现不均衡,估计是由此引起的。
解决办法
分别采用了自定义带权重的损失函数和focal_loss(),自定义的函数能够将f1_score提升10%,focal_loss()提升7%。