Snowflake Model Registry (Snowpark ML Ops)

备注

本主题中描述的模型注册表 API 从包版本 1.5.0 开始正式发布。

作为 Snowpark ML Operations (MLOps) 的一部分,Snowflake Model Registry 允许客户在 Snowflake 中安全地管理模型及其元数据,而无论其来源如何。模型注册表将机器学习模型存储为 Snowflake 中的一级架构级对象,以便组织中的其他人可以轻松找到和使用这些模型。您可以使用 Snowpark ML 库中的类创建注册表,并在其中存储模型。模型可以有多个版本,您可以将一个版本指定为默认版本。

一旦存储了模型,就可以调用它的方法(相当于函数或存储过程)来在 Snowflake 虚拟仓库 中执行模型操作,比如推理。

小技巧

请参阅 ` 通过 Snowpark ML 使用机器学习简介 <https://quickstarts.snowflake.com/guide/intro_to_machine_learning_with_snowpark_ml_for_python/#0 (https://quickstarts.snowflake.com/guide/intro_to_machine_learning_with_snowpark_ml_for_python/#0)>`_,其中提供了一个 Snowpark ML 中的端到端工作流程示例,包括 Snowflake Model Registry。

如果您在 Microsoft Azure Machine Learning 或 Amazon SageMaker 中拥有模型,请参阅 ` 将模型从 Azure ML 和 SageMaker 部署到 Snowpark ML <https://quickstarts.snowflake.com/guide/deploying_models_from_azureml_and_sagemaker_to_snowparkml/index.html?index=..%2F..index#0 (https://quickstarts.snowflake.com/guide/deploying_models_from_azureml_and_sagemaker_to_snowparkml/index.html?index=..%2F..index#0)>`_。

Snowflake Model Registry API 中最重要的类是:

Snowflake Model Registry 支持以下类型的模型。

本主题介绍如何使用 Snowpark ML 在 Python 中执行注册表操作。您还可以在 SQL 中执行许多注册表操作。有关更多信息,请参阅 模型命令

与非公开预览版的区别

Snowflake 先前曾以非公开形式为部分客户提供了一个模型注册表。与非公开预览版相比,本主题中介绍的注册表功能在功能和 APIs 上有重大变化。最值得注意的是,模型注册表功能现在使用一个新的架构级对象,在 Snowflake 中原生托管。

有关这两种 APIs 之间的差异的详细信息,请参阅 从 Snowflake Model Registry 预览版迁移 API

所需权限

若要创建模型,您必须拥有创建模型的架构,或者拥有其 CREATE MODEL 权限。要使用模型,您必须拥有该模型或拥有该模型的 USAGE 权限。

当前限制

Snowflake Model Registry 目前有以下限制:

  • 注册表不能在 Snowflake Native Apps 中使用。

  • 模型不能跨云提供商或区域共享。

  • 模型不能克隆,在复制过程中会被跳过。

  • 目前,日志记录模型 (log_model) 和显示标签 (show_tags) 在 所有者权限存储过程 中不起作用。

打开 Snowflake Model Registry

模型是一级 Snowflake 对象,可以与其他 Snowflake 对象一起组织到数据库和架构内。Snowflake Model Registry 提供了一个 Python 类来在架构内管理模型。因此,任何 Snowflake 架构均可用作注册表。不必为此目的初始化或准备架构。Snowflake 建议为此目的创建一个或多个专用架构,例如 ML.REGISTRY。您可以使用 CREATE SCHEMA 创建架构。

在注册表中创建或修改模型之前,必须打开注册表。打开注册表将返回其引用,然后您可以使用该引用来添加新模型,并获取对现有模型的引用。

from snowflake.ml.registry import Registry

reg = Registry(session=sp_session, database_name="ML", schema_name="REGISTRY")
Copy

注册模型和版本

将模型添加到注册表中的操作称为 登记 模型。通过调用注册表的 log_model 方法来登记模型。此方法会:

  • 序列化模型(Python 对象),并通过它创建 Snowflake 模型对象。

  • 将元数据(例如描述)添加到 log_model 调用中指定的模型。

备注

模型中的单个文件不得大于 5 GB。但模型整体大小可能会超过 5 GB。

每个模型可能有任意多个版本。要登记模型的其他版本,请再次调用具有相同 model_name 但不同 version_namelog_model

备注

model_nameversion_name 都必须遵循 Snowflake 标识符语法

当模型被添加到注册表时,您不能向模型添加标签,因为标签是模型的属性,log_model 会添加特定的模型版本,只有在添加模型的第一个版本时才会创建模型。您可以在登记模型的第一个版本后 更新模型的标签

