中文命名实体识别 NER BILSTM CRF IDCNN BERT

举报
码上开花_Lancer 发表于 2022/09/27 14:45:47 2022/09/27
【摘要】 NER(中文实体命名识别) 光健字: 中文命名实体识别 NER BILSTM CRF IDCNN BERT 摘要:对中文命名实体识别一直处于知道却未曾真正实践过的状态,此次主要是想了解和实践一些主流的中文命名实体识别的神经网络算法。通过对网上博客的阅读了解,中文命名实体识别比较主流的方法是BILSTM+CRF、IDCNN+CRF、BERT+BILSTM+CRF这几种神经网络算法,这个demo也

NER(中文实体命名识别)

关键字: 中文命名实体识别 NER BILSTM CRF IDCNN BERT

摘要:对中文命名实体识别一直处于知道却未曾真正实践过的状态,此次主要是想了解和实践一些主流的中文命名实体识别的神经网络算法。通过对网上博客的阅读了解,中文命名实体识别比较主流的方法是BILSTM+CRF、IDCNN+CRF、BERT+BILSTM+CRF这几种神经网络算法,这个demo也用Keras实现了这几个算法,并且采用几个比较通用的数据集进行训练测试。这个demo是以了解和学习为目的的,所以未得出任何结论

注意:由于算力和时间的问题,对神经网络的参数未进行太多调试,所以模型现在的参数并不是最佳参数

主要库的版本

本项目是基于keras(Using TensorFlow backend)以下是主要库的版本

python = 3.6.8

keras == 2.2.4

keras_contrib == 0.0.2

keras_bert == 0.80.0

tensorflow == 1.14.0

项目目录结构

data 数据目录

具体请查看数据目录文件夹下的README文件

DataProcess 数据处理文件夹

具体请查看数据处理文件夹下的README文件

Pubilc 公共工具

path 定义文件(文件夹)的路径

utils 工具

创建log
keras的callback调类
Model 模型(总共定义了5个模型,具体结构请查看Model文件夹下的README文件)

BERT+BILST+CRF

BILSTM+Attention+CRF

BILSTM+CRF

IDCNN+CRF(1)

IDCNN+CRF(2)

log 记录数据

运行项目

注意:需要用到bert网络的需要提前下载BERT预训练模型解压到data文件夹下

直接在IDE里运行项目

直接运行 train.py文件

命令行

python train.py
运行结果

运行GPU: GeForceRTX2080Ti(GPU显存 10.0G, 算力7.5)

训练周期为15个周期,提前停止条件:2个周期验证集准确率没有提升。

BERT采用batch_size=32 因为值为64的时候所使用GPU内存不够

以下数据基于MSRA数据集,以8:2的拆分(训练集:测试集)。测试结果

模型 准确率 F1 召回率
IDCNN_CRF 0.988 0.860 0.871
IDCNN_CRF_2 0.990 0.872 0.897
BILSTM_Attention_CRF 0.987 0.850 0.848
BILSTMCRF 0.989 0.870 0.863
BERT_BILSTM_CRF 0.996 0.954 0.950

很显然BERT+BILIST+CRF的组合效果会好很多

提示:log文件夹里有每个训练周期记录的数据

数据 处理

数据文件结构

chinese_L-12_H-768_A-12 (bert官方预训练模型, 需要去官方进行下载) 下载地址

bert_config.json
bert_model.ckpt.data-00000-of-00001
bert_model.ckpt.index
bert_model.ckpt.meta
vocab.txt
data (data数据集)
train.txt
 
test.txt
data2
all.txt (原数据集)
 
train.txt (预处理分割出来的训练数据集)
test.txt (预处理分割出来的测试数据集)

MSRA 微软亚洲研究院开源数据http://www.pudn.com/Download/item/id/2435241.html

train1.txt (原数据集)
train.txt (预处理分割出来的训练数据集)
test.txt (预处理分割出来的测试数据集)
renMinRiBao 人民日报标注数据集
renmin3.txt (原数据集)
train.txt (预处理分割出来的训练数据集)
test.txt (预处理分割出来的测试数据集)

数据处理模块

​ 此模块主要对数据data、data2、msra、人名日报 4份数据进行处理,可直接提供给模型使用。

