上一篇博客介绍了文本分类任务的text_cnn模型,本篇博客主要介绍一下另一个常见的nlp任务,命名实体识别。简单来说,命名实体识别也可以算分类,但是它的不同点在它是对整个句子的每一个字做实体标签预测,也可以称为序列标注任务。
还是从以下几个步骤来简单说明一下命名实体识别任务:
一、原始数据预处理
首先来看下命名实体识别任务的语料和标签是怎么样的,其中一条样本可以如下示例:
text:人 民 网 1 月 1 日 讯 据 《 纽 约 时 报 》 报 道 , 美 国 华 尔 街 股 市 在 2 0 1 3 年 的 最 后 一 天 继 续 上 涨 , 和 全 球 股 市 一 样 , 都 以 最 高 纪 录 或 接 近 最 高 纪 录 结 束 本 年 的 交 易 。
tags:O O O B_T I_T I_T I_T O O O B_LOC I_LOC O O O O O O B_LOC I_LOC I_LOC I_LOC I_LOC O O O B_T I_T I_T I_T I_T 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 O O O O O O O O
每一个字都有一个对应的token,其中B_T I_T I_T I_T代表时间的实体,B_LOC I_LOC代表地名实体,大写字母B表示实体的起止符号。o代表非实体的字。
所以目标任务就是将性质为实体的字给它预测为相对应的标签,常见的实体主要有人名、地名、机构名、时间等等。
所以文本和标签都得转换成序列格式,方便后面的模型训练和预测。
二、基于tf2.x的bilstm-crf模型
代码如下:
class BilstmCRF(tf.keras.Model): ''' bilstm+crf实体识别网络结构 ''' def __init__(self, config, vocab_size, word_vectors): self.config = config self.vocab_size = vocab_size self.word_vectors = word_vectors #定义输入 word_ids = tf.keras.layers.Input(shape=(None,), dtype=tf.int64, name='input_word_ids') #embedding层 class GatherLayer(tf.keras.layers.Layer): def __init__(self, config, vocab_size, word_vectors): super(GatherLayer, self).__init__() self.config = config self.vocab_size = vocab_size self.word_vectors = word_vectors def build(self, input_shape): with tf.name_scope('embedding'): if not self.config['use_word2vec']: self.embedding_w = tf.Variable(tf.keras.initializers.glorot_normal()( shape=[self.vocab_size, self.config['embedding_size']], dtype=tf.float32), trainable=True, name='embedding_w') else: self.embedding_w = tf.Variable(tf.cast(self.word_vectors, tf.float32), trainable=True, name='embedding_w') self.build = True def call(self, indices): return tf.gather(self.embedding_w, indices, name='embedded_words') def get_config(self): config = super(GatherLayer, self).get_config() return config # 利用词嵌入矩阵将输入数据转成词向量,shape=[batch_size, seq_len, embedding_size] embedded_words = GatherLayer(config, vocab_size, word_vectors)(word_ids) #bi-lstm层 forward_layer = tf.keras.layers.LSTM(self.config['hidden_size'], dropout=self.config['dropout_rate'], return_sequences=True) backward_layer = tf.keras.layers.LSTM(self.config['hidden_size'], dropout=self.config['dropout_rate'], return_sequences=True, go_backwards=True) #双向网络层,得到的结果拼接,维度大小为[batch_size, forward_size+backward_size] lstm_res = tf.keras.layers.Bidirectional(forward_layer, backward_layer=backward_layer)(embedded_words) #crf层 decoded_sequence, potentials, sequence_length, chain_kernel = CRF(self.config['tag_categories'])(lstm_res) #输出为【batch_size, seq_len, num_tags] self.logits = potentials outputs = dict(logits=self.logits, decoded_outputs=decoded_sequence) super(BilstmCRF, self).__init__(inputs=[word_ids], outputs=outputs)
三、模型训练、保存及预测
完整的工程代码可以到https://github.com/dextroushands/nlp_tasks进行使用,包括模型训练保存预测一系列步骤。