在下面的示例中,clf (“classifier”的缩写)是已在代码中其他位置创建的 Python 模型对象。您可以在注册时添加注释,如此处所示。名称和版本的组合在架构中必须唯一。您可以指定 conda_dependencies 列表;指定的包将随模型一起部署。

mv = reg.log_model(clf,
                   model_name="my_model",
                   version_name="v1",
                   conda_dependencies=["scikit-learn"],
                   comment="My awesome ML model",
                   metrics={"score": 96},
                   sample_input_data=train_features)
Copy

log_model 的实参说明如下。

必填实参

实参

描述

model

受支持模型类型的 Python 模型对象。必须可序列化(“可执行 pickle 操作”)。

model_name

模型的名称,与 version_name 一同使用,以在注册表中标识模型。在模型登记之后,不能再更改名称。必须是 有效的 Snowflake 标识符

version_name

指定模型版本的字符串,与 model_name 配合使用,以在注册表中标识模型。必须是 有效的 Snowflake 标识符

备注

模型名称和版本的组合在架构中必须唯一。

可选实参

实参

描述

code_paths

加载或部署模型时要导入的代码目录的路径列表。

comment

注释,例如对于模型的描述。

conda_dependencies

您的模型所需的 Conda 包列表。此参数以 ` Conda 格式 <https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/pkg-search.html (https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/pkg-search.html)>`__ (即 "[channel::]package [operator version]")指定包名称和可选的版本。如果未指定渠道,则假定为 Snowflake 渠道。

ext_modules

要与模型一起执行 pickle 操作的外部模块列表。支持 scikit-learn、Snowpark ML、PyTorch、TorchScript 和自定义模型。

metrics

包含链接到模型版本的指标的字典。

options

包含模型创建选项的字典。以下选项适用于所有模型类型。

  • embed_local_ml_library:是否将本地 Snowpark ML 库的副本嵌入到模型中。默认:False

  • relax_version:是否放宽依赖项的版本约束。这将用 <=x.y, <(x+1) 等说明符替换版本说明符(如 ==x.y.z)。默认:True

  • method_options:包含各方法选项的字典,其中键是方法的名称,值是包含此处描述的一个或多个选项的字典。可用选项包括:

    • case_sensitive:指示方法及其签名是否区分大小写。在 SQL 中使用时,区分大小写的方法必须放在双引号里。此选项还允许在方法名称中使用非字母字符。默认:False

    • max_batch_size:在仓库中调用时,该方法将接受的最大批次大小。默认:None (自动确定批次大小)

个别模型类型可能支持其他选项。请参阅 关于特定模型类型的说明

pip_requirements

您的模型所需的 PyPI 包的包规格列表。

python_version

模型将在其中运行的 Python 版本。默认为 None,指定仓库中可用的最新版本。

sample_input_data

包含示例输入数据的 DataFrame。模型所需的特征名称及其类型均提取自 DataFrame。必须为除 Snowpark ML 和 MLFlow 模型以及 Hugging Face pipeline 之外的所有模型提供此实参或 signatures

signatures

将方法签名建模为从目标方法名称到输入和输出签名的映射。必须为除 Snowpark ML 和 MLFlow 模型以及 Hugging Face pipeline 之外的所有模型提供此实参或 sample_input_data

log_model 会返回一个 snowflake.ml.model.ModelVersion 对象,该对象表示已添加到注册表的模型的版本。

在注册之后,模型本身就无法修改(不过您可以更改其元数据)。要删除模型及其所有版本,请使用注册表的 delete_model 方法。

删除模型

使用注册表的 delete_model 方法删除模型及其所有版本。

reg.delete_model("mymodel")
Copy

从注册表获取模型

要获取有关每个模型的信息,请使用 show_models 方法。

model_df = reg.show_models()
Copy

show_models 的结果是一个 pandas DataFrame。可用列如下所示。

描述

created_on

模型的创建日期和时间。

name

模型的名称。

database_name

存储模型的数据库。

schema_name

存储模型的架构。

owner

拥有模型的角色。

comment

为模型添加注释。

versions

JSON 数组列出模型的版本。

default_version_name

引用没有版本的模型时使用的模型的版本。

要改为获取注册表中的模型列表(每个模型都作为一个 Model 实例),请使用 models 方法。

model_list = reg.models()
Copy

要根据名称从注册表获取对特定模型的引用,请使用注册表的 get_model 方法。此方法返回一个 Model 实例。

m = reg.get_model("MyModel")
Copy

备注

Model 实例不是原始登记的 Python 模型对象的副本,而是对注册表中基础模型对象的引用。