文件构成
data2_preprocessing.py data2数据预处理文件
msra_preprocessing.py MSRA数据预处理
process_data.py 数据处理
renminribao_preprocessing.py 人民日报数据处理
vocab.py 词表
提供词表 和 tag 标签表格
词表采用 BERT 预训练文件中vocab.txt
tag 采用 O、B-PER、I-PER、B-LOC、I-LOC、B-ORG、I-ORG
文件简介
data2_preprocessing.py

data2 原文件all.txt 文件中的格式,这便是我们预处理的标准格式,所以这里只需要将文件切分成test.txt和train.txt两份数据即可。

中	B-ORG
共	I-ORG
中	I-ORG
央	I-ORG
致	O
中	B-ORG
国	I-ORG
致	I-ORG
公	I-ORG
党	I-ORG
十	I-ORG
一	I-ORG
大	I-ORG
的	O
贺	O
词	O

msra_preprocessing.py MSRA数据预处理

MAST是微软亚洲研究院开源数据

train1.txt 数据格式:

当/o 希望工程/o 救助/o 的/o 百万/o 儿童/o 成长/o 起来/o ,/o 科教/o 兴/o 国/o 蔚然成风/o 时/o ,/o 今天/o 有/o 收藏/o 价值/o 的/o 书/o 你/o 没/o 买/o ,/o 明日/o 就/o 叫/o 你/o 悔不当初/o !/o 

其中需要做几个映射:

人名:
nr -> B-PER、I-PER
地名:
ns -> B-LOC、I-LOC
机构名称:
nt -> B-ORG、I-ORG

我们需要处理成以下格式:

当 O
希 O
望 O
工 O
程 O
救 O
助 O
的 O
百 O
万 O

并且切分成训练和测试数据集

process_data.py 数据处理

数据处理直接提供给模型训练使用。

数据处理有两种一种是一般的模型输入只需要一个2维数组

一般模型

inputs = ids(n_sample x max_len) 只需要一个二维输入
labels = label(n_sample x max_len x one_hot_num) (转化为noe-hot为可选项目) 三维数据

BERT

inputs =[ids(n_sample x max_len) , types(n_sample x max_len) ] 只需要2个二维输入
labels = label(n_sample x max_len x one_hot_num) (转化为noe-hot为可选项目) 三维数据

所以 一般模型的输入和bert数据输入需要进行区分

数据处理 (过程)

data(texts)(一般处理)
获取char to index 字典
把文本转化为index的形式
截取过长的文本、填充长度不够文本
data(texts)(bert数据处理)
获取char to index 字典
ids把文本转化为index的形式 type 全部填充0 因为只有一个句子
截取过长的文本
首尾进行填充(开始填充[CLS] 结尾填充 [SEP])
labels()
获取tag to index 字典
把label处理成Index的形式
截取和填充(bert需要注意填充了[CLS] [SEP])
转化成one-hot(如果需要)

最终输出(以label为one-hot为例子)

一般数据

datas.shape=(n_sample, max_len)
labels.shape=(n_sample, max_len, one_hot_len)
bert数据
datas = [ ids.shape=(n_sample, max_len), types.shape=(n_sample, max_len) ]
lables.shape=(n_sample, max_len, one_hot_len)

bert数据处理

renminribao_preprocessing.py

人名日报标注数据预处理

原数据格式 (其实这个是别人稍稍处理过的-------------- )

迈/O 向/O 充/O 满/O 希/O 望/O 的/O 新/O 世/O 纪/O —/O —/O 一/O 九/O 九/O 八/O 年/O 新/O 年/O 讲/O 话/O (/O 附/O 图/O 片/O 1/O 张/O )/O 
中/B_nt 共/M_nt 中/M_nt 央/E_nt 总/O 书/O 记/O 、/O 国/O 家/O 主/O 席/O 江/B_nr 泽/M_nr 民/E_nr 
(/O 一/O 九/O 九/O 七/O 年/O 十/O 二/O 月/O 三/O 十/O 一/O 日/O )/O 
1/O 2/O 月/O 3/O 1/O 日/O ,/O 中/B_nt 共/M_nt 中/M_nt 央/E_nt 总/O 书/O 记/O 、/O 国/O 家/O 主/O 席/O 江/B_nr 泽/M_nr 民/E_nr 发/O 表/O 1/O 9/O 9/O 8/O 年/O 新/O 年/O 讲/O 话/O 《/O 迈/O 向/O 充/O 满/O 希/O 望/O 的/O 新/O 世/O 纪/O 》/O 。/O (/O 新/B_nt 华/M_nt 社/E_nt 记/O 者/O 兰/B_nr 红/M_nr 光/E_nr 摄/O )/O 

