使用SpaCy构建自定义 NER 模型

2021-11-23 16:28:50 浏览数 (1)

点击上方“Deephub Imba”,关注公众号,好文章不错过 !

什么是NER?

命名实体识别(NER)是一种自然语言处理技术,用于在给定的文本内容中提取适当的实体,并将提取的实体分类到预定义的类别下。简单来说,NER 是一种用于从给定文本中提取诸如人名、地名、公司名称等实体的技术。在信息检索方面,NER 有其自身的重要性。

NER是如何工作的?

在阅读文本后人类可以识别一些常见的实体,如人名、日期等。但是要让计算机做同样的事情,我们必须帮助计算机进行学习才能为我们完成任务。这里就需要需要利用自然语言处理 (NLP) 和机器学习 (ML) 了。NLP 的作用是让计算机通过了解语言的模式和规则来阅读文本、与人类交流、理解他们并对其进行解释。而机器学习的作用是帮助机器及时学习和改进。

我们将 NER 的工作定义为两步过程,1. 识别命名实体 2. 对命名实体进行分类。

让我们举个例子。

代码语言:javascript复制
doc = nlp('Mr.Sundar Pichai, the CEO of Google Inc. was born in 1972 in India')
print([(X.text, X.label_) for X in doc.ents])

输出是这样的

代码语言:javascript复制
[('Sundar Pichai', 'PERSON'), ('Google Inc.', 'ORG'), ('1972', 'DATE'), ('India', 'GPE')]

NER 算法可以突出显示和提取给定文本中的特定实体。

代码语言:javascript复制
displacy.render(doc, style='ent', jupyter=True)

Spacy 库允许我们通过根据特定上下文更新现有模型来训练 NER,也可以训练新的 NER 模型。在本文中,我们将探讨如何构建自定义 NER 模型以从简历数据中提取教育详细信息。

构建自定义 NER 模型

导入必要的库

就像在启动新项目之前执行仪式一样,我们必须导入必要的库。

代码语言:javascript复制
from __future__ import unicode_literals, print_function

import random
from pathlib import Path
import spacy
from tqdm import tqdm
from spacy.training.example import Example
import pickle

训练数据

首先,我们需要创建实体类别,例如学位、学校名称、位置、百分比和日期,并将相关训练数据提供给 NER 模型。

Spacy 库以包含文本数据和字典的元组形式接收训练数据。字典应该在命名实体的文本和类别中包含命名实体的开始和结束索引。