一旦有了对模型的引用,无论是来自 models 方法返回的列表,还是通过使用 get_model 检索到的引用,都可以使用 其元数据其版本

查看和更新模型的元数据

您可以在注册表中查看和更新模型的元数据属性,包括其名称、注释、标签和指标。

检索和更新注释

使用模型的 comment 属性来检索和更新模型的注释。

print(m.comment)
m.comment = "A better description than the one I provided originally"
Copy

备注

description 属性是 comment 的别名。上面的代码也可以写成如下形式:

print(m.description)
m.description = "A better description than the one I provided originally"
Copy

检索和更新标签

标签是元数据,用于记录模型的目的、算法、训练数据集、生命周期阶段或您选择的其他信息。您可在注册模型之时或之后的任何时间设置标签。您还可以更新现有标签的值或完全移除标签。

备注

所有标签的名称(及其可能的值)必须提前使用 CREATE TAG 定义。请参阅 Object Tagging

要将模型的所有标签作为 Python 字典获取,请使用 show_tags

print(m.show_tags())
Copy

要添加新标签或更改现有标签的值,请使用 set_tag

m.set_tag("live_version", "v1")
Copy

要检索标签的值,请使用 get_tag

m.get_tag("live_version")
Copy

要移除标签,请使用 unset_tag

m.unset_tag("live_version")
Copy

重命名模型

使用 rename 方法重命名模型。

m.rename("MY-MODEL-TOO")
Copy

小技巧

指定完全限定名称作为新名称,以将模型移动到不同的数据库或架构。

使用模型版本

一个模型可以有任意多个的版本,每个版本由一个字符串标识。您可以使用自己喜欢的任何版本命名约定。登记模型实际上登记的是模型的 特定版本。要登记模型的其他版本,请再次调用具有相同 model_name 但不同 version_namelog_model

模型的一个版本由 snowflake.ml.model.ModelVersion 类的一个实例表示。

要获取模型的所有版本的列表,请调用模型对象的 versions 方法。结果是 ModelVersion 实例的列表。

version_list = m.versions()
Copy

要改为以 DataFrame 的形式获取有关每个模型的信息,请调用模型的 show_versions 方法。

version_df = m.show_versions()
Copy

所得的 DataFrame 包含以下列。

描述

created_on

模型版本的创建日期和时间。

name

版本的名称。

database_name

存储版本的数据库。

schema_name

存储版本的架构。

model_name

此版本所属的模型名称。

is_default_version

布尔值,指示此版本是否为模型的默认版本。

functions

此版本中可用的函数名称的 JSON 数组。

metadata

JSON 对象包含作为键值对的元数据(如果未指定元数据,则为 {})。

user_data

