700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 天池下的瑞金医院MMC人工智能辅助构建知识图谱

天池下的瑞金医院MMC人工智能辅助构建知识图谱

时间:2018-04-29 15:43:15

相关推荐

天池下的瑞金医院MMC人工智能辅助构建知识图谱

浅谈知识图谱------天池下的瑞金医院MMC人工智能辅助构建知识图谱

前言数据说明问题网络模型和效果展示代码实体的定义和处理句子的切分和处理代码和数据集:

前言

知识图谱是个很大的概念,可惜我没数据,借用瑞金医院的数据集,来谈下命名识别。

数据说明

数据使用 brat 进行标注,每个 .txt 文件对应一个 .ann 标注文件。

txt文件对应一篇糖尿病下的论文

ann文件有3列,以 \t 分隔,第一列为实体编号,第二列为实体类别,第三列为实体位置信息。实体位置信息共3列, 以空格分隔,分别代表实体的开始位置,结束位置,实体文本

问题

这里我引用冠军队伍的代码,他们当时所面临的问题如下:

(1)他们是对一篇文章去做实体标注,文章的字数可能很长(几千到上万字),不可能直接输入到一个 RNN 中;

(2)样本中文章可能由于格式转换的一些原因,没有一个很好的句子边界,甚至一个词汇当中存在换行符 \n 或者句号 的情况,因此用换行 符或者句号去切割句子不一定合适。

(3)如果按照固定窗口大小的滑动窗口去切句子,刚好把一个实体切分成2个部分怎么办?

中文文本,面临是否要分词的选择;

下面是他们的解决方案:

网络模型和效果展示

网络模型为了便于上下文的关联采用了双向的lstm,为了使滑动的时候不丢到相关联的词语采用了一层CRF,作为最后最后一层的预测。

代码

代码主要分为三个部分,实体的定义和处理、句子的切分和处理、模型的搭建,除此之外还有预测评估的部分

实体的定义和处理

class Entity(object):def __init__(self, ent_id, category, start_pos, end_pos, text):self.ent_id = ent_idself.category = categoryself.start_pos = start_posself.end_pos = end_posself.text = textdef __gt__(self, other):return self.start_pos > other.start_posdef offset(self, offset_val):return Entity(self.ent_id,self.category,self.start_pos + offset_val,self.end_pos + offset_val,self.text)def __repr__(self):return '({}, {}, ({}, {}), {})'.format(self.ent_id,self.category,self.start_pos,self.end_pos,self.text)

class Entities(object):def __init__(self, ents):self.ents = sorted(ents)self.ent_dict = dict(zip([ent.ent_id for ent in ents], ents))def __getitem__(self, key):if isinstance(key, int) or isinstance(key, slice):return self.ents[key]else:return self.ent_dict.get(key, None)def offset(self, offset_val):ents = [ent.offset(offset_val) for ent in self.ents]return Entities(ents)def vectorize(self, vec_len, cate2idx):res_vec = np.zeros(vec_len, dtype=int)for ent in self.ents:res_vec[ent.start_pos: ent.end_pos] = cate2idx[ent.category]return res_vecdef find_entities(self, start_pos, end_pos):res = []for ent in self.ents:if ent.start_pos > end_pos:breaksp, ep = (max(start_pos, ent.start_pos), min(end_pos, ent.end_pos))if ep > sp:new_ent = Entity(ent.ent_id, ent.category, sp, ep, ent.text[:(ep - sp)])res.append(new_ent)return Entities(res)def merge(self):merged_ents = []for ent in self.ents:if len(merged_ents) == 0:merged_ents.append(ent)elif (merged_ents[-1].end_pos == ent.start_pos andmerged_ents[-1].category == ent.category):merged_ent = Entity(ent_id=merged_ents[-1].ent_id,category=ent.category,start_pos=merged_ents[-1].start_pos,end_pos=ent.end_pos,text=merged_ents[-1].text + ent.text)merged_ents[-1] = merged_entelse:merged_ents.append(ent)return Entities(merged_ents)

句子的切分和处理

