可解释的命名实体识别指南

446 阅读7分钟

命名实体识别(NER)是任何NLP项目的关键部分之一。我们可以看到各种实现NER的例子,但是当涉及到理解NER的过程在后台是如何工作的,或者这个过程在数据中是如何表现的,它需要更多的可解释性。在这篇文章中,我们将尝试使命名实体识别变得可解释和可说明,这将有助于理解其工作理念。本文要涉及的主要内容如下。

内容表

  1. 什么是命名实体识别(NER)?
  2. 从Kaggle提取数据
    1. 加载数据
    2. 数据预处理
  3. NER建模
  4. 解释预测

让我们先来了解一下命名实体识别。

什么是命名实体识别(NER)?

在我们的一篇文章中,我们已经讨论了命名实体是任何文本数据中的词,是存在于现实世界中的物体。这些现实世界的对象的一些例子是任何人、地方或事物的名称。这些对象在任何文本数据中都有自己的身份。例如,Narendra Singh Modi, Mumbai, Plasto water tank, 等等。这个命名实体有它自己的类别,如Narendra Modi是一个人的名字。命名实体识别(NER)可以被认为是一个让机器识别具有其类别和其他规格的对象的过程。有了这些关于命名实体识别的信息,我们也讨论了如何使用spaCy和NLTK库实现NER。

谈到NER的应用,我们发现我们可以利用这个过程对文档进行信息总结,优化搜索引擎的算法,识别不同的生物医学子部分,以及内容推荐。

通过这篇文章,我们旨在使NER的实施过程更易于解释。为此目的,我们将使用Keras和lime库。此外,我们将讨论如何在google Colab环境下从Kaggle中提取数据。让我们从提取数据开始

从Kaggle提取数据

为了从Kaggle提取数据,我们需要在Kaggle网站上有一个账户。要建立一个账户,我们使用这个链接。建立账户后,我们需要进入账户页面。例如,我的账户页面地址是

www.kaggle.com/yugeshverma…

其中yugeshvermaaim是我的账户名称。到达账户页面后,我们需要向下滚动页面到API部分。

在这个部分,我们需要点击创建新的API令牌按钮。这个按钮负责为我们提供一个名为kaggle.json的JSON文件。提取这个文件后,我们需要在google Colab环境中上传它。我们可以在google collab笔记本的左边部分找到一个上传文件的快捷方式。

这个面板上的第一个按钮是用来上传文件的,我们需要用它来上传kaggle.json文件。上传JSON文件后,我们可以使用以下命令在环境中安装Kaggle。

! pip install kaggle

安装完成后,我们需要建立一个目录。使用下面的命令,我们可以建立一个目录。

! mkdir ~/.kaggle

使用下面的命令,我们可以将kaggle.json复制到上述制作的目录中,作为。

! cp kaggle.json ~/.kaggle/

下面给出的代码需要给予文件分配的权限。

! chmod 600 ~/.kaggle/kaggle.json

现在在实现NER的过程中,我们使用的是Kaggle的数据ner_datasset,可以在这个链接中找到。这个数据包括用于命名实体识别的注释语料,可以用来进行实体分类。

为了提取这些数据,我们需要复制API命令,可以从新笔记本面板右侧的三点式面板上收集。

对于我们的数据,它有以下的API命令:

kaggle datasets download -d abhinavwalia95/entity-annotated-corpus

这个命令可以在谷歌Colab上运行:

!kaggle datasets download -d abhinavwalia95/entity-annotated-corpus

输出:

这个收集到的文件是一个压缩文件,可以用以下命令解压:

! unzip entity-annotated-corpus

输出:

在上面的内容中,我们可以根据自己的兴趣从Kaggle中提取文件进行修改。在这个数据提取之后,我们就可以准备实施NER了。让我们从加载数据开始。

加载数据

import pandas as pd
data = pd.read_csv("ner_dataset.csv", encoding="latin1").fillna(method="ffill")

检查数据