需要做的标注映射:

人名:
    B_nr -> B-PER
    M_nr -> I-PER
    E_nr -> I-PER

地名:
    B_ns -> B-LOC
    M_ns -> I-LOC
    E_ns -> I-LOC

机构名称:
    B_nt -> B-ORG
    M_nt -> I-ORG
    E_nt -> I-ORG

处理成通用的格式

迈 O
向 O
充 O
满 O
希 O
望 O
的 O
新 O
世 O
纪 O
— O
— O

vocab.py 词表
提供词表 和 tag 标签表格
词表采用 BERT 预训练文件中vocab.txt
tag 采用 O、B-PER、I-PER、B-LOC、I-LOC、B-ORG、I-ORG

模型介绍和实现

Model

​ 在通过查阅一些博客后,在实体命名识别方面,几大主流的模型就是BILSTM+CRF、IDCNN+CRF、BERT+BILSTM+CRF。所以在此也是搭建了这几种模型分别进行测试。

注意:由于算力和时间原因,并没有对模型进行很好的调参~现在所搭建的模型并没有进行调参对比。

本demo总共采用了5个模型分别是:

BERT+BILSTM+CRF
BILSTM+Attention+CRF
BILSTM+CRF
IDCNN+CRF(1)
IDCNN+CRF(2) 与(1)的CNN的filters数和全连接层会有些区别。
BERT+LSTM+CRF

采用BERT输出直接接上LSTM再接上CRF ,并没有进行太多参数的调整。

但从网络结构上看,LSTM和全连接层和dropout部分是可以做一些调整和尝试的,由于算力和时间的问题实在没办法做太多尝试。等有机会了再做更多尝试吧。