来自模型定义清单的 user_data 部分的 JSON 对象(如果未指定用户数据,则为 {}

删除模型版本

您可以使用模型的 delete_version 方法删除模型版本。

m.delete_version("rc1")
Copy

默认版本

模型的版本可指定为默认模型。设置模型的 default 属性,以获取当前默认版本(作为 ModelVersion 对象)或对其进行更改(使用字符串)。

default_version = m.default
m.default = "v2"
Copy

获取对模型版本的引用

要以 ModelVersion 实例的形式获得对模型特定版本的引用,请使用模型的 version 方法。使用模型的 default 属性获取模型的默认版本。

mv = m.version("v1")
mv = m.default
Copy

一旦您引用了模型的特定版本(例如本例中的 mv 变量),您就可以检索或更新其注释或指标,并调用模型的方法(或函数),如以下部分所示。

检索和更新注释

与模型一样,模型版本可以有注释,可以通过模型版本的 commentdescription 属性访问和设置。

print(mv.comment)
print(mv.description)

mv.comment = "A model version comment"
mv.description = "Same as setting the comment"
Copy

检索和更新指标

指标是用于跟踪预测准确度和其他模型版本特征的键值对。您可以在创建模型版本时设置指标,也可以使用 set_metric 方法设置指标。指标值可以是任何可序列化为 JSON 的 Python 对象,包括数字、字符串、列表和字典。与标签不同,指标名称和可能的值不需要预先定义。

可以使用 sklearn 的 accuracy_score 生成测试准确性指标:

from sklearn import metrics

test_accuracy = metrics.accuracy_score(test_labels, prediction)
Copy

类似地,可以使用 sklearn 生成混淆矩阵:

test_confusion_matrix = metrics.confusion_matrix(test_labels, prediction)
Copy

然后,我们可以将这些值设置为指标,如下所示。

# scalar metric
mv.set_metric("test_accuracy", test_accuracy)

# hierarchical (dictionary) metric
mv.set_metric("evaluation_info", {"dataset_used": "my_dataset", "accuracy": test_accuracy, "f1_score": f1_score})

# multivalent (matrix) metric
mv.set_metric("confusion_matrix", test_confusion_matrix)
Copy

要以 Python 字典的形式检索模型版本的指标,请使用 show_metrics

metrics = mv.show_metrics()
Copy

要删除指标,请调用 delete_metric

mv.delete_metric("test_accuracy")
Copy

导出模型版本

使用 mv.export 将模型文件导出到本地目录。如果目录不存在,则创建该目录。

mv.export("~/mymodel/")
Copy

默认情况下,导出的文件包括代码、加载模型的环境和模型权重。要导出在仓库中运行模型所需的文件,请指定 export_mode = ExportMode.FULL

mv.export("~/mymodel/", export_mode=ExportMode.FULL)
Copy

加载模型版本

使用 mv.load 加载最初添加到注册表的原始 Python 模型对象。然后,您可以使用模型进行推理,就像在 Python 代码中定义的模型一样。

clf = mv.load()
Copy

重要

为了确保模型的正确功能,目标 Python 环境(即 Python 解析器和所有库的版本)应该与模型登记时所在的环境相同。在 load 调用中指定 force=True 以强制加载模型,即使环境有所不同。

可选的 options 实参是用于加载模型的选项字典。目前,该实参仅支持 use_gpu 选项。

选项

类型

描述

默认值

use_gpu

bool

启用特定 GPU 的加载逻辑。

False

下面的示例说明了 options 实参的用法。

clf = mv.load(options={"use_gpu": True})
Copy

调用模型方法

模型版本可以具有 方法,这些方法是附加的函数,可执行这些函数来执行推理或其他模型操作。模型的版本可以具有不同的方法,这些方法的签名也可以有所不同。

要调用模型版本的方法,请使用 mv.run,指定要调用的函数的名称,并传递包含推理数据和任何其他必需参数的 Snowpark 或 pandas DataFrame。该方法在 Snowflake 仓库中执行。

该方法的返回值是 Snowpark 或 pandas DataFrame,具体取决于传入的 DataFrame 类型。Snowpark DataFrames 采用延迟计算的方式,因此只有在调用 DataFrame 的 collectshowto_pandas 方法时才会运行此类方法。

备注

调用方法时,该方法会在连接注册表时所用会话内指定的仓库中运行。请参阅 指定仓库

下面的示例阐释了模型的 predict 方法的运行。除了推理数据(此处的 test_features)之外,此模型的 predict 方法不需要任何参数。如果确实需要,其他参数将作为附加参数在推理数据之后传递。

remote_prediction = mv.run(test_features, function_name="predict")
remote_prediction.show()   # assuming test_features is Snowpark DataFrame
Copy

要查看在给定模型上可以调用哪些方法,请调用 mv.show_functions。此方法的返回值是一个 ModelFunctionInfo 对象列表。这些对象中的每一个都包括以下属性:

  • name:可从 Python 或 SQL 调用的函数的名称。

  • target_method:原始登记的模型中 Python 方法的名称。

成本注意事项

使用 Snowflake Model Registry 会产生标准的基于 Snowflake 用量的成本。这些对象包括:

  • 存储模型工件、元数据和函数的成本。有关存储成本的一般信息,请参阅 探索存储成本

  • 在暂存区之间将文件复制到 Snowflake 的成本。请参阅 COPY FILES

  • 通过 Snowsight UI 或者 SQL 接口 或 Python 接口进行无服务器模型对象操作的成本,例如显示模型和模型版本,以及更改模型注释、标签和指标。

  • 仓库计算成本,具体取决于模型的类型和用于推理的数据量。有关 Snowflake 计算成本的一般信息,请参阅 了解计算成本。以下操作会产生仓库计算成本:

    • 模型和版本创建操作。

    • 调用一个模型的方法。

关于特定模型类型的说明

此部分提供有关在 Snowflake Model Registry 中登记特定类型的模型的附加信息。

Snowpark ML

该注册表支持使用 :doc:` Snowpark ML 建模 APIs <snowpark-ml-modeling>` (模型派生自 snowpark.ml.modeling.framework.base.BaseEstimator)创建的模型。调用 log_model 时,可以在 options 字典中使用下列附加选项。

选项

描述

target_methods

可在模型对象上使用的方法的名称列表。默认情况下,Snowpark ML 模型具有以下目标方法(假设方法存在):predicttransformpredict_probapredict_log_probadecision_function

在登记 Snowpark ML 模型时,您不需要指定 sample_input_datasignatures;在拟合过程中会自动推断出这些。

示例

import pandas as pd
import numpy as np
from sklearn import datasets
from snowflake.ml.modeling.xgboost import XGBClassifier

iris = datasets.load_iris()
df = pd.DataFrame(data=np.c_[iris["data"], iris["target"]], columns=iris["feature_names"] + ["target"])
df.columns = [s.replace(" (CM)", "").replace(" ", "") for s in df.columns.str.upper()]

input_cols = ["SEPALLENGTH", "SEPALWIDTH", "PETALLENGTH", "PETALWIDTH"]
label_cols = "TARGET"
output_cols = "PREDICTED_TARGET"

clf_xgb = XGBClassifier(
        input_cols=input_cols, output_cols=output_cols, label_cols=label_cols, drop_input_cols=True
)
clf_xgb.fit(df)
model_ref = registry.log_model(
    clf_xgb,
    model_name="XGBClassifier",
    version_name="v1",
)
model_ref.run(df.drop(columns=label_cols).head(10), function_name='predict_proba')
Copy

scikit-learn

注册表支持使用 scikit-learn 创建的模型(从 sklearn.base.BaseEstimatorsklearn.pipeline.Pipeline 派生的模型)。调用 log_model 时,可以在 options 字典中使用下列附加选项。

选项

描述

target_methods

模型对象上可用方法的名称列表。scikit-learn 模型默认具有以下目标方法(假设方法存在):predicttransformpredict_probapredict_log_probadecision_function

在登记 scikit-learn 模型时,您必须指定 sample_input_datasignatures 参数,以确保注册表了解目标方法的签名。

示例

from sklearn import datasets, ensemble

iris_X, iris_y = datasets.load_iris(return_X_y=True, as_frame=True)
clf = ensemble.RandomForestClassifier(random_state=42)
clf.fit(iris_X, iris_y)
model_ref = registry.log_model(
    clf,
    model_name="RandomForestClassifier",
    version_name="v1",
    sample_input_data=iris_X,
    options={
        "method_options": {
            "predict": {"case_sensitive": True},
            "predict_proba": {"case_sensitive": True},
            "predict_log_proba": {"case_sensitive": True},
        }
    },
)
model_ref.run(iris_X[-10:], function_name='"predict_proba"')
Copy

XGBoost

注册表支持使用 XGBoost 创建的模型(从 xgboost.XGBModelxgboost.Booster 派生的模型)。调用 log_model 时,可以在 options 字典中使用下列附加选项。

选项

描述

target_methods

可在模型对象上使用的方法的名称列表。从 XGBModel 派生的模型默认具有以下目标方法(假设方法存在):predictpredict_proba。(在 v1.4.0 之前,还包括 apply。)从 Booster 派生的模型默认具有 predict 方法。

cuda_version

部署到具有 GPU 的平台时使用的 CUDA 运行时版本;默认值为 11.7。如果手动设置为 None,则无法将模型部署到具有 GPU 的平台。

在登记 XGBoost 模型时,您必须指定 sample_input_datasignatures 参数,以确保注册表了解目标方法的签名。

示例

import xgboost
from sklearn import datasets, model_selection

cal_X, cal_y = datasets.load_breast_cancer(as_frame=True, return_X_y=True)
cal_X_train, cal_X_test, cal_y_train, cal_y_test = model_selection.train_test_split(cal_X, cal_y)
params = dict(n_estimators=100, reg_lambda=1, gamma=0, max_depth=3, objective="binary:logistic")
regressor = xgboost.train(params, xgboost.DMatrix(data=cal_X_train, label=cal_y_train))
model_ref = registry.log_model(
    regressor,
    model_name="xgBooster",
    version_name="v1",
    sample_input_data=cal_X_test,
    options={
        "target_methods": ["predict"],
        "method_options": {
            "predict": {"case_sensitive": True},
        },
    },
)
model_ref.run(cal_X_test[-10:])
Copy

PyTorch

如果模型的 forward 方法接受一个或多个 torch.Tensor 实例作为输入,并返回一个 torch.Tensor 或它的一个元组,则注册表支持 PyTorch 模型(从 torch.nn.Moduletorch.jit.ModuleScript 派生的类)。该注册表在调用模型并返回结果时,会在 pandas DataFrames 与张量之间进行转换。张量对应于数据框架中的列。

例如,假设您的模型接受两个这样的张量:

import torch

class TorchModel(torch.nn.Module):
    def __init__(self, n_input: int, n_hidden: int, n_out: int, dtype: torch.dtype = torch.float32) -> None:
        super().__init__()
        self.model = torch.nn.Sequential(
            torch.nn.Linear(n_input, n_hidden, dtype=dtype),
            torch.nn.ReLU(),
            torch.nn.Linear(n_hidden, n_out, dtype=dtype),
            torch.nn.Sigmoid(),
        )

    def forward(self, tensor_1: torch.Tensor, tensor_2: torch.Tensor) -> torch.Tensor:
        return self.model(tensor_1) + self.model(tensor_2)
Copy

如果要将 torch.Tensor([[1,2],[3,4]]) 作为 tensor_1 传递,将 torch.Tensor([[5,6], [7,8]]) 作为 tensor_2 传递,请创建如下 DataFrame,以传递给模型。

import pandas as pd
tensors = pd.DataFrame([[[1,2],[5,6]],[[3,4],[7,8]]])
Copy

tensors DataFrame 的形式如下。

        0       1
0  [1, 2]  [5, 6]
1  [3, 4]  [7, 8]
Copy

类似地,如果模型返回两个张量,例如 (torch.Tensor([[1,2],[3,4]]), torch.Tensor([[5,6], [7,8]])),则结果是类似于上面这样的 DataFrame。

为 PyTorch 模型提供样本输入数据时,您必须提供张量列表(将转换为pandas DataFrame)或 DataFrame。一个列表可以包含一个张量,但单独的张量本身不能被接受。

登记模型

调用 options 时,可以在 log_model 字典中使用下列附加选项。

选项

描述

target_methods

可在模型对象上使用的方法的名称列表。PyTorch 模型默认为 forward

cuda_version

部署到具有 GPU 的平台时使用的 CUDA 运行时版本;默认值为 11.7。如果手动设置为 None,则无法将模型部署到具有 GPU 的平台。

在登记 PyTorch 模型时,您必须指定 sample_input_datasignatures 参数,以确保注册表了解目标方法的签名。

示例

import torch
import numpy as np

class TorchModel(torch.nn.Module):
        def __init__(self, n_input: int, n_hidden: int, n_out: int, dtype: torch.dtype = torch.float32) -> None:
                super().__init__()
                self.model = torch.nn.Sequential(
                        torch.nn.Linear(n_input, n_hidden, dtype=dtype),
                        torch.nn.ReLU(),
                        torch.nn.Linear(n_hidden, n_out, dtype=dtype),
                        torch.nn.Sigmoid(),
                )

        def forward(self, tensor: torch.Tensor) -> torch.Tensor:
                return self.model(tensor)

n_input, n_hidden, n_out, batch_size, learning_rate = 10, 15, 1, 100, 0.01
dtype = torch.float32
x = np.random.rand(batch_size, n_input)
data_x = torch.from_numpy(x).to(dtype=dtype)
data_y = (torch.rand(size=(batch_size, 1)) < 0.5).to(dtype=dtype)

model = TorchModel(n_input, n_hidden, n_out, dtype=dtype)
loss_function = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
for _epoch in range(100):
        pred_y = model.forward(data_x)
        loss = loss_function(pred_y, data_y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()


model_ref = registry.log_model(
    model,
    model_name="torchModel",
    version_name="v1",
    sample_input_data=[data_x],
)
model_ref.run([data_x])
Copy

TensorFlow

当模型接受和返回张量,并且可编译或已编译时,系统支持扩展 tensorflow.Moduletensorflow.keras.Model 的模型。

  • tensorflow.Module__call__ 方法或 tensorflow.keras.Modelcall 方法接受一个或多个 tensorflow.Tensortensorflow.Variable 作为输入,并返回 tensorflow.Tensortensorflow.Variable,或者这些类型之一的元组。

  • 如果您的模型扩展了 Module,则它必须可编译,这意味着 __call__ 方法使用 @tensorflow.function 修饰;请参阅 ` tf.function文档 <https://www.tensorflow.org/guide/function (https://www.tensorflow.org/guide/function)>`_。如果它扩展了 Model,则它必须已编译;请参阅 ` 编译文档 <https://www.tensorflow.org/api_docs/python/tf/keras/Model#compile (https://www.tensorflow.org/api_docs/python/tf/keras/Model#compile)>`_。

该注册表在调用模型并返回结果时,会在 pandas DataFrames 与张量之间进行转换。张量对应于数据框架中的列。

例如,假设您的模型接受两个这样的张量:

import tensorflow as tf

class KerasModel(tf.keras.Model):
    def  __init__(self, n_hidden: int, n_out: int) -> None:
        super().__init__()
        self.fc_1 = tf.keras.layers.Dense(n_hidden, activation="relu")
        self.fc_2 = tf.keras.layers.Dense(n_out, activation="sigmoid")

    def call(self, tensor_1: tf.Tensor, tensor_2: tf.Tensor) -> tf.Tensor:
        input = tensor_1 + tensor_2
        x = self.fc_1(input)
        x = self.fc_2(x)
        return x
Copy

如果要将 tf.Tensor([[1,2],[3,4]]) 作为 tensor_1 传递,将 tf.Tensor([[5,6], [7,8]]) 作为 tensor_2 传递,请创建如下 DataFrame,以传递给模型。

import pandas as pd
tensors = pd.DataFrame([[[1,2],[5,6]],[[3,4],[7,8]]])
Copy

tensors DataFrame 的形式如下。

        0       1
0  [1, 2]  [5, 6]
1  [3, 4]  [7, 8]
Copy

类似地,如果模型返回两个张量,例如 (tf.Tensor([[1,2],[3,4]]), tf.Tensor([[5,6], [7,8]])),则结果是类似于上面这样的 DataFrame。

为 TensorFlow 模型提供样本输入数据时,您必须提供张量列表(将转换为pandas DataFrame)或 DataFrame。一个列表可以包含一个张量,但单独的张量本身不能被接受。

登记模型

调用 options 时,可以在 log_model 字典中使用下列附加选项。

选项

描述

target_methods

可在模型对象上使用的方法的名称列表。TensorFlow 模型默认为 forward

cuda_version

部署到具有 GPU 的平台时使用的 CUDA 运行时版本;默认值为 11.7。如果手动设置为 None,则无法将模型部署到具有 GPU 的平台。

在登记 TensorFlow 模型时,您必须指定 sample_input_datasignatures 参数,以确保注册表了解目标方法的签名。

示例

import tensorflow as tf
import numpy as np

class KerasModel(tf.keras.Model):
        def __init__(self, n_hidden: int, n_out: int) -> None:
                super().__init__()
                self.fc_1 = tf.keras.layers.Dense(n_hidden, activation="relu")
                self.fc_2 = tf.keras.layers.Dense(n_out, activation="sigmoid")

        def call(self, tensor: tf.Tensor) -> tf.Tensor:
                input = tensor
                x = self.fc_1(input)
                x = self.fc_2(x)
                return x

n_input, n_hidden, n_out, batch_size, learning_rate = 10, 15, 1, 100, 0.01
dtype = tf.float32
x = np.random.rand(batch_size, n_input)
data_x = tf.convert_to_tensor(x, dtype=dtype)
raw_data_y = tf.random.uniform((batch_size, 1))
raw_data_y = tf.where(raw_data_y > 0.5, tf.ones_like(raw_data_y), tf.zeros_like(raw_data_y))
data_y = tf.cast(raw_data_y, dtype=dtype)

model = KerasModel(n_hidden, n_out)
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=learning_rate), loss=tf.keras.losses.MeanSquaredError())
model.fit(data_x, data_y, batch_size=batch_size, epochs=100)