data.head()

输出:

data.describe()

输出

在上面的描述中,我们可以发现有47959个句子和35178个句子中的独特词汇,其中有42个语篇和17类对象或标签 :

上面的图片是数据集中第4句的一个例子。为了使其发挥作用,我定义了一个函数,该函数可以根据句子的编号,将所有的词加在一起,组成一个句子。有兴趣的读者可以在这里找到这个函数。

让我们检查一下这些词的标签:

print(labels[3])

输出:

数据预处理

在这一节中,我们将首先建立一个由一些常见的10000个单词组成的词汇表。下面的图片是词汇表的展示:

print(vocabulary)
len(vocabulary)

输出:

本节的第二步将是把序列填充到一个常见的长度:

print(word2idx)
print(tag2idx)

输出:

在使填充序列达到共同的长度后,我们就可以准备好分割我们的数据了:

from sklearn.model_selection import train_test_split
 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, shuffle=False)

在这些数据预处理步骤之后,我们就可以进行NER建模了。

误码率建模

在NER建模中,我们使用了一个双向LSTM模型,该模型具有0.1个递归辍学,在编译中,我使用了均方根传播作为优化器。在拟合模型时,我们使用了5个epochs。该程序的全部代码可以在这里找到。

使用下面的代码,我们可以训练我们的网络:

history = model.fit(X_train, y_train.reshape(*y_train.shape, 1),
                    batch_size=32, epochs=5,
                    validation_split=0.1, verbose=1)

训练完模型后,我们就可以对预测进行解释了。

解释预测

如上所述,我们将使用LIME库使NER的过程更容易解释。这个库是一个开源的库,用于使人工智能和机器学习更容易解释。在解释NER之前,我们需要安装这个库。我们也可以使用eli5库来使用lime库中构建的函数。 可以使用以下几行代码来安装。

!pip install lime

输出:

!pip install eli5

输出:

安装完成后,我们就可以解释NER建模的预测结果了。为了解释使用LIME的NER,我们需要把我们的问题变成一个多类分类问题。

让我们看一下我们的文本数据的第100个样本:

index = 99
label = labels[index]
text = sentences[index]
print(text)
print()
print(" ".join([f"{t} ({l})" for t, l in zip(text.split(), label)]))

输出:

让我们开始解释误码率模型的预测。为此,我们定义了一个名为NERExplainerGenerator的类,其中我们定义了一个名为get_predict_function的函数,它将向LIME库的函数TextExplainer提供预测结果。

从上面的例子中,我们将使用第6个单词并生成相应的预测函数。使用LIME的MaskExplainer模块,我们可以为LIME算法初始化一个采样器:

from eli5.lime.samplers import MaskingTextSampler
word_index = 6
predict_func = explainer_generator.get_predict_function(word_index=word_index)
sampler = MaskingTextSampler(
    replacement="UNK",
    max_replace=0.7,
    token_pattern=None,
    bow=False
)

使用采样器打印样本:

samples, similarity = sampler.sample_near(text, n_samples=6)
print(samples)

输出:

初始化来自LIME的TextExplainer模块来解释预测结果:

from eli5.lime import TextExplainer
te = TextExplainer(
    sampler=sampler,
    position_dependent=True,
    random_state=42
)
 
te.fit(text, predict_func)

拟合后我们就可以使用TestExplainer了:

te.explain_prediction(
    target_names=list(explainer_generator.idx2tag.values()),
    top_targets=4
)

输出:

在上面的输出中,我们可以看到,我们已经使NER的建模变得更容易解释。在输出中,我们可以看到印度这个词被强烈地突出显示,这意味着印度作为任何对象的名称的概率较高,而且数据集拥有的印度经常作为一个国家的名称。

最后的话

在这篇文章中,我们讨论了如何使用Keras库进行命名实体识别,以及如何使用LIME库来使其更容易解释。我们了解了命名实体识别是如何工作的,以及它在数据中的表现。

参考资料