data_dir = 'ruijin_round1_train2_1022/'ent2idx = dict(zip(ENTITIES, range(1, len(ENTITIES) + 1)))idx2ent = dict([(v, k) for k, v in ent2idx.items()])# print(idx2ent)docs = Documents(data_dir=data_dir)# ShuffleSplit() 随机排列交叉验证,生成一个用户给定数量的独立的训练/测试数据划分。样例首先被打散然后划分为一对训练测试集合。# n_splits:划分训练集、测试集的次数,默认为10# test_size: 测试集比例或样本数量,# random_state:随机种子值,默认为None,可以通过设定明确的random_state,使得伪随机生成器的结果可以重复。rs = ShuffleSplit(n_splits=1, test_size=20, random_state=)train_doc_ids, test_doc_ids = next(rs.split(docs))train_docs, test_docs = docs[train_doc_ids], docs[test_doc_ids]num_cates = max(ent2idx.values()) + 1sent_len = 64vocab_size = 3000emb_size = 100sent_pad = 10sent_extrator = SentenceExtractor(window_size=sent_len, pad_size=sent_pad)train_sents = sent_extrator(train_docs)test_sents = sent_extrator(test_docs)train_data = Dataset(train_sents, cate2idx=ent2idx)train_data.build_vocab_dict(vocab_size=vocab_size)test_data = Dataset(test_sents, word2idx=train_data.word2idx, cate2idx=ent2idx)

class Sentence(object):"""定义被切分的句子的类:text:句子的文本doc_id:句子所述文档idoffset:句子相对文档的偏移距离ents:句子包含的实体列表"""def __init__(self, doc_id, offset, text, ents):self.text = textself.doc_id = doc_idself.offset = offsetself.ents = entsdef __repr__(self):"""内部魔法函数:以text显示类:return:"""return self.textdef __gt__(self, other):#内部魔法函数:按类的offset偏移距离对类进行排序return self.offset > other.offsetdef __getitem__(self, key):"""内部魔法函数:预测结果评估时,去除句子两端延申的部分:param key::return:"""if isinstance(key, int):return self.text[key]if isinstance(key, slice):text = self.text[key]start = key.start or 0stop = key.stop or len(self.text)if start < 0:start += len(self.text)if stop < 0:stop += len(self.text)#改变实体相对于句子的偏移距离ents = self.ents.find_entities(start, stop).offset(-start)#改变句子相对于文档的偏移距离offset = self.offset + startreturn Sentence(self.doc_id, offset, text, ents)def _repr_html_(self):"""内部函数:网页显示不同的实体以不同的颜色区分:return:"""ents = []for ent in self.ents:ents.append({'start': ent.start_pos,'end': ent.end_pos,'label': ent.category})ex = {'text': self.text, 'ents': ents, 'title': None, 'settings': {}}return displacy.render(ex,style='ent',options={'colors': COLOR_MAP},manual=True,minify=True)class SentenceExtractor(object):#句子切分器,窗口为windows,两端分别延申pad_sizedef __init__(self, window_size=50, pad_size=10):self.window_size = window_sizeself.pad_size = pad_sizedef extract_doc(self, doc):#句子切分函数,切分的时候注意每个切分的句子相对于文档的偏移距离,预测的时候还需要还原num_sents = math.ceil(len(doc.text) / self.window_size)doc = doc.pad(pad_left=self.pad_size, pad_right=num_sents * self.window_size - len(doc.text) + self.pad_size)sents = []for cur_idx in range(self.pad_size, len(doc.text) - self.pad_size, self.window_size):sent_text = doc.text[cur_idx - self.pad_size: cur_idx + self.window_size + self.pad_size]ents = []for ent in doc.ents.find_entities(start_pos=cur_idx - self.pad_size,end_pos=cur_idx + self.window_size + self.pad_size):ents.append(ent.offset(-cur_idx + self.pad_size))sent = Sentence(doc.doc_id,offset=cur_idx - 2 * self.pad_size,text=sent_text,ents=Entities(ents))sents.append(sent)return sentsdef __call__(self, docs):#内部函数:将类当成函数形式的调用sents = []for doc in docs:sents += self.extract_doc(doc)return sents

模型的构建

def build_lstm_crf_model(num_cates, seq_len, vocab_size, model_opts=dict()):opts = {'emb_size': 256,'emb_trainable': True,'emb_matrix': None,'lstm_units': 256,'optimizer': keras.optimizers.Adam()}opts.update(model_opts)input_seq = Input(shape=(seq_len,), dtype='int32')if opts.get('emb_matrix') is not None:embedding = Embedding(vocab_size, opts['emb_size'], weights=[opts['emb_matrix']],trainable=opts['emb_trainable'])else:embedding = Embedding(vocab_size, opts['emb_size'])x = embedding(input_seq)lstm = LSTM(opts['lstm_units'], return_sequences=True)x = Bidirectional(lstm)(x)crf = CRF(num_cates, sparse_target=True)output = crf(x)model = Model(input_seq, output)pile(opts['optimizer'], loss=crf.loss_function, metrics=[crf.accuracy])return model

代码和数据集:

我把代码和数据集打包了

链接:/s/1mvjPuoGRChTpIqCYrLB6VA

提取码:z9tz

复制这段内容后打开百度网盘手机App,操作更方便哦–来自百度网盘超级会员V3的分享

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。