如何使用Keras为自定义NER构建深度神经网络

如何使用Keras为自定义NER构建深度神经网络

在这篇文章中,我们将学习如何使用Keras创建一个简单的神经网络来从非结构化文本数据中提取信息(NER)。

模型架构

在这里,我们将使用BILSTM + CRF层。LSTM层用于过滤不需要的信息,将仅保留重要的特征/信息,而CRF层用于处理序列数据。

BI-LSTM层

BI-LSTM用于为我们的单词生成向量表示。 它以句子中的每个单词作为输入,并在两个方向(即正向和反向)上生成每个单词的向量表示,其中正向访问过去的信息而反向访问将来的信息。 然后将其与CRF层合并。

CRF层

CRF层是BI-LSTM层之上的优化。它可用于基于过去的属性标签有效地预测当前标签。

如何使用Keras为自定义NER构建深度神经网络

数据预处理

加载数据

在本文中,我使用机器学习数据集(https://www.kaggle.com/abhinavwalia95/entity-annotated-corpus)。对于我们的机器学习模型,我们需要一个包含“ Sentence_id” /“ Sentence”列,“ word”列和“ tag”列的data frame。Python代码如下:

import pandas as pddf = pd.read_csv("/kaggle/input/entity-annotated-corpus/ner.csv", encoding = "ISO-8859-1", error_bad_lines=False)data = df[['sentence_idx','word','tag']]data.head()

如何使用Keras为自定义NER构建深度神经网络

在SentenceGetter中包装输入数据

加载数据之后,我们将使用SentenceGetter类来检索带有标签的句子。Python实现如下:

class SentenceGetter(object):        def __init__(self, dataset):        self.n_sent = 1        self.dataset = dataset        self.empty = False        agg_func = lambda s: [(w, t) for w,t in zip(s["word"].values.tolist(),                                                        s["tag"].values.tolist())]        self.grouped = self.dataset.groupby("sentence_idx").apply(agg_func)        self.sentences = [s for s in self.grouped]        def get_next(self):        try:            s = self.grouped["Sentence: {}".format(self.n_sent)]            self.n_sent += 1            return s        except:            return None          getter = SentenceGetter(data)sentences = getter.sentencesprint(sentences[1:3])

如何使用Keras为自定义NER构建深度神经网络

这是三个句子的样子:

如何使用Keras为自定义NER构建深度神经网络

单词和标签词典

Keras(和大多数其他机器学习模型)期望所有id都是数字,这是节省内存的优化。我们将使用word2idx字典将每个单词转换为相应的整数ID,并使用tag2idx将tag转换为整数ID。

from math import nanwords = list(set(data["word"].values))n_words = len(words)tags = []for tag in set(data["tag"].values):    if tag is nan or isinstance(tag, float):        tags.append('unk')    else:        tags.append(tag)n_tags = len(tags)from future.utils import iteritemsword2idx = {w: i for i, w in enumerate(words)}tag2idx = {t: i for i, t in enumerate(tags)}idx2tag = {v: k for k, v in iteritems(tag2idx)}

如何使用Keras为自定义NER构建深度神经网络

Pad Sequence

BI-LSTM层期望所有文本/句子的长度相同。我们将填充大小选择为最长句子的长度。Python代码如下:

from keras.preprocessing.sequence import pad_sequencesfrom keras.utils import to_categoricalfrom sklearn.model_selection import train_test_splitmaxlen = max([len(s) for s in sentences])X = [[word2idx[w[0]] for w in s] for s in sentences]X = pad_sequences(maxlen=maxlen, sequences=X, padding="post",value=n_words - 1)y = [[tag2idx[w[1]] for w in s] for s in sentences]y = pad_sequences(maxlen=maxlen, sequences=y, padding="post", value=tag2idx["O"])y = [to_categorical(i, num_classes=n_tags) for i in y]# Split train and test dataX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

如何使用Keras为自定义NER构建深度神经网络

创建模型(并了解层参数)

输入层

输入层采用形状参数,该参数是表示输入数据维数的元组。

嵌入层

基本上,它是一个字典查找,它以整数作为输入并返回关联的向量。它包含三个参数:

  • input_dim:文本数据中词汇的大小,即n_words + 1
  • output_dim:嵌入的维数
  • input_length:输入序列的长度,即最长句子的长度

BI-LSTM层

它包含五个参数:

  • units:输出空间的维数
  • return_sequences:如果return_sequence = True,则返回完整的输出序列,否则,返回输出序列中的最后一个输出。
  • dropout:输入线性转换要下降的单位的分数。它介于0和1之间。
  • recurrent_dropout:recurrent状态的线性转换要下降的单位的分数。它介于0和1之间。
  • kernel_initializer:核权重矩阵的初始化程序,用于输入的线性转换。

TimeDistributed层

它是一个包装器,允许我们对序列中的每个元素独立地应用一个层。它用于序列分类,以保持输入和输出的一对一关系。

CRF层

我们没有应用任何自定义的CRF层。我们已经将输出类的数量传递给了CRF层。

机器学习模型Python代码

from keras.models import Model, Inputfrom keras.layers import LSTM, Embedding, Dense, TimeDistributed, Dropout, Bidirectionalimport keras as kfrom keras_contrib.layers import CRFinput = Input(shape=(140,))word_embedding_size = 150# Embedding Layermodel = Embedding(input_dim=n_words, output_dim=word_embedding_size, input_length=140)(input)# BI-LSTM Layermodel = Bidirectional(LSTM(units=word_embedding_size,                            return_sequences=True,                            dropout=0.5,                            recurrent_dropout=0.5,                            kernel_initializer=k.initializers.he_normal()))(model)model = LSTM(units=word_embedding_size * 2,              return_sequences=True,              dropout=0.5,              recurrent_dropout=0.5,              kernel_initializer=k.initializers.he_normal())(model)# TimeDistributed Layermodel = TimeDistributed(Dense(n_tags, activation="relu"))(model)  # CRF Layercrf = CRF(n_tags)out = crf(model)  # outputmodel = Model(input, out)

如何使用Keras为自定义NER构建深度神经网络

拟合和评估模型

编译模型

在训练模型之前,我们需要配置学习过程。它包含三个参数:

  • 优化器:它将根据看到的数据及其损失函数进行自我更新
  • 损失:它将能够根据训练数据衡量其性能。
  • 指标:机器学习模型在训练和测试期间要评估的指标列表。

回调列表

当且仅当验证精度提高时,它才用于将模型权重更新/保存到模型文件。它包含五个参数:

  • filepath:目标模型文件的路径
  • monitor:监视模型的验证准确性
  • verbose:如果verbose = 1,它将显示进度条和每个epoch一行,如果verbose = 0,它将不显示任何内容,如果verbose = 2,它将只显示每个epoch一行。
  • save_best_only:如果save_best_only = True,则根据监视数量的最新最佳模型将不会被覆盖。
  • mode:如果我们希望将其最小化,则将监视值设为val_loss,将mode ='min'设置;如果我们要将其最大化,将set _ ='max'进行监视,将其设为val_acc。

拟合模型

它包含七个参数:

  • X:输入数据
  • y:目标数据
  • batch_size:每个梯度更新的样本数,batch_size将默认为32。
  • epochs:epoch是对所提供的整个x和y数据的迭代。训练模型的epochs数。
  • validate_split:将训练数据的一部分用作验证数据。
  • verbose:如果verbose = 0,它将不显示任何内容,如果verbose = 1,它将显示进度条和每个epoch一行,如果verbose = 2,它将只显示每个epoch一行。
  • callbacks:评估期间要应用的回调列表。
from keras.callbacks import ModelCheckpointimport matplotlib.pyplot as plt#Optimiser adam = k.optimizers.Adam(lr=0.0005, beta_1=0.9, beta_2=0.999)# Compile modelmodel.compile(optimizer=adam, loss=crf.loss_function, metrics=[crf.accuracy, 'accuracy'])model.summary()# Saving the best model onlyfilepath="ner-bi-lstm-td-model-{val_accuracy:.2f}.hdf5"checkpoint = ModelCheckpoint(filepath, monitor='val_accuracy', verbose=1, save_best_only=True, mode='max')callbacks_list = [checkpoint]# Fit the best modelhistory = model.fit(X, np.array(y), batch_size=256, epochs=10, validation_split=0.2, verbose=1, callbacks=callbacks_list)# Plot the graph plt.style.use('ggplot')def plot_history(history):    accuracy = history.history['accuracy']    val_accuracy = history.history['val_accuracy']    loss = history.history['loss']    val_loss = history.history['val_loss']    x = range(1, len(accuracy) + 1)    plt.figure(figsize=(12, 5))    plt.subplot(1, 2, 1)    plt.plot(x, accuracy, 'b', label='Training acc')    plt.plot(x, val_accuracy, 'r', label='Validation acc')    plt.title('Training and validation accuracy')    plt.legend()    plt.subplot(1, 2, 2)    plt.plot(x, loss, 'b', label='Training loss')    plt.plot(x, val_loss, 'r', label='Validation loss')    plt.title('Training and validation loss')    plt.legend()plot_history(history)

如何使用Keras为自定义NER构建深度神经网络

如何使用Keras为自定义NER构建深度神经网络