众所周知,通过Bilstm已经可以实现分词或命名实体标注了,同样地单独的CRF也可以很好的实现。既然LSTM都已经可以预测了,为啥要搞一个LSTM+CRF的hybrid model? 因为单独LSTM预测出来的标注可能会出现(I-Organization->I-Person,B-Organization ->I-Person)这样的问题序列。

但这种错误在CRF中是不存在的,因为CRF的特征函数的存在就是为了对输入序列观察、学习各种特征,这些特征就是在限定窗口size下的各种词之间的关系。

将CRF接在LSTM网络的输出结果后,让LSTM负责在CRF的特征限定下,依照新的loss function,学习出新的模型。

基于字的模型标注:

假定我们使用Bakeoff-3评测中所采用的的BIO标注集,即B-PER、I-PER代表人名首字、人名非首字,B-ORG、I-ORG代表组织机构名首字、组织机构名非首字,O代表该字不属于命名实体的一部分

  • B-Person
  • I- Person
  • B-Organization
  • I-Organization
  • O

加入CRF layer对LSTM网络输出结果的影响

为直观的看到加入后的区别我们可以借用网络中的图来表示:其中\(x\)表示输入的句子,包含5个字分别用\(w_1\),\(w_2\),\(w_3\),\(w_4\),\(w_5\)表示

**没有CRF layer的网络示意图 **

含有CRF layer的网络输出示意图

上图可以看到在没有CRF layer的情况下出现了 B-Person->I-Person 的序列,而在有CRF layer层的网络中,我们将 LSTM 的输出再次送入CRF layer中计算新的结果。而在CRF layer中会加入一些限制,以排除可能会出现上文所提及的不合法的情况

CRF loss function

CRF loss function 如下:

Loss Function = \(\frac{P_{RealPath}}{P_1 + P_2 + … + P_N}\)

主要包括两个部分Real path score 和 total path scroe

1、Real path score

\(P_{RealPath}\) =\(e^{S_i}\)

因此重点在于求出:

\(S_i\) = EmissionScore + TransitionScore

EmissionScore=\(x_{0,START}+x_{1,B-Person}+x_{2,I-Person}+x_{3,O}+x_{4,B-Organization}+x_{5,O}+x_{6,END}\)

因此根据转移概率和发射概率很容易求出\(P_{RealPath}\)

2、total score

total scroe的计算相对比较复杂,可参看https://createmomo.github.io/2017/11/11/CRF-Layer-on-the-Top-of-BiLSTM-5/

实现代码(keras版本)

1、搭建网络模型

使用2.1.4版本的keras,在keras版本里面已经包含bilstm模型,但crf的loss function还没有,不过可以从keras contribute中获得,具体可参看:https://github.com/keras-team/keras-contrib

