生物医学领域的关系抽取(多分类)利用循环神经网络加最大池组合模型
生物医学领域中的关系抽取其实就是多分类任务,利用有监督的深度学习模型进行训练并给出最终的实体关系;这是目前研究生自然语言处理领域中所研究的重要问题,也是一个科研硕果容易出的点,因为模型之间的合理组合就可以收获意料之外的效果,虽然效果有好有坏,发论文还是有一定困难的,还是对于那么想寻找一些新的idea想毕业的学生,这也是一个不错的毕业设计方向。(如果该方向或者类似方向的研究生想要以这个方向做毕业设计的可以加群128393770进行讨论研究)
在这里本博主将简单给出该模型的一种实现方式,并给出该模型的实现代码和结果语料,python实现环境为:
Python SciPy环境,Python 3以上版本。你必须使用tensorflow1.4.0。并已经安装了scikit-learn,Pandas,NumPy和Matplotlib等各种库。
目的:SemEval-2010任务(即有监督的多分类任务)
例:-
“ 碗里有苹果,梨和橘子。” → CONTENT-CONTAINER(梨,碗)
- “杯中盛着干人参茶。” → ENTITY-ORIGIN(茶,人参)
语义关系清单
- 原因 - 效应(CE):事件或对象导致效应(这些癌症是由辐射暴露引起的)
- 仪器 - 代理(IA):代理使用仪器(电话运营商)
- 产品 - 生产者(PP):生产者使产品存在(工厂生产西装)
- 内容容器(CC):一个物体被物理存储在空间划分的区域(一个充满蜂蜜的瓶子被称重)Hendrickx,Kim,Kozareva,Nakov,OS'eaghdha,Pad'o,'Pennacchiotti,Romano,Szpakowicz Task概述数据创建竞争结果和讨论语义关系清单(III)
- 实体原产地(EO):实体来自或源自原产地,例如,位置或材料(来自国外的信函)
- 实体 - 目的地(ED):实体正朝着目的地移动(男孩去睡觉)
- 组件 - 整体(CW):一个物体是一个较大整体的组成部分(我的公寓有一个大厨房)
- 成员集合(MC):成员构成集合的非功能部分(森林中有许多树)
- 消息主题(CT):一种书面或口头交流行为是关于一个话题的(讲座是关于语义的)
-
其他:如果上述九种关系都不适合。
数据集的分配
关系 | 训练数据 | 测试数据 | 总数据 |
---|---|---|---|
因果 | 1,003(12.54%) | 328(12.07%) | 1331(12.42%) |
仪表局 | 504(6.30%) | 156(5.74%) | 660(6.16%) |
产品生产者 | 717(8.96%) | 231(8.50%) | 948(8.85%) |
内容容器 | 540(6.75%) | 192(7.07%) | 732(6.83%) |
实体原产地 | 716(8.95%) | 258(9.50%) | 974(9.09%) |
实体目的地 | 845(10.56%) | 292(10.75%) | 1137(10.61%) |
组件的全 | 941(11.76%) | 312(11.48%) | 1253(11.69%) |
会员收集 | 690(8.63%) | 233(8.58%) | 923(8.61%) |
消息主题 | 634(7.92%) | 261(9.61%) | 895(8.35%) |
其他 | 1,410(17.63%) | 454(16.71%) | 1864(17.39%) |
总 | 8,000(100.00%) | 2,717(100.00%) | 10,717(100.00%) |
模型结构图:
- 双向RNN(Bi-RNN)用于实现左右上下文向量。
- 通过移位Bi-RNN的输出并连接指示上下文的开始的零状态来创建每个上下文向量
核心代码实现:
import tensorflow as tf class TRNN: def __init__(self, sequence_length, num_classes, vocab_size, text_embedding_size, context_embedding_size, cell_type, hidden_size, l2_reg_lambda=0.0): # Placeholders for input, output and dropout self.input_text = tf.placeholder(tf.int32, shape=[None, sequence_length], name='input_text') self.input_y = tf.placeholder(tf.float32, shape=[None, num_classes], name='input_y') self.dropout_keep_prob = tf.placeholder(tf.float32, name='dropout_keep_prob') l2_loss = tf.constant(0.0) text_length = self._length(self.input_text) # Embeddings self.W_text = tf.Variable(tf.random_uniform([vocab_size, text_embedding_size], -1.0, 1.0), name="W_text") self.embedded_chars = tf.nn.embedding_lookup(self.W_text, self.input_text) # Bidirectional(Left&Right) Recurrent Structure fw_cell = self._get_cell(context_embedding_size, cell_type) fw_cell = tf.nn.rnn_cell.DropoutWrapper(fw_cell, output_keep_prob=self.dropout_keep_prob) bw_cell = self._get_cell(context_embedding_size, cell_type) bw_cell = tf.nn.rnn_cell.DropoutWrapper(bw_cell, output_keep_prob=self.dropout_keep_prob) (self.output_fw, self.output_bw), states = tf.nn.bidirectional_dynamic_rnn(cell_fw=fw_cell, cell_bw=bw_cell, inputs=self.embedded_chars, sequence_length=text_length, dtype=tf.float32) shape = [tf.shape(self.output_fw)[0], 1, tf.shape(self.output_fw)[2]] self.c_left = tf.concat([tf.zeros(shape), self.output_fw[:, :-1]], axis=1, name="context_left") self.c_right = tf.concat([self.output_bw[:, 1:], tf.zeros(shape)], axis=1, name="context_right") self.x = tf.concat([self.c_left, self.embedded_chars, self.c_right], axis=2, name="x") embedding_size = text_embedding_size + 2*context_embedding_size W2 = tf.Variable(tf.random_uniform([embedding_size, hidden_size], -1.0, 1.0), name="W2") b2 = tf.Variable(tf.constant(0.1, shape=[hidden_size]), name="b2") self.y2 = tf.einsum('aij,jk->aik', self.x, W2) + b2 self.y3 = tf.reduce_max(self.y2, axis=1) W4 = tf.get_variable("W4", shape=[hidden_size, num_classes], initializer=tf.contrib.layers.xavier_initializer()) b4 = tf.Variable(tf.constant(0.1, shape=[num_classes]), name="b4") l2_loss += tf.nn.l2_loss(W4) l2_loss += tf.nn.l2_loss(b4) self.logits = tf.nn.xw_plus_b(self.y3, W4, b4, name="logits") self.predictions = tf.argmax(self.logits, 1, name="predictions") # Calculate mean cross-entropy loss losses = tf.nn.softmax_cross_entropy_with_logits(logits=self.logits, labels=self.input_y) self.loss = tf.reduce_mean(losses) + l2_reg_lambda * l2_loss # Accuracy correct_predictions = tf.equal(self.predictions, tf.argmax(self.input_y, axis=1)) self.accuracy = tf.reduce_mean(tf.cast(correct_predictions, tf.float32), name="accuracy") def _get_cell(hidden_size, cell_type): if cell_type == "vanilla": return tf.nn.rnn_cell.BasicRNNCell(hidden_size) elif cell_type == "lstm": return tf.nn.rnn_cell.BasicLSTMCell(hidden_size) elif cell_type == "gru": return tf.nn.rnn_cell.GRUCell(hidden_size) else: print("ERROR: '" + cell_type + "' is a wrong cell type !!!") return None # Length of the sequence data @staticmethod def _length(seq): relevant = tf.sign(tf.abs(seq)) length = tf.reduce_sum(relevant, reduction_indices=1) length = tf.cast(length, tf.int32) return length def last_relevant(seq, length): batch_size = tf.shape(seq)[0] max_length = int(seq.get_shape()[1]) input_size = int(seq.get_shape()[2]) index = tf.range(0, batch_size) * max_length + (length - 1) flat = tf.reshape(seq, [-1, input_size]) return tf.gather(flat, index) 实验项目目录结构表:
实验结果:precision:72.8 Recall:63.42 F score:65.32
如果大家对该项目感兴趣可以找博主索要完整代码,该实验是一个较大项目,适合研究生包括本科生毕业使用!