• 基于keras实现的中文实体识别


    1、简介

    NER(Named Entity Recognition,命名实体识别)又称作专名识别,是自然语言处理中常见的一项任务,使用的范围非常广。命名实体通常指的是文本中具有特别意义或者指代性非常强的实体,通常包括人名、地名、机构名、时间、专有名词等。NER系统就是从非结构化的文本中抽取出上述实体,并且可以按照业务需求识别出更多类别的实体,比如产品名称、型号、价格等。

    命名实体识别是信息提取、问答系统、句法分析、机器翻译等应用领域的重要基础工具,作为结构化信息提取的重要步骤。

    2、常见算法

    2.1、基于规则和词典的方法

    基于规则和词典的方法是命名实体识别中最早使用的方法,多采用语言学专家构造规则模板,选用特征包括统计信息、标点符号、关键字、指示词和方向词、位置词、中心词等方法,以模式和字符串相匹配为主要手段,这类系统大多依赖于知识库和词典的建立。

    2.2、基于统计的方法 

    基于统计机器学习的方法主要包括:隐马尔可夫模型、最大熵、支持向量机、条件随机场等。

    在这4种学习方法中,最大熵模型结构紧凑,具有较好的通用性,主要缺点是训练时间复杂性非常高,有时甚至导致训练代价难以承受,另外由于需要明确的归一化计算,导致开销比较大。而条件随机场为命名实体识别提供了一个特征灵活、全局最优的标注框架,但同时存在收敛速度慢、训练时间长的问题。一般说来,最大熵和支持向量机在正确率上要比隐马尔可夫模型高一些,但是隐马尔可夫模型在训练和识别时的速度要快一些,主要是由于在利用维特比算法求解命名实体类别序列的效率较高。隐马尔可夫模型更适用于一些对实时性有要求以及像信息检索这样需要处理大量文本的应用,如短文本命名实体识别。

     2.3、基于深度学习的方法

    随着深度学习的兴起,RNN、LSTM、Bi-LSTM等模型已经被证明在NLP任务上有着良好的表现。相比传统模型,RNN能够考虑长远的上下文信息,并且能够解决CRF特征选择的问题,可以将主要的精力花在网络设计和参数调优上,但RNN一般需要较大的训练数据,在小规模数据集上,CRF表现较好。 

    3、中文实体识别

    目前比较流行的做法是将Bi-LISTM和CRF进行结合,借鉴两个模型各自的优点,来达到更好的效果。模型图如下:

    LSTM的全称是Long Short-Term Memory,它是RNN(Recurrent Neural Network)的一种。LSTM由于其设计的特点,非常适合用于对时序数据的建模,如文本数据。Bi-LSTM是Bi-directional Long Short-Term Memory的缩写,是由前向LSTM与后向LSTM组合而成。两者在自然语言处理任务中都常被用来建模上下文信息。

    CRF(Conditional random field,条件随机场)是一种判别式模型,是给定一组输入随机变量条件下另一组输出随机变量的条件概率分布模型。

    3.1 实体类别定义

    实体类别包括以下6种:

    time: 时间

    location: 地点

    person_name: 人名

    org_name: 组织名

    company_name: 公司名

    product_name: 产品名 

    3.2 数据标注

    采用UTF-8进行编码,每行为一个段落标注。所有的实体以如下的格式进行标注: 

    {{实体类型:实体文本}}

    示例:

    此次{{location:中国}}个展,{{person_name:苏珊}}将与她80多岁高龄的父亲一起合作,哼唱一首古老的{{location:威尔士}}民歌{{product_name:《白蜡林》}}。届时在{{location:画廊大厅}}中将安放6个音箱进行播放,艺术家还特意回到家乡{{location:格拉斯哥}},同父亲一起在{{org_name:中国音乐学院}}里为作品录制了具有{{location:中国}}元素的音乐片段。 

    3.3 标签体系

    对于NER任务,常见的标签体系包括IO、BIO、BMEWO、BMEWO+。下面举例说明不同标签体系的区别。

     

     大部分情况下,标签体系越复杂准确度也越高,但相应的训练时间也会增加。因此需要根据实际情况选择合适的标签体系。这里选择和分词系统类似的BMEWO标签体系。

    3.4 环境搭建

    基于keras + tensorflow实现Bi-LSTM + CRF实体识别。目前使用2.2.4版本的keras,在keras版本里面已经包含bilstm模型,但crf的loss function还没有,可以从keras contribute中获得,具体可参看:

    https://github.com/keras-team/keras-contrib

    环境搭建请参考这篇博文: https://www.cnblogs.com/MikeZhang/p/createKerasEnv-20210228.html

    3.5 示例代码

    训练代码:

    #! /usr/bin/env python3
    #-*- coding:utf-8 -*- 
    
    import process_data,os
    from bilsm_crf_model import create_model
    
    os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
    EPOCHS = 1
    
    (train_x, train_y), (test_x, test_y), (vocab, chunk_tags) = process_data.load_data()
    model = create_model(len(vocab),len(chunk_tags))
    # train model
    model.fit(train_x, train_y,batch_size=128,epochs=EPOCHS, validation_data=[test_x, test_y])
    model.save('model/ner_crf.h5')

    测试代码:

    #! /usr/bin/env python3
    #-*- coding:utf-8 -*- 
    
    import bilsm_crf_model
    import process_data
    import numpy as np
    import pickle
    
    def doParse(predict_text):
        model,vocab,chunk_tags = None,None,None
        with open('model/config.pkl', 'rb') as inp:
            (vocab, chunk_tags) = pickle.load(inp)
            model = bilsm_crf_model.create_model(len(vocab),len(chunk_tags))
        if not model : return None
        model.load_weights('model/ner_crf.h5')
        
        str,length = process_data.process_data(predict_text, vocab)
        raw = model.predict(str)[0][-length:]
        result = [np.argmax(row) for row in raw]
        result_tags = [chunk_tags[i] for i in result]
    
        per, loc, org,company,product = '', '', '','',''
        #print(result_tags)
        resultMap = {}
        for s, t in zip(predict_text, result_tags):
            #print(s,t)
            if 'O' == t : continue
            key = t[2:]
            if t.startswith('B_'):
                if key not in resultMap : resultMap[key] = ''
                resultMap[key] += ' ' + s
            else:
                resultMap[key] += s
        return resultMap
    
    predict_text = '中华人民共和国国务院总理在外交部长的陪同下,连续访问了埃塞俄比亚等非洲10国以及阿尔巴尼亚'
    resultMap = doParse(predict_text)
    print(predict_text)
    for k,v in resultMap.items():
        print("%s : %s" % (k,v))

    示例代码目录结构:

     本文涉代码及资源下载地址:https://pan.baidu.com/s/1w9T_mDxwqfzQ3Xf8_3FLrw

    可关注微信公众号(聊聊博文)后回复 2021022801 获取提取码。

    微信公众号:

  • E-Mail : Mike_Zhang@live.com
  • 转载请注明出处,谢谢!
  • 相关阅读:
    上传文件是常要处理的事情,使用ajaxFileUpload.js处理比较方便,这里的ajaxFileUpload.js文件修改过的,
    文件上传控件bootstrap-fileinput的使用
    常用开发中使用到的作图工具(开发向)
    mybatis-generator + mysql/ptsql
    表单嵌套问题的解决方法
    C++和QML混合的QT程序调试方法
    windows下,Qt Creator 中javascript调试器安装并使用
    Qt浮动按钮的实现(使用窗口背景透明、实现只显示浮动按钮的目的)
    不能继承于QObject的类就一定不能使用信号槽?(用一个代理类进行发射就行了)
    关于SetLength报Out of memory的研究及解决办法
  • 原文地址:https://www.cnblogs.com/MikeZhang/p/kerasNER-20210228.html
  • Copyright © 2020-2023  润新知