model_ref = registry.log_model(
    model,
    model_name="tfModel",
    version_name="v1",
    sample_input_data=[data_x],
)
model_ref.run([data_x])
Copy

MLFlow

支持提供 PyFunc 风格的 MLFlow 模型。如果您的 MLFlow 模型具有签名,则会从模型中推断出 signature 实参。否则,必须提供 signaturesample_input_data

调用 options 时,可以在 log_model 字典中使用下列附加选项。

选项

描述

model_uri

MLFlow 模型工件的 URI。如果在模型的元数据中不可用,则必须以 model.metadata.get_model_info().model_uri 的形式提供。

ignore_mlflow_metadata

如果为 True,则不将模型的元数据导入到注册表中的模型对象。默认:False

ignore_mlflow_dependencies

如果为 True,则忽略模型元数据中的依赖项,由于 Snowflake 仓库中的包可用限制,这非常有用。默认:False

示例

import mlflow
from sklearn import datasets, model_selection, ensemble

db = datasets.load_diabetes(as_frame=True)
X_train, X_test, y_train, y_test = model_selection.train_test_split(db.data, db.target)
with mlflow.start_run() as run:
    rf = ensemble.RandomForestRegressor(n_estimators=100, max_depth=6, max_features=3)
    rf.fit(X_train, y_train)

    # Use the model to make predictions on the test dataset.
    predictions = rf.predict(X_test)
    signature = mlflow.models.signature.infer_signature(X_test, predictions)
    mlflow.sklearn.log_model(
        rf,
        "model",
        signature=signature,
    )
    run_id = run.info.run_id