代码语言:javascript复制
TRAIN_DATA = [(“Higher School Certificate, Parramatta Marist High School, Westmead (1998)”,{“entities”:[(0,25,”degree”),(27,56,”school_name”),(58,66,”location”),(68,72,”date”)]}),

(“Bachelor of Business, University of Western Sydney (2005) “,{“entities”:[(0,20,”degree”),(22,43,”school_name”),(44,50,”location”),(52,56,”date”)]}),

(“2007–2010 BCA (Bachelor of Computer Application) from Khalsa college for women, Amritsar (Affiliated to Guru Nanak Dev University (G.N.D.U) India “,{“entities”:[(0,9,”date”),(12,50,”degree”),(54,78,”school_name”),(80,88,”location”)]}),

(“2010–2013 MCA (Masters in Computer Applications) from Amritsar College of Engineering, Amritsar (Affiliated to Punjab Technical University (P.T.U) India. “,{“entities”:[(0,9,”date”),(10,48,”degree”),(54,85,”school_name”),(87,95,”location”)]})]

创建模型

构建自定义模型的第一步是创建一个空白的“en”模型。该空白模型是为了进行NER过程而建立的。

代码语言:javascript复制
model = None
output_dir=Path("ner/")
n_iter=100

#load the model

if model is not None:
    nlp = spacy.load(model)  
    print("Loaded model '%s'" % model)
else:
    nlp = spacy.blank('en')  
    print("Created blank 'en' model")

构建流水线

下一步是使用create_pipe函数只使用NER设置操作步骤。

代码语言:javascript复制
if 'ner' not in nlp.pipe_names:
    ner = nlp.create_pipe('ner')
    nlp.add_pipe(ner, last=True)
else:
    ner = nlp.get_pipe('ner')

训练模型

在开始训练模型之前,我们必须使用ner.add_label()方法将命名实体(标签)的类别添加到' ner ',然后我们必须禁用除' ner '之外的其他组件,因为这些组件在训练时不应该受到影响。我们通过使用nlp.disable_pipes()方法在训练时禁用这些组件。

为了训练“ner”模型,模型必须在训练数据上循环,以获得足够的迭代次数。为此,我们使用n_iter,它被设置为100。为了确保模型不会根据示例的顺序进行泛化,我们将在每次迭代之前使用random.shuffle()函数随机打乱训练数据。

我们使用tqdm()函数来创建进度条。示例中保存训练过程的信息。它存储两个对象,一个用于保存管道的预测,另一个用于保存引用数据。Example.from_dict(doc,annotations)方法用于从预测的文档(doc)和作为字典提供的引用注解(annotation)构造一个Example对象。nlp_update()函数可用于训练识别器。

代码语言:javascript复制
for _, annotations in TRAIN_DATA:
    for ent in annotations.get('entities'):
        ner.add_label(ent[2])
example = []
other_pipes = [pipe for pipe in nlp.pipe_names if pipe != 'ner']
with nlp.disable_pipes(*other_pipes):  # only train NER
    optimizer = nlp.begin_training()
    for itn in range(n_iter):
        random.shuffle(TRAIN_DATA)
        losses = {}
        for text, annotations in tqdm(TRAIN_DATA):
            doc = nlp.make_doc(text)
            example = Example.from_dict(doc, annotations)
            nlp.update(
                [example], 
                drop=0.5,  
                sgd=optimizer,
                losses=losses)
        print(losses)

保存模型

训练完成后变量中的模型会保存在output_dir,并将模型导出为pkl文件。

代码语言:javascript复制
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)
pickle.dump(nlp, open( "education nlp.pkl", "wb" ))

测试训练的模型

代码语言:javascript复制
doc=nlp("•2015-2017, BE Chemical Engineering, Coimbatore Institute of Technology , India")
for ent in doc.ents:
    print(ent.label_  '  ------>   '   ent.text)

输出是这样的

代码语言:javascript复制
date  ------>   2015-2017
degree  ------>   BE Chemical Engineering
school_name  ------>   Coimbatore Institute of Technology
location  ------>   India

以上使用SpaCy可以快速的训练我们的自定义模型,它的优点是:

  1. SpaCy NER模型只需要几行注释数据就可以快速学习。训练数据越多,模型的性能越好。
  2. 有许多开源注释工具可用于为SpaCy NER模型创建训练数据。

但也会有一些缺点

  1. 歧义和缩写——识别命名实体的主要挑战之一是语言。识别有多种含义的单词是很困难的。
  2. 现在不太常用的词汇。比如人名、地名等,可能会有一些问题

总结

对于从简历中提取实体,我们更喜欢定制的NER而不是预先训练的NER。这是因为预训练的NER模型将只有常见的类别,如PERSON,ORG,GPE等。但是,当我们构建一个定制的NER模型时,我们可以拥有自己的一组类别,这组类别适合于我们正在处理的上下文,比如以下的应用:

  1. 从非结构化文本数据中提取结构-从简历中提取像教育和其他专业信息的实体。
  2. 推荐系统——NER可以通过从一个文档中提取实体并将这些实体存储在关系数据库中来帮助推荐算法。数据科学团队可以创建工具,推荐其他有类似实体的文档。
  3. 客户支持- NER可用于对客户登记的投诉进行分类,并将其分配给组织内应处理该投诉的相关部门。
  4. 高效的搜索算法- NER可以在所有文档上运行,提取实体并单独存储。下一次用户搜索一个词时,该搜索词将与每个文档中更小的实体列表相匹配,这将提高的搜索执行速度。

作者:Abhishek Ravichandran

喜欢就关注一下吧:

点个 在看 你最好看!

0 人点赞