注意:以下翻译的准确性尚未经过验证。这是使用 AIP ↗ 从原始英文文本进行的机器翻译。

示例: spaCy 自然语言处理

已淘汰的功能

以下文档描述了不再推荐在平台中使用的 foundry_ml 库。相反,使用 palantir_models 库。您还可以通过一个示例学习如何将模型从 foundry_ml 迁移到 palantir_models 框架。

foundry_ml 库将于2025年10月31日移除,这与计划淘汰Python 3.9相对应。

spaCy ↗ 是一个流行的开源软件库,用于高级自然语言处理(NLP)。此示例将引导您通过 foundry_ml 阶段注册表注册一个 spaCy 模型。此代码遵循 spaCy 网站上的示例,自定义 spaCy 的词元化类 ↗,并利用命名实体识别模型。

先决条件

本教程建立在Foundry中模型集成的基本构建块之上,并假设您熟悉以下内容:

  1. 理解 Foundry 中的 Python 模型
  2. 理解如何将自定义阶段添加到 foundry_ml 阶段注册表。有关更多信息,请参阅添加额外库支持文档。请注意,本教程实现了该文档中详细说明的大部分步骤。
  3. 理解 代码仓库 如何管理其 Python 环境

本教程假设预训练的 spaCy 语言模型在您的创作环境中可用。如果您没有看到它可用,您可能需要通过开源的 conda 频道启用访问权限,或设置自己的私有 conda 频道,使其在您的创作环境中可用。请联系您的 Palantir 代表以获得指导。

第一步:定义自定义词元化器和模型类

我们希望创建一个模型,该模型接受包含“text”列的数据帧,并将模型应用于每一行。为此,我们需要定义一个包装类,SpacyNERModel,它将注册变换函数、序列化器和反序列化器。所有这些装饰函数都是 Foundry 正确序列化和执行模型所必需的。

第一步是创建一个类型为“Python 库”的新代码仓库并设置项目结构。在此示例中,我们创建了 spacy-custom-ner-stage 仓库,其中包含一个 spacy_custom_stage 文件夹,内有两个 Python 文件,model.pymodel_class_registry.py。请注意,您不必将下面定义的代码分成两个文件,但我们在此处这样做是为了提供更清晰的概念划分。

├── conda_recipe
│   └── meta.yaml                # Conda包的元数据文件
├── settings.gradle              # Gradle构建工具的设置文件
├── src
│   ├── spacy_custom_stage       # 自定义Spacy阶段的源代码目录
│   │   ├── __init__.py          # 初始化模块,标识此目录为Python包
│   │   └── model.py             # 包含模型相关代码的模块
│   │   └── model_class_registry.py # 模型类注册表模块
│   ├── setup.cfg                # Python项目的配置文件
│   └── setup.py                 # 安装脚本,用于定义包的构建信息
└── README.md                    # 项目的自述文件,通常包含项目概述和使用说明

model.py文件中,我们将按照spaCy教程编写一个自定义词元化器,并定义我们的新模型类:

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import spacy from spacy.tokenizer import Tokenizer # 创建自定义分词器 def custom_tokenizer(nlp): import re special_cases = {":)": [{"ORTH": ":)"}]} # 特殊情况处理,例如 ":)" 表情符号 prefix_re = re.compile(r'''^[[("']''') # 前缀正则表达式 suffix_re = re.compile(r'''[])"']$''') # 后缀正则表达式 infix_re = re.compile(r'''[-~]''') # 中缀正则表达式 simple_url_re = re.compile(r'''^https?://''') # 简单的 URL 正则表达式匹配 return Tokenizer(nlp.vocab, rules=special_cases, prefix_search=prefix_re.search, suffix_search=suffix_re.search, infix_finditer=infix_re.finditer, url_match=simple_url_re.match) # 定义 Foundry ML 注册表的包装类 class SpacyNERModel(): # 初始化时接受加载的语言模型名称,并使用自定义分词器 def __init__(self, model_name): self.spacy = spacy.load(model_name) self.spacy.tokenizer = custom_tokenizer(self.spacy) # 使用加载的 SpaCy 模型返回提取的实体 # 这个函数可以适应于执行不同的自然语言处理任务 def predict(self, text): doc = self.spacy(text) results = [(ent.text, ent.start_char, ent.end_char, ent.label_) for ent in doc.ents] return results # 定义一个针对数据框操作的预测函数,假设数据框中存在 "text" 列 def predict_df(self, df): df["entities"] = df["text"].apply(self.predict) return df

以上代码实现了一个使用 SpaCy 进行命名实体识别(NER)的模型类。通过自定义分词器来处理特殊符号和匹配模式,SpacyNERModel 类可以对文本进行实体识别并返回结果。此外,还提供了一个方法 predict_df,可以直接对数据框中的文本进行批量预测。