构建网络模型代码如下:

  1. model = Sequential()
  2. model.add(Embedding(len(vocab), EMBED_DIM, mask_zero=True)) # Random embedding
  3. model.add(Bidirectional(LSTM(BiRNN_UNITS // 2, return_sequences=True)))
  4. crf = CRF(len(chunk_tags), sparse_target=True)
  5. model.add(crf)
  6. model.summary()
  7. model.compile('adam', loss=crf.loss_function, metrics=[crf.accuracy])

2、清洗数据

清晰数据是最麻烦的一步,首先我们采用网上开源的语料库作为训练和测试数据。语料库中已经做好了标记,其格式如下:

月 O

油 O

印 O

的 O

《 O

北 B-LOC

京 I-LOC

文 O

物 O

保 O

存 O

保 O

管 O

语料库中对每一个字分别进行标记,比较包括如下几种:

  1. 'O', 'B-PER', 'I-PER', 'B-LOC', 'I-LOC', "B-ORG", "I-ORG"

分别表示,其他,人名第一个,人名非第一个,位置第一个,位置非第一个,组织第一个,非组织第一个

  1. train = _parse_data(open('data/train_data.data', 'rb'))
  2. test = _parse_data(open('data/test_data.data', 'rb'))
  3. word_counts = Counter(row[0].lower() for sample in train for row in sample)
  4. vocab = [w for w, f in iter(word_counts.items()) if f >= 2]
  5. chunk_tags = ['O', 'B-PER', 'I-PER', 'B-LOC', 'I-LOC', "B-ORG", "I-ORG"]
  6. # save initial config data
  7. with open('model/config.pkl', 'wb') as outp:
  8. pickle.dump((vocab, chunk_tags), outp)
  9. train = _process_data(train, vocab, chunk_tags)
  10. test = _process_data(test, vocab, chunk_tags)
  11. return train, test, (vocab, chunk_tags)

3、训练数据

在处理好数据后可以训练数据,本文中将batch-size=16获得较为高的accuracy(99%左右),进行了10个epoch的训练。

  1. import bilsm_crf_model
  2. EPOCHS = 10
  3. model, (train_x, train_y), (test_x, test_y) = bilsm_crf_model.create_model()
  4. # train model
  5. model.fit(train_x, train_y,batch_size=16,epochs=EPOCHS, validation_data=[test_x, test_y])
  6. model.save('model/crf.h5')

4、验证数据

  1. import bilsm_crf_model
  2. import process_data
  3. import numpy as np
  4. model, (vocab, chunk_tags) = bilsm_crf_model.create_model(train=False)
  5. predict_text = '中华人民共和国国务院总理周恩来在外交部长陈毅的陪同下,连续访问了埃塞俄比亚等非洲10国以及阿尔巴尼亚'
  6. str, length = process_data.process_data(predict_text, vocab)
  7. model.load_weights('model/crf.h5')
  8. raw = model.predict(str)[0][-length:]
  9. result = [np.argmax(row) for row in raw]
  10. result_tags = [chunk_tags[i] for i in result]
  11. per, loc, org = '', '', ''
  12. for s, t in zip(predict_text, result_tags):
  13. if t in ('B-PER', 'I-PER'):
  14. per += ' ' + s if (t == 'B-PER') else s
  15. if t in ('B-ORG', 'I-ORG'):
  16. org += ' ' + s if (t == 'B-ORG') else s
  17. if t in ('B-LOC', 'I-LOC'):
  18. loc += ' ' + s if (t == 'B-LOC') else s
  19. print(['person:' + per, 'location:' + loc, 'organzation:' + org])

输出结果如下:

  1. ['person: 周恩来 陈毅, 王东', 'location: 埃塞俄比亚 非洲 阿尔巴尼亚', 'organzation: 中华人民共和国国务院 外交部']

源码地址:https://github.com/stephen-v/zh-NER-keras

基于keras的BiLstm与CRF实现命名实体标注的更多相关文章

  1. BiLstm与CRF实现命名实体标注

    众所周知,通过Bilstm已经可以实现分词或命名实体标注了,同样地单独的CRF也可以很好的实现.既然LSTM都已经可以预测了,为啥要搞一个LSTM+CRF的hybrid model? 因为单独LSTM ...

  2. bi-Lstm +CRF 实现命名实体标注

    1. https://blog.csdn.net/buppt/article/details/82227030 (Bilstm+crf中的crf详解,包括是整体架构) 2. 邹博关于CRF的讲解视频 ...

  3. 用CRF做命名实体识别(一)

    用CRF做命名实体识别(二) 用CRF做命名实体识别(三) 用BILSTM-CRF做命名实体识别 博客园的markdown格式可能不太方便看,也欢迎大家去我的简书里看 摘要 本文主要讲述了关于人民日报 ...

  4. 用CRF做命名实体识别(二)

    用CRF做命名实体识别(一) 用CRF做命名实体识别(三) 一. 摘要 本文是对上文用CRF做命名实体识别(一)做一次升级.多添加了5个特征(分别是词性,词语边界,人名,地名,组织名指示词),另外还修 ...

  5. 使用CRF做命名实体识别(三)

    摘要 本文主要是对近期做的命名实体识别做一个总结,会给出构造一个特征的大概思路,以及对比所有构造的特征对结构的影响.先给出我最近做出来的特征对比: 目录 整体操作流程 特征的构造思路 用CRF++训练 ...

  6. PyTorch 高级实战教程:基于 BI-LSTM CRF 实现命名实体识别和中文分词

    前言:译者实测 PyTorch 代码非常简洁易懂,只需要将中文分词的数据集预处理成作者提到的格式,即可很快的就迁移了这个代码到中文分词中,相关的代码后续将会分享. 具体的数据格式,这种方式并不适合处理 ...

  7. NLP入门(八)使用CRF++实现命名实体识别(NER)

    CRF与NER简介   CRF,英文全称为conditional random field, 中文名为条件随机场,是给定一组输入随机变量条件下另一组输出随机变量的条件概率分布模型,其特点是假设输出随机 ...

  8. Bi-LSTM+CRF在文本序列标注中的应用

    传统 CRF 中的输入 X 向量一般是 word 的 one-hot 形式,前面提到这种形式的输入损失了很多词语的语义信息.有了词嵌入方法之后,词向量形式的词表征一般效果比 one-hot 表示的特征 ...

  9. 【NER】对命名实体识别(槽位填充)的一些认识

    命名实体识别 1. 问题定义 广义的命名实体识别是指识别出待处理文本中三大类(实体类.时间类和数字类).七小类(人名.机构名.地名.日期.货币和百分比)命名实体.但实际应用中不只是识别上述所说的实体类 ...

随机推荐

  1. Jpa中设置OneToMany插入报异常解决办法

    在Jpa中如果设置@OneToMany,但使用的时候,如果没有赋值,会报异常出现,这时只需要实例化一个空数组即可, 但类型一定要对应: 实例如下: newField.setxxxxxList(new ...

  2. 移动端开发利器vConsole.js,app内嵌H5开发时调试用

    vConsole:一个轻量.可拓展.针对手机网页的前端开发者调试面板,主要还是用于内嵌app页面时在手机上进行调试,打印完全和在PC端一样,方便大家找出问题所在. 不说废话直接进入主题,vConsol ...

  3. UBOOT添加命令的执行流程

    BootLoader(引导装载程序)是嵌入式系统软件开发的第一个环节,它把操作系统和硬件平台衔接在一起,对于嵌入式系统的后续软件开发十分重要,在整个开发中也占有相当大的比例.U-BOOT是当前比较流行 ...

  4. 修正uboot网络不可用

    通过使用uboot的网络功能可以更新ubook,烧写内核,文件系统,如果网络功能不可能,那还不如同变砖了一样.当然如果支持sd卡启动,可能通过sd卡完成这些功能,但是也太过麻烦了.飞凌的6410开发板 ...

  5. FusionCharts重写单系列图

    /** * @Title:FusionChart.java * @Package:com.yhd.chart.model * @Description:封装FusionChart单系列图 * @aut ...

  6. 《实战Nginx》读书笔记

    最近今天读了一本书叫做<实战Nginx:取代Apache的高性能Web服务器>,看后对Nginx 了解了不少.但是还有很多地方不是很了解.不过此书可以作为一本参考手册来使用,里面的讲解很详 ...

  7. R语言-动画

    使用动画可以使得图形更形象,更能反映数据的变化 1.安装环境gganimate if(!require(devtools)) install.packages("devtools" ...

  8. Java并发系列[7]----CountDownLatch源码分析

    CountDownLatch(闭锁)是一个很有用的工具类,利用它我们可以拦截一个或多个线程使其在某个条件成熟后再执行.它的内部提供了一个计数器,在构造闭锁时必须指定计数器的初始值,且计数器的初始值必须 ...

  9. js数组使用JSON.stringify()和toString()的区别,JSON.parse

    JSON.stringify()中的<br><br>var arr = [1,2,3,4]; console.log(arr.toString()); // 1,2,3,4 a ...

  10. 通过smtp直接发送邮件

    /// <param name="fromEmail">发件人的邮箱</param> /// <param name="toEmail&qu ...