Spacy - 保存自定义管道

Spacy - Save custom pipeline

我正在尝试将自定义 PhraseMatcher() 组件集成到我的 nlp 管道中,这样我就可以加载自定义 Spacy 模型,而无需将我的自定义组件重新添加到通用模型每个负载。

如何加载包含自定义管道组件的 Spacy 模型?

我创建了组件,将其添加到我的管道并使用以下内容保存:

import requests
from spacy.lang.en import English
from spacy.matcher import PhraseMatcher
from spacy.tokens import Doc, Span, Token

class RESTCountriesComponent(object):
    name = 'countries'
    def __init__(self, nlp, label='GPE'):
        self.countries = [u'MyCountry', u'MyOtherCountry']
        self.label = nlp.vocab.strings[label]
        patterns = [nlp(c) for c in self.countries]
        self.matcher = PhraseMatcher(nlp.vocab)
        self.matcher.add('COUNTRIES', None, *patterns)        
    def __call__(self, doc):
        matches = self.matcher(doc)
        spans = []
        for _, start, end in matches:
            entity = Span(doc, start, end, label=self.label)
            spans.append(entity)
        doc.ents = list(doc.ents) + spans
        for span in spans:
            span.merge()
        return doc

nlp = English()
rest_countries = RESTCountriesComponent(nlp)
nlp.add_pipe(rest_countries)
nlp.to_disk('myNlp')

然后我尝试加载我的模型,

nlp = spacy.load('myNlp')

但是得到这个错误信息:

KeyError: u"[E002] Can't find factory for 'countries'. This usually happens when spaCy calls nlp.create_pipe with a component name that's not built in - for example, when constructing the pipeline from a model's meta.json. If you're using a custom component, you can write to Language.factories['countries'] or remove it from the model meta and add it via nlp.add_pipe instead."

我不能只将我的自定义组件添加到我的编程环境中的通用管道中。我怎样才能做我想做的事?

当您保存模型时,spaCy 将序列化所有数据并在模型的 meta.json 中存储对管道的引用。例如:["ner", "countries"]。当您重新加载模型时,spaCy 将检查元数据并通过在所谓的 "factories": 函数中查找来初始化每个管道组件,这些函数告诉 spaCy 如何构建管道组件。 (原因是您通常不希望模型在重新加载时存储和评估任意代码——至少默认情况下不会。)

在您的例子中,spaCy 试图在工厂中查找组件名称 'countries' 但失败了,因为它不是内置的。 Language.factories 是一个简单的字典,因此您可以自定义它并添加您自己的条目:

from spacy.language import Language
Language.factories['countries'] = lambda nlp, **cfg: RESTCountriesComponent(nlp, **cfg)

工厂是一个接收共享 nlp 对象和可选关键字参数(配置参数)的函数。然后它初始化组件并 returns 它。如果您在加载模型 之前 添加上述代码,它应该会按预期加载。

更高级的方法

如果您希望自动处理此问题,您还可以将组件 模型一起发送。这需要使用 spacy package 命令将其包装为 Python 包,该命令会创建所有必需的 Python 文件。默认情况下,__init__.py 仅包含加载模型的函数——但您也可以向其添加自定义函数或使用它向 spaCy 的工厂添加条目。

v2.1.0 开始(目前以 nightly version for testing), spaCy will also support providing pipeline component factories via Python entry points 的形式提供。这对于生产设置特别有用 and/or 如果您想模块化您的各个组件并将它们拆分成自己的包. 例如,您可以为您的国家组件及其工厂创建一个 Python 包,将其上传到 PyPi,对其进行版本控制并单独测试。在其 setup.py 中,您的包可以定义它的 spaCy 工厂暴露以及在哪里找到它们。spaCy 将能够自动检测它们——您需要做的就是在相同的环境中安装包。您的模型包甚至可能需要您的组件包作为依赖项,因此它会在您安装时自动安装型号。

我遇到了同样的问题,这些是我使用的步骤:

  • 1) 在包含所有不同 nlp 管道组件的 运行ning 笔记本之后保存管道,例如nlp.to_disc('pipeline_model_name')
  • 2) 使用 Spacy 构建包保存管道:运行 python setup.py sdist 在此目录中。
  • 3) pip 安装创建的包
  • 4) 按照上述说明将自定义组件放入包的 __init__.py 文件中
  • 4) 加载管道:
    • 导入spacy
    • nlp = spacy_package.load()