**"""

采用 BERT + BILSTM + CRF 网络进行处理

“”"

from Public.path import path_bert_dir


from keras.models import Model
from keras.layers import Bidirectional, LSTM, Dense, Dropout
from keras.optimizers import Adam
from keras_contrib.layers import CRF
import keras_bert
import os



class BERTBILSTMCRF(object):
    def __init__(self,
                 vocab_size: int,
                 n_class: int,
                 max_len: int = 100,
                 embedding_dim: int = 128,
                 rnn_units: int = 128,
                 drop_rate: float = 0.5,
                 ):
        self.vocab_size = vocab_size
        self.n_class = n_class
        self.max_len = max_len
        self.embedding_dim = embedding_dim
        self.rnn_units = rnn_units
        self.drop_rate = drop_rate
        self.config_path = os.path.join(path_bert_dir, 'bert_config.json')
        self.check_point_path = os.path.join(path_bert_dir, 'bert_model.ckpt')
        self.dict_path = os.path.join(path_bert_dir, 'vocab.txt')


    def creat_model(self):
        print('load bert Model start!')
        model = keras_bert.load_trained_model_from_checkpoint(self.config_path,
                                                              checkpoint_file=self.check_point_path,
                                                              seq_len=self.max_len,
                                                              trainable=True)
        print('load bert Model end!')
        inputs = model.inputs
        embedding = model.output
        x = Bidirectional(LSTM(units=self.rnn_units, return_sequences=True))(embedding)
        x = Dropout(self.drop_rate)(x)
        x = Dense(self.n_class)(x)
        self.crf = CRF(self.n_class, sparse_target=False)
        x = self.crf(x)
        self.model = Model(inputs=inputs, outputs=x)
        self.model.summary()
        self.compile()


        return self.model


    def compile(self):
        self.model.compile(optimizer=Adam(1e-5),
                           loss=self.crf.loss_function,
                           metrics=[self.crf.accuracy])



if __name__ == '__main__':


    from DataProcess.process_data import DataProcess
    from keras.utils.vis_utils import plot_model


    dp = DataProcess(data_type='msra', model='bert')
    train_data, train_label, test_data, test_label = dp.get_data(one_hot=True)


    md = BERTBILSTMCRF(vocab_size=dp.vocab_size, n_class=dp.tag_size)
    md.creat_model()
    model = md.model


    plot_model(model, to_file='picture/BERT_BILSTM_CRF.png', show_shapes=True)


    exit()


    model.fit(train_data, train_label, batch_size=64, epochs=2,
              validation_data=[test_data, test_label])

BILSTM+Attention+CRF

BILSTM接上self attention层在家CRF。

其中AttentionSelf层是根据大神实现的代码实现的

from keras.regularizers import L1L2
from keras.engine.topology import Layer
from keras import backend as K


from keras.models import Model
from keras.layers import Embedding, Bidirectional, LSTM, Dense, Dropout, Input
from keras_contrib.layers import CRF



class AttentionSelf(Layer):
    """
        self attention,
        codes from:  https://mp.weixin.qq.com/s/qmJnyFMkXVjYBwoR_AQLVA
    """
    def __init__(self, output_dim, **kwargs):
        self.output_dim = output_dim
        super().__init__(**kwargs)


    def build(self, input_shape):
        # W、K and V
        self.kernel = self.add_weight(name='WKV',
                                        shape=(3, input_shape[2], self.output_dim),
                                        initializer='uniform',
                                        regularizer=L1L2(0.0000032),
                                        trainable=True)
        super().build(input_shape)


    def call(self, x):
        WQ = K.dot(x, self.kernel[0])
        WK = K.dot(x, self.kernel[1])
        WV = K.dot(x, self.kernel[2])
        print("WQ.shape",WQ.shape)
        print("K.permute_dimensions(WK, [0, 2, 1]).shape",K.permute_dimensions(WK, [0, 2, 1]).shape)
        QK = K.batch_dot(WQ,K.permute_dimensions(WK, [0, 2, 1]))
        QK = QK / (64**0.5)
        QK = K.softmax(QK)
        print("QK.shape",QK.shape)
        V = K.batch_dot(QK,WV)
        return V


    def compute_output_shape(self, input_shape):
        return (input_shape[0],input_shape[1],self.output_dim)



class BILSTMAttentionCRF(object):
    def __init__(self,
                 vocab_size: int,
                 n_class: int,
                 embedding_dim: int = 128,
                 rnn_units: int = 128,
                 drop_rate: float = 0.5,
                 ):
        self.vocab_size = vocab_size
        self.n_class = n_class
        self.embedding_dim = embedding_dim
        self.rnn_units = rnn_units
        self.drop_rate = drop_rate
        pass


    def creat_model(self):
        inputs = Input(shape=(None,))
        x = Embedding(input_dim=self.vocab_size, output_dim=self.embedding_dim)(inputs)
        x = Bidirectional(LSTM(units=self.rnn_units, return_sequences=True))(x)
        x = AttentionSelf(300)(x)
        x = Dropout(self.drop_rate)(x)
        x = Dense(self.n_class)(x)
        self.crf = CRF(self.n_class, sparse_target=False)
        x = self.crf(x)
        self.model = Model(inputs=inputs, outputs=x)
        self.model.summary()
        self.compile()
        return self.model


    def compile(self):
        self.model.compile('adam',
                           loss=self.crf.loss_function,
                           metrics=[self.crf.accuracy])



if __name__ == '__main__':


    from DataProcess.process_data import DataProcess
    from sklearn.metrics import f1_score
    import numpy as np
    from keras.utils.vis_utils import plot_model


    dp = DataProcess(data_type='msra')
    train_data, train_label, test_data, test_label = dp.get_data(one_hot=True)


    model_class = BILSTMAttentionCRF(vocab_size=dp.vocab_size, n_class=7)
    model_class.creat_model()
    model = model_class.model


    plot_model(model, to_file='picture/BILSTM_ATTENTION_CRF.png', show_shapes=True)
    exit()


    model.fit(train_data, train_label, batch_size=64, epochs=2,
              validation_data=[test_data, test_label])


    # 对比测试数据的tag
    y = model.predict(test_data)


    label_indexs = []
    pridict_indexs = []


    num2tag = dp.num2tag()
    i2w = dp.i2w()
    texts = []
    texts.append(f"字符\t预测tag\t原tag\n")
    for i, x_line in enumerate(test_data):
        for j, index in enumerate(x_line):
            if index != 0:
                char = i2w.get(index, ' ')
                t_line = y[i]
                t_index = np.argmax(t_line[j])
                tag = num2tag.get(t_index, 'O')
                pridict_indexs.append(t_index)


                t_line = test_label[i]
                t_index = np.argmax(t_line[j])
                org_tag = num2tag.get(t_index, 'O')
                label_indexs.append(t_index)
                texts.append(f"{char}\t{tag}\t{org_tag}\n")
        texts.append('\n')


    f1score = f1_score(label_indexs, pridict_indexs, average='macro')
    print(f"f1score:{f1score}")


    """ epochs=1
   
    - val_loss: 0.1038 - val_crf_viterbi_accuracy: 0.9664
   
        epochs=2
       
    - val_loss: 0.0531 - val_crf_viterbi_accuracy: 0.9819
   
    f1score:0.7481255117004026
       
        epochs=3
       
       
       
        epochs=4
       
       
        epochs=5


    """


    exit()


    with open('./pre.txt', 'w') as f:
        f.write("".join(texts))**





BILSTM+CRF






from keras.models import Model
from keras.layers import Embedding, Bidirectional, LSTM, Dense, Dropout, Input
from keras_contrib.layers import CRF



class BILSTMCRF():
    def __init__(self,
                 vocab_size: int,
                 n_class: int,
                 embedding_dim: int = 128,
                 rnn_units: int = 128,
                 drop_rate: float = 0.5,
                 ):
        self.vocab_size = vocab_size
        self.n_class = n_class
        self.embedding_dim = embedding_dim
        self.rnn_units = rnn_units
        self.drop_rate = drop_rate


    def creat_model(self):
        inputs = Input(shape=(None,))
        x = Embedding(input_dim=self.vocab_size, output_dim=self.embedding_dim)(inputs)
        x = Bidirectional(LSTM(units=self.rnn_units, return_sequences=True))(x)
        x = Dropout(self.drop_rate)(x)
        x = Dense(self.n_class)(x)
        self.crf = CRF(self.n_class, sparse_target=False)
        x = self.crf(x)
        self.model = Model(inputs=inputs, outputs=x)
        self.model.summary()
        self.compile()
        return self.model


    def compile(self):
        self.model.compile('adam',
                           loss=self.crf.loss_function,
                           metrics=[self.crf.accuracy])



if __name__ == '__main__':


    from DataProcess.process_data import DataProcess
    from sklearn.metrics import f1_score
    import numpy as np
    from keras.utils.vis_utils import plot_model


    dp = DataProcess(data_type='msra')
    train_data, train_label, test_data, test_label = dp.get_data(one_hot=True)


    lstm_crf = BILSTMCRF(vocab_size=dp.vocab_size, n_class=7)
    lstm_crf.creat_model()
    model = lstm_crf.model


    plot_model(model, to_file='picture/BILSTM_CRF.png', show_shapes=True)
    exit()


    model.fit(train_data, train_label, batch_size=64, epochs=2,
              validation_data=[test_data, test_label])


    # 对比测试数据的tag
    y = model.predict(test_data)


    label_indexs =[]
    pridict_indexs = []


    num2tag = dp.num2tag()
    i2w = dp.i2w()
    texts = []
    texts.append(f"字符\t预测tag\t原tag\n")
    for i, x_line in enumerate(test_data):
        for j, index in enumerate(x_line):
            if index != 0:
                char = i2w.get(index, ' ')
                t_line = y[i]
                t_index = np.argmax(t_line[j])
                tag = num2tag.get(t_index, 'O')
                pridict_indexs.append(t_index)


                t_line = test_label[i]
                t_index = np.argmax(t_line[j])
                org_tag = num2tag.get(t_index, 'O')
                label_indexs.append(t_index)


                texts.append(f"{char}\t{tag}\t{org_tag}\n")
        texts.append('\n')


    f1score = f1_score(label_indexs, pridict_indexs, average='macro')
    print(f"f1score:{f1score}")


    """ epochs=2
   
     - val_loss: 0.0422 - val_crf_viterbi_accuracy: 0.9852
     
     f1score:0.8070982542924598
     
    """


    exit()


    with open('./pre.txt', 'w') as f:
        f.write("".join(texts))

IDCNN+CRF(1)

"""
IDCNN(空洞CNN) 当卷积Conv1D的参数dilation_rate>1的时候,便是空洞CNN的操作
"""


from keras.models import  Model
from keras.layers import Embedding, Dense, Dropout, Input
from keras.layers import Conv1D
from keras_contrib.layers import CRF


class IDCNNCRF(object):
    def __init__(self,
                 vocab_size: int,  # 词的数量(词表的大小)
                 n_class: int,  # 分类的类别(本demo中包括小类别定义了7个类别)
                 max_len: int = 100,  # 最长的句子最长长度
                 embedding_dim: int = 128,  # 词向量编码长度
                 drop_rate: float = 0.5,  # dropout比例
                 ):
        self.vocab_size = vocab_size
        self.n_class = n_class
        self.max_len = max_len
        self.embedding_dim = embedding_dim
        self.drop_rate = drop_rate
        pass


    def creat_model(self):
        """
        本网络的机构采用的是,
           Embedding
           直接进行2个常规一维卷积操作
           接上一个空洞卷积操作
           连接全连接层
           最后连接CRF层


        kernel_size 采用2、3、4


        cnn  特征层数: 64、128、128
        """


        inputs = Input(shape=(self.max_len,))
        x = Embedding(input_dim=self.vocab_size, output_dim=self.embedding_dim)(inputs)
        x = Conv1D(filters=64,
                   kernel_size=3,
                   activation='relu',
                   padding='same',
                   dilation_rate=1)(x)
        x = Conv1D(filters=128,
                   kernel_size=3,
                   activation='relu',
                   padding='same',
                   dilation_rate=1)(x)
        x = Conv1D(filters=128,
                   kernel_size=3,
                   activation='relu',
                   padding='same',
                   dilation_rate=2)(x)
        x = Dropout(self.drop_rate)(x)
        x = Dense(self.n_class)(x)
        self.crf = CRF(self.n_class, sparse_target=False)
        x = self.crf(x)
        self.model = Model(inputs=inputs, outputs=x)
        self.model.summary()
        self.compile()
        return self.model


    def compile(self):
        self.model.compile('adam',
                           loss=self.crf.loss_function,
                           metrics=[self.crf.accuracy])



if __name__ == '__main__':


    from DataProcess.process_data import DataProcess
    from sklearn.metrics import f1_score
    import numpy as np
    from keras.utils.vis_utils import plot_model


    dp = DataProcess(max_len=100, data_type='msra')
    train_data, train_label, test_data, test_label = dp.get_data(one_hot=True)


    model_class = IDCNNCRF(vocab_size=dp.vocab_size, n_class=7, max_len=100)
    model_class.creat_model()
    model = model_class.model


    plot_model(model, to_file='picture/IDCNN_CRF.png', show_shapes=True)
    exit()


    model.fit(train_data, train_label, batch_size=64, epochs=5,
              validation_data=[test_data, test_label])


    # 对比测试数据的tag
    y = model.predict(test_data)


    label_indexs = []
    pridict_indexs = []


    num2tag = dp.num2tag()
    i2w = dp.i2w()
    texts = []
    texts.append(f"字符\t预测tag\t原tag\n")
    for i, x_line in enumerate(test_data):
        for j, index in enumerate(x_line):
            if index != 0:
                char = i2w.get(index, ' ')
                t_line = y[i]
                t_index = np.argmax(t_line[j])
                tag = num2tag.get(t_index, 'O')
                pridict_indexs.append(t_index)


                t_line = test_label[i]
                t_index = np.argmax(t_line[j])
                org_tag = num2tag.get(t_index, 'O')
                label_indexs.append(t_index)


                texts.append(f"{char}\t{tag}\t{org_tag}\n")
        texts.append('\n')


    f1score = f1_score(label_indexs, pridict_indexs, average='macro')
    print(f"f1score:{f1score}")


    """ epochs=1


    - val_loss: 0.0518 - val_crf_viterbi_accuracy: 0.9830
   
        epochs=2
   
    - val_loss: 0.0386 - val_crf_viterbi_accuracy: 0.9867
   
        epochs=3
       
    - val_loss: 0.0338 - val_crf_viterbi_accuracy: 0.9880
       
        epochs=4
       
    - val_loss: 0.0304 - val_crf_viterbi_accuracy: 0.9889
       
        epochs=5
   
    - val_loss: 0.0283 - val_crf_viterbi_accuracy: 0.9890
   
    f1score:0.8564147211248077
   


    """


    exit()


    with open('./pre.txt', 'w') as f:
        f.write("".join(texts))

IDCNN+CRF(2)

"""
IDCNN(空洞CNN) 当卷积Conv1D的参数dilation_rate>1的时候,便是空洞CNN的操作
"""


from keras.models import Model
from keras.layers import Embedding, Dense, Dropout, Input, Conv1D
from keras_contrib.layers import CRF



class IDCNNCRF2():
    def __init__(self,
                 vocab_size: int,  # 词的数量(词表的大小)
                 n_class: int,  # 分类的类别(本demo中包括小类别定义了7个类别)
                 max_len: int = 100,  # 最长的句子最长长度
                 embedding_dim: int = 128,  # 词向量编码长度
                 drop_rate: float = 0.5,  # dropout比例
                 ):
        self.vocab_size = vocab_size
        self.n_class = n_class
        self.max_len = max_len
        self.embedding_dim = embedding_dim
        self.drop_rate = drop_rate


    def creat_model(self):
        """
        本网络的机构采用的是,
           Embedding
           直接进行2个常规一维卷积操作
           接上一个空洞卷积操作
           连接2个全连接层
           最后连接CRF层


        kernel_size 采用2、3、4


        cnn  特征层数: 256、256、512


        """
        inputs = Input(shape=(self.max_len,))
        x = Embedding(input_dim=self.vocab_size, output_dim=self.embedding_dim)(inputs)
        x = Conv1D(filters=256,
                   kernel_size=2,
                   activation='relu',
                   padding='same',
                   dilation_rate=1)(x)
        x = Conv1D(filters=256,
                   kernel_size=3,
                   activation='relu',
                   padding='same',
                   dilation_rate=1)(x)
        x = Conv1D(filters=512,
                   kernel_size=4,
                   activation='relu',
                   padding='same',
                   dilation_rate=2)(x)
        x = Dropout(self.drop_rate)(x)
        x = Dense(1024)(x)
        x = Dropout(self.drop_rate)(x)
        x = Dense(self.n_class)(x)
        self.crf = CRF(self.n_class, sparse_target=False)
        x = self.crf(x)
        self.model = Model(inputs=inputs, outputs=x)
        self.model.summary()
        self.compile()
        return self.model


    def compile(self):
        self.model.compile('adam',
                           loss=self.crf.loss_function,
                           metrics=[self.crf.accuracy])



if __name__ == '__main__':


    from DataProcess.process_data import DataProcess
    from sklearn.metrics import f1_score
    import numpy as np
    from keras.utils.vis_utils import plot_model


    dp = DataProcess(max_len=100, data_type='msra')
    train_data, train_label, test_data, test_label = dp.get_data(one_hot=True)


    lstm_crf = IDCNNCRF2(vocab_size=dp.vocab_size, n_class=7, max_len=100)
    lstm_crf.creat_model()
    model = lstm_crf.model


    plot_model(model, to_file='picture/IDCNN_CRF_2.png', show_shapes=True)
    exit()


    model.fit(train_data, train_label, batch_size=64, epochs=5,
              validation_data=[test_data, test_label])


    # 对比测试数据的tag
    y = model.predict(test_data)


    label_indexs = []
    pridict_indexs = []


    num2tag = dp.num2tag()
    i2w = dp.i2w()
    texts = []
    texts.append(f"字符\t预测tag\t原tag\n")
    for i, x_line in enumerate(test_data):
        for j, index in enumerate(x_line):
            if index != 0:
                char = i2w.get(index, ' ')
                t_line = y[i]
                t_index = np.argmax(t_line[j])
                tag = num2tag.get(t_index, 'O')
                pridict_indexs.append(t_index)


                t_line = test_label[i]
                t_index = np.argmax(t_line[j])
                org_tag = num2tag.get(t_index, 'O')
                label_indexs.append(t_index)


                texts.append(f"{char}\t{tag}\t{org_tag}\n")
        texts.append('\n')


    f1score = f1_score(label_indexs, pridict_indexs, average='macro')
    print(f"f1score:{f1score}")


    """ epochs=1


    - val_loss: 0.0421 - val_crf_viterbi_accuracy: 0.9858
   
        epochs=2
   
    - val_loss: 0.0304 - val_crf_viterbi_accuracy: 0.9892
   
        epochs=3
       
    - val_loss: 0.0269 - val_crf_viterbi_accuracy: 0.9898


        epochs=4
   
    - val_loss: 0.0267 - val_crf_viterbi_accuracy: 0.9899


        epochs=5
   
    - val_loss: 0.0231 - val_crf_viterbi_accuracy: 0.9898
   
    f1score:0.871357911057253
   
    """


    exit()


    with open('./pre.txt', 'w') as f:
        f.write("".join(texts))
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。