命名实体识别 (NER)#
本笔记本来自 AI for Beginners Curriculum。
在这个示例中,我们将学习如何在 命名实体识别的标注语料库 数据集上训练 NER 模型。在开始之前,请将 ner_dataset.csv 文件下载到当前目录中。
import pandas as pd
from tensorflow import keras
import numpy as np准备数据集#
我们将从将数据集读取到一个数据框开始。如果你想了解更多关于使用 Pandas 的内容,可以访问我们的数据科学入门中的数据处理课程。
df = pd.read_csv('ner_dataset.csv',encoding='unicode-escape')
df.head()| Sentence # | Word | POS | Tag | |
|---|---|---|---|---|
| 0 | Sentence: 1 | Thousands | NNS | O |
| 1 | NaN | of | IN | O |
| 2 | NaN | demonstrators | NNS | O |
| 3 | NaN | have | VBP | O |
| 4 | NaN | marched | VBN | O |
让我们获取唯一标签并创建查找字典,以便我们可以将标签转换为类别编号:
tags = df.Tag.unique()
tagsarray(['O', 'B-geo', 'B-gpe', 'B-per', 'I-geo', 'B-org', 'I-org', 'B-tim',
'B-art', 'I-art', 'I-per', 'I-gpe', 'I-tim', 'B-nat', 'B-eve',
'I-eve', 'I-nat'], dtype=object)id2tag = dict(enumerate(tags))
tag2id = { v : k for k,v in id2tag.items() }
id2tag[0]'O'现在我们需要对词汇做同样的处理。为简单起见,我们将在不考虑词频的情况下创建词汇表;在实际应用中,您可能需要使用 Keras 向量化工具,并限制单词的数量。
vocab = set(df['Word'].apply(lambda x: x.lower()))
id2word = { i+1 : v for i,v in enumerate(vocab) }
id2word[0] = '<UNK>'
vocab.add('<UNK>')
word2id = { v : k for k,v in id2word.items() }我们需要创建一个句子数据集用于训练。让我们遍历原始数据集,并将所有单独的句子分离为 X(单词列表)和 Y(标记列表):
X,Y = [],[]
s,t = [],[]
for i,row in df[['Sentence #','Word','Tag']].iterrows():
if pd.isna(row['Sentence #']):
s.append(row['Word'])
t.append(row['Tag'])
else:
if len(s)>0:
X.append(s)
Y.append(t)
s,t = [row['Word']],[row['Tag']]
X.append(s)
Y.append(t)
def vectorize(seq):
return [word2id[x.lower()] for x in seq]
def tagify(seq):
return [tag2id[x] for x in seq]
Xv = list(map(vectorize,X))
Yv = list(map(tagify,Y))
Xv[0], Yv[0]([10386,
23515,
4134,
29620,
7954,
13583,
21193,
12222,
27322,
18258,
5815,
15880,
5355,
25242,
31327,
18258,
27067,
23515,
26444,
14412,
358,
26551,
5011,
30558],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0])为了简单起见,我们将所有句子用0标记填充到最大长度。在现实生活中,我们可能希望使用更聪明的策略,仅在一个小批量内填充序列。
X_data = keras.preprocessing.sequence.pad_sequences(Xv,padding='post')
Y_data = keras.preprocessing.sequence.pad_sequences(Yv,padding='post')定义标记分类网络#
我们将使用两层双向 LSTM 网络进行标记分类。为了对最后一层 LSTM 的每个输出应用密集分类器,我们将使用 TimeDistributed 构造,它会在每一步将相同的密集层复制到 LSTM 的每个输出:
maxlen = X_data.shape[1]
vocab_size = len(vocab)
num_tags = len(tags)
model = keras.models.Sequential([
keras.layers.Embedding(vocab_size, 300, input_length=maxlen),
keras.layers.Bidirectional(keras.layers.LSTM(units=100, activation='tanh', return_sequences=True)),
keras.layers.Bidirectional(keras.layers.LSTM(units=100, activation='tanh', return_sequences=True)),
keras.layers.TimeDistributed(keras.layers.Dense(num_tags, activation='softmax'))
])
model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])
model.summary()Model: "sequential_3"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_4 (Embedding) (None, 104, 300) 9545400
bidirectional_6 (Bidirectio (None, 104, 200) 320800
nal)
bidirectional_7 (Bidirectio (None, 104, 200) 240800
nal)
time_distributed_3 (TimeDis (None, 104, 17) 3417
tributed)
=================================================================
Total params: 10,110,417
Trainable params: 10,110,417
Non-trainable params: 0
_________________________________________________________________
请注意,这里我们为数据集明确指定了 maxlen——如果我们希望网络能够处理可变长度的序列,那么在定义网络时需要更巧妙一些。
现在让我们开始训练模型。为了加快速度,我们只训练一个周期,但你可以尝试训练更长时间。此外,你可能希望将数据集的一部分分离出来作为训练数据集,以观察验证准确率。
model.fit(X_data,Y_data)1499/1499 [==============================] - 740s 488ms/step - loss: 0.0667 - acc: 0.9841
<keras.callbacks.History at 0x16f0bb2a310>测试结果#
现在让我们看看实体识别模型在一个示例句子上的表现:
sent = 'John Smith went to Paris to attend a conference in cancer development institute'
words = sent.lower().split()
v = keras.preprocessing.sequence.pad_sequences([[word2id[x] for x in words]],padding='post',maxlen=maxlen)
res = model(v)[0]r = np.argmax(res.numpy(),axis=1)
for i,w in zip(r,words):
print(f"{w} -> {id2tag[i]}")john -> B-per
smith -> I-per
went -> O
to -> O
paris -> B-geo
to -> O
attend -> O
a -> O
conference -> O
in -> O
cancer -> B-org
development -> I-org
institute -> I-org
关键点#
即使是简单的 LSTM 模型在命名实体识别(NER)任务中也能表现出不错的效果。然而,如果想要获得更好的结果,可以考虑使用大型预训练语言模型,例如 BERT。使用 Huggingface Transformers 库训练 BERT 进行 NER 的方法可以在这里找到。
免责声明:
本文档使用AI翻译服务 Co-op Translator 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用此翻译而引起的任何误解或误读不承担责任。