model_ref = registry.log_model(
    mlflow.pyfunc.load_model(f"runs:/{run_id}/model"),
    model_name="mlflowModel",
    version_name="v1",
    conda_dependencies=["mlflow<=2.4.0", "scikit-learn", "scipy"],
    options={"ignore_mlflow_dependencies": True}
)
model_ref.run(X_test)
Copy

Hugging Face Pipeline

备注

有关特定类型的 Hugging Face Pipeline 的预期输入和输出的详细信息,请参阅 Hugging Face 管道的推断签名

transformers.Pipeline 派生的 ` 转换器 <https://huggingface.co/docs/transformers/index (link removed)>`_ 定义的 Hugging Face 模型类。下面的代码是登记兼容模型的示例。

lm_hf_model = transformers.pipeline(
    task="text-generation",
    model="bigscience/bloom-560m",
    token="...",  # Put your HuggingFace token here.
    return_full_text=False,
    max_new_tokens=100,
)

lmv = reg.log_model(lm_hf_model, model_name='bloom', version_name='v560m')
Copy

重要

基于的 huggingface_pipeline.HuggingFacePipelineModel 的模型仅包含配置数据;每次使用模型时,都会从 Hugging Face Hub 下载模型权重。

模型注册表目前仅支持将模型部署到仓库。仓库不支持外部网络访问,除非进行 特殊配置。即便已经创建了所需的外部访问集成,此时也无法指定特定模型需要哪些集成。