步骤2:确保您的模型类可被Foundry发现

model_class_registry.py文件中,我们将实现serializedeserializetransform函数。

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 import dill import os import tempfile # 导入新创建的模型类 from spacy_custom_stage.model import SpacyNERModel # 导入Foundry的Python函数 from foundry_ml.stage.flexible import stage_transform, register_stage_transform_for_class from foundry_ml.stage.serialization import deserializer, serializer, register_serializer_for_class from foundry_object.utils import safe_upload_file, download_file # 注解一个函数,用于包装模型和在各阶段传递的数据 @stage_transform() def _transform(model, df): return model.predict_df(df) # 调用此函数将其注册到Python Stage Registry,force=True表示覆盖任何已有的注册转换 register_stage_transform_for_class(SpacyNERModel, _transform, force=True) # 反序列化器装饰器 @deserializer("spacy_ner_model.dill", force=True) def _deserializer(filesystem, path): with tempfile.TemporaryDirectory() as tmpdir: local_path = os.path.join(tmpdir, "file.dill") download_file(filesystem, path, local_path) with open(local_path) as f: model = dill.load(f) return model # 序列化器装饰器 @serializer(_deserializer) def _serializer(filesystem, value): path = 'spacy_ner_model.dill' with tempfile.NamedTemporaryFile() as tmp: dill.dump(value, tmp) safe_upload_file(filesystem, tmp.name, path, base64_encode=True) return path register_serializer_for_class(SpacyNERModel, _serializer, force=True)

在这个代码中,我们使用了 dill 库进行序列化和反序列化操作,定义了用于模型转换的装饰器函数,并通过注册机制将这些函数与自定义的 SpacyNERModel 类关联。序列化和反序列化处理过程中使用临时文件来安全地处理文件上传和下载。 接下来,我们需要确保所有适当的包都已添加到meta.yaml文件中。在这个示例中,文件的这一部分应类似于以下内容:

Copied!
1 2 3 4 5 6 # 运行此包所需的任何软件包 run: - python 3.8.* # 指定Python版本为3.8的任意小版本 - spacy # 自然语言处理库 - foundry_ml # 机器学习相关库 - dill # 用于序列化Python对象的库

现在,将我们刚刚创建的两个文件的内容导入到__init__.py中。注意,您不必完全遵循下面的约定。

Copied!
1 2 3 4 from spacy_custom_stage.model import SpacyNERModel # 从 spacy_custom_stage.model 导入 SpacyNERModel 类 from .model_class_registry import * # 从当前目录下的 model_class_registry 导入所有内容 __all__ = ["SpacyNERModel"] # 定义模块的公共接口,只暴露 SpacyNERModel

确保在setup.py文件中的setup()内添加以下代码。

Copied!
1 2 3 4 # 定义入口点,指定插件名称和对应的模块。 # 'foundry_ml.plugins' 是入口点组的名称 # 'plugin=spacy_custom_stage' 是入口点,其中 'plugin' 是插件的名称,'spacy_custom_stage' 是实现该插件的模块 entry_points={'foundry_ml.plugins': ['plugin=spacy_custom_stage']}

一旦您提交、搭建并标记一个版本,您的新模型类应该可以在代码工作簿或代码仓库中使用。

步骤3:创建并使用模型

在您的自定义库保存并发布后,您现在可以创建、保存和使用一个SpaCy模型。此步骤可以使用代码仓库代码工作簿完成。下面的截图和代码片段来自代码工作簿。

再次注意,en_core_web_sm是一个预训练的spaCy语言模型,可以作为Conda包导入到您的Python环境中。

确保在运行代码之前,将spacy-model-en_core_web_md和spaCy的2.3.x版本作为依赖项添加到您的编码环境中。

我们刚刚创建的Python模型类现在应该可以作为spacy-custom-ner-stage导入到您的Python环境中。请注意,如果您在代码仓库中进行开发,您还需要将spacy-custom-ner-stage添加为一个支持库

创建模型:

Copied!
1 2 3 4 5 6 7 8 9 10 11 12 import spacy from foundry_ml import Model, Stage # 导入我们的新模型类 from spacy_custom_stage import SpacyNERModel def spacy_model(): # 传入带有词向量的spacy模型 model = SpacyNERModel('en_core_web_sm') return Model(Stage(model))

现在应用模型:

Copied!
1 2 3 4 5 6 7 8 9 10 11 def model_inference(spacy_model): import pandas as pd # 示例数据集 df = pd.DataFrame({"text": ["The White House is a white building in Washington D.C.", "Cats is a Broadway musical in New York"]}) # 使用传入的spacy模型进行转换 output = spacy_model.transform(df) return output