文章目录
从头开始训练一个 NER 标注器
NER 标注的中文名为命名实体识别,与词性标注一样是自然语言处理的技术基础之一。NER 标注是指对现实世界中某个对象的名称的识别,例如法国、Donald Trump 或者微信。在这些词汇中法国是一个国家,标识为 GPE(地缘整治实体),Donald Trump 标识为 PER(人名),微信是一家公司,因此被标识为 ORG(组织)。
在spaCy的模块中常见的实体类型有:
NER标注的作用:
1)显而易见最主要的是通过模型可以识别出文本中需要的实体。
2)可以推导出实体之间的关系;例如,Rome is the capital of Italy,可以根据实体识别可以判断出 Rome 是意大利的城市而不是 R&B 艺术家,这项工作叫实体消岐(NED);
NED的使用场景可以在医学研究中消除词语歧义鉴定基因和基因产物,写作风格分析等。
接下来开始 spaCy 训练 NER 标注器。
注:本文使用 spaCy 3.0 代码实现。
一、自定义模型
1、导入所需要的包与模块
from __future__ import unicode_literals, print_function
import plac
import random
from pathlib import Path
import spacy
from spacy.training import Example
from spacy.tokens import Doc
2、导入训练样本
实体标注的索引从 0 开始 17 是最后一字符的索引 +1 ,索引参考python索引方法
# training data
TRAIN_DATA = [
('Who is Shaka Khan?', {
'entities': [(7, 17, 'PERSON')]
}),
('I like London and Berlin.', {
'entities': [(7, 13, 'LOC'), (18, 24, 'LOC')]
})
]
虽然示例中的训练样本数量不多,但是具有代表性。
二、训练模型
1、对现有的模型进行优化
if model is not None:
nlp = spacy.load(model) # 加载存在的模型
print("Loaded model '%s'" % model)
else:
nlp = spacy.blank('en') # 创建空白模型
print("Created blank 'en' model")
2、创建内置管道组件
使用 add_pipeline
函数创建流水线
if 'ner' not in nlp.pipe_names:
ner = nlp.create_pipe('ner')
nlp.add_pipe('ner', last=True)
else:
ner = nlp.get_pipe('ner')
3、添加train data的标签
for _, annotations in TRAIN_DATA:
for ent in annotations.get('entities'):
ner.add_label(ent[2])
4、构建模型
训练过程本身很简单,nlp.update()
方法为我们抽象了所有内容,由 spaCy 处理实际的机器学习和训练过程。
# 禁用流水线中所有其他组件,以便只训练/更新NER标注器
other_pipes = [pipe for pipe in nlp.pipe_names if pipe != 'ner']
with nlp.disable_pipes(*other_pipes): # 仅训练我们标注的标签,假如没有则会对所有的标签训练,
for itn in range(n_iter):
random.shuffle(TRAIN_DATA) # 训练数据每次迭代打乱顺序
losses = {} # 定义损失函数
for text, annotations in TRAIN_DATA:
# 对数据进行整理成新模型需要的数据
example = Example.from_dict(nlp.make_doc(text), annotations)
print("example:",example)
nlp.update(
[example], # 批注
drop=0.5,
sgd=optimizer, # 更新权重
losses=losses)
print(losses)
5、模型保存
if output_dir is not None:
output_dir = Path(output_dir)
if not output_dir.exists():
output_dir.mkdir()
nlp.to_disk(output_dir)
print("Saved model to", output_dir)
三、模型测试
def load_model_test(path,text):
nlp = spacy.load(path)
print("Loading from", path)
doc = nlp(text)
for i in doc.ents:
print(i.text,i.label_)
if __name__ == "__main__":
path = "./model/"
text = "Who is Shaka Khan"
load_model_test(path,text)
模型的效果如下
Loading from ./model/
Shaka Khan PERSON
可以的到 Shaka Khan 标注为 PERSON,即人名。
参考
【法】巴格夫·斯里尼瓦萨-德西坎.《自然语言处理与计算语言学》.人民邮电出版社