当前最佳实践是使用 transformers.Pipeline,如上面的示例中所示。这会将模型权重下载到您的本地系统,并将整个模型上传到仓库。这会导致了一个不需要互联网访问、独立完整的模型。

只要管道仅包含以下列表中的任务,注册表就会推断 signatures 实参。

  • conversational

  • fill-mask

  • question-answering

  • summarization

  • table-question-answering

  • text2text-generation

  • text-classification (别名:sentiment-analysis

  • text-generation

  • token-classification (别名:ner

  • translation

  • translation_xx_to_yy

  • zero-shot-classification

Hugging Face 模型会完全忽略 sample_input_data 实参。登记未在上面列表中列出的 Hugging Face 模型时指定 signatures 实参,以便注册表知道目标方法的签名。

若要查看推断的签名,请使用 show_functions 方法。例如,下面是 lmv.show_functions() 的结果,其中 lmv 是上面登记的模型。

{'name': '__CALL__',
  'target_method': '__call__',
  'signature': ModelSignature(
                      inputs=[
                          FeatureSpec(dtype=DataType.STRING, name='inputs')
                      ],
                      outputs=[
                          FeatureSpec(dtype=DataType.STRING, name='outputs')
                      ]
                  )}]
Copy

有了这些信息,您可以按如下方式调用模型。

import pandas as pd
remote_prediction = lmv.run(pd.DataFrame(["Hello, how are you?"], columns=["inputs"]))
Copy

使用说明

  • 许多 Hugging Face 模型都很庞大,不适合标准仓库。请使用 Snowpark 优化型仓库,或者选择较小版本的模型。例如,不使用 Llama-2-70b-chat-hf 模型,而是尝试 Llama-2-7b-chat-hf

  • Snowflake 仓库没有 GPUs。仅使用 CPU 优化型 Hugging Face 模型。

  • 有些 Hugging Face 转换器会为每个输入行返回一个字典数组。注册表会将此类输出转换为包含数组的 JSON 表示的字符串。例如,多重输出问题回答输出如下所示:

    [{"score": 0.61094731092453, "start": 139, "end": 178, "answer": "learn more about the world of athletics"},
    {"score": 0.17750297486782074, "start": 139, "end": 180, "answer": "learn more about the world of athletics.\""}]
    
    Copy

在登记 Hugging Face 模型时,您必须指定 sample_input_datasignatures 参数,以确保注册表了解目标方法的签名。

示例

# Prepare model
import transformers
import pandas as pd

finbert_model = transformers.pipeline(
    task="text-classification",
    model="ProsusAI/finbert",
    top_k=2,
)

# Log the model
mv = registry.log_model(
    finbert_model,
    model_name="finbert",
    version_name="v1",
)

# Use the model
mv.run(pd.DataFrame(
        [
            ["I have a problem with my Snowflake that needs to be resolved asap!!", ""],
            ["I would like to have udon for today's dinner.", ""],
        ]
    )
)
Copy

结果:

0  [{"label": "negative", "score": 0.8106237053871155}, {"label": "neutral", "score": 0.16587384045124054}]
1  [{"label": "neutral", "score": 0.9263970851898193}, {"label": "positive", "score": 0.05286872014403343}]
Copy
语言: 中文