指定模型签名

为了确保无论模型在何处运行都能获得一致的体验,Snowflake Model Registry 需要知道模型推理方法的输入和输出架构:即输入或输出 DataFrame 中所有列的名称和类型。这允许这些列在必要时在 Python 和 SQL 数据类型之间映射。这种架构被称为 签名,类比于函数的实参及其类型。签名还可以包括控制推理行为的可选 参数,例如温度设置。

对于某些 ML 框架,模型注册表可以从模型本身的数据结构或样本输入数据中推断这些架构。但是,模型通常接受或返回缺少此信息的对象,例如 NumPy 数组。在这些情况下,Snowpark ML 会推断输入特征名称为 input_feature_1input_feature_2 等。类似地,输出特征命名为 output_feature_1output_feature_2 等。

要在自定义模型中使用更有意义的名称,可以使用以下方法之一:

  • 使用列名更新 sample_input_data,通常是将数据集转换为 Pandas 或 Snowpark DataFrame

  • log_model 显式传递签名。当模型的输出中不产生名称时,显式签名可能是唯一的选择。

推断签名

与模型注册表本身一样,您可以自动生成签名。使用 snowflake.ml.model.model_signature.infer_signature 可以根据提供的示例输入、输出和列名称推断签名,然后在记录模型时将该签名应用到相应的方法中,如下面的示例所示:

import pandas as pd
from sklearn import svm, datasets

from snowflake.ml.model import model_signature

digits = datasets.load_digits()
target_digit = 6

def one_vs_all(dataset, digit):
    return [x == digit for x in dataset]

train_features = digits.data[:10]
train_labels = one_vs_all(digits.target[:10], target_digit)
clf = svm.SVC(gamma=0.001, C=10.0, probability=True)
clf.fit(train_features, train_labels)

sig = model_signature.infer_signature(
    train_features,
    train_labels,
    input_feature_names=['column1', 'column2', ...],
    output_feature_names=['is_target_digit'])

# Supply a signature for every function the model exposes, in this case only `predict`.
mv = reg.log_model(
    clf,
    model_name='my_model',
    version_name='v1',
    signatures={"predict": sig}
)
Copy

此示例仅将签名应用于一个方法,但您可以为模型公开的每种方法推断签名。您可以对具有相同签名的所有方法使用相同的签名对象(示例中的 sig)。

备注

对于 Snowpark DataFrames,infer_signature 必须运行 DataFrame 的查询来获取推理签名的数据。这可能会产生巨额成本,具体取决于数据集的大小。大多数训练数据集的规模都足够大,因此需要将这一点纳入考量。

为避免如此大的查询,infer_signature 通过在查询中添加 LIMIT 100 来仅考虑数据的前一百行。但是,如果这些行不能代表数据,则推理的签名可能不准确。当数据集包含许多 NULL 值且数据集中的一列只有前一百行中的 NULL 值时,通常会发生这种情况。在这种情况下,推理的签名错误地省略了该列。显式提供签名,如下一节所示,以避免出现此问题。

构造签名

您还可以使用 snowflake.ml.model.model_signature.ModelSignature 手动构造签名。支持标量类型和张量类型(包括不规则张量)。

示例:

from snowflake.ml.model.model_signature import ModelSignature, FeatureSpec, DataType

sig = ModelSignature(
    inputs=[
        FeatureSpec(dtype=DataType.DOUBLE, name=f_0),
        FeatureSpec(dtype=DataType.INT64, name=sparse_0_fixed_len, shape=(5, 5)),
        FeatureSpec(dtype=DataType.INT64, name=sparse_1_variable_len, shape=(-1,)),
    ],
    outputs=[
        FeatureSpec(dtype=DataType.FLOAT, name=output),
    ]
)
Copy

然后,将签名对象 sig 作为 signatures 实参传递给 ``log_model``(如上面的示例所示),以用于相应的方法。

使用 ParamSpec 指定参数

除了输入和输出特征外,模型签名还可以包含 参数。参数定义了可选的配置值,您可以在发出推理请求时将其传递给模型推理方法。与指定要处理的数据的输入特征不同,参数控制推理行为,例如要返回的结果数或温度设置。

使用来自 snowflake.ml.model.model_signature.ModelSignatureParamSpec 来定义参数。

每个 ParamSpec 都需要名称、数据类型和默认值。如果在推理时未显式提供参数,则使用默认值。

构造带有参数的签名

以下示例创建了一个包含输入/输出特征和参数的模型签名:

from snowflake.ml.model.model_signature import ModelSignature, FeatureSpec, ParamSpec, DataType

sig = ModelSignature(
    inputs=[
        FeatureSpec(dtype=DataType.STRING, name="input_text"),
    ],
    outputs=[
        FeatureSpec(dtype=DataType.STRING, name="output_text"),
    ],
    params=[
        ParamSpec(name="temperature", dtype=DataType.DOUBLE, default_value=0.7),
        ParamSpec(name="max_tokens", dtype=DataType.INT32, default_value=256),
    ]
)

mv = reg.log_model(
    my_model,
    model_name='my_model',
    version_name='v1',
    signatures={"predict": sig}
)
Copy

在使用 infer_signature 推断签名时,您也可以包含参数:

from snowflake.ml.model.model_signature import ParamSpec, DataType
from snowflake.ml.model import model_signature

params = [
    ParamSpec(name="top_k", dtype=DataType.INT32, default_value=10),
    ParamSpec(name="threshold", dtype=DataType.DOUBLE, default_value=0.5),
]

sig = model_signature.infer_signature(
    input_data,
    output_data,
    params=params
)
Copy

备注

参数名称在签名中必须是唯一的,且不能与输入特征同名。如果参数名称与输入特征名称冲突,则会引发 ValueError

有关 ParamSpec 实参的完整列表,请参阅 API 参考

有关在推理时传递参数值的详细信息,请参阅 在推理期间传递参数 以及 在 SQL 中传递参数

数据类型映射

本节描述在 Snowflake Model Registry 中,对于受支持的类型系统,类型的等价性。

列数据类型

下表显示了模型签名类型、Pandas DataFrames (NumPy) 类型和 Snowpark Python 类型的等价性。

模型签名类型

Pandas DataFrame (NumPy) 类型

Snowpark Python 类型

INT8

np.int8

ByteType

INT16

np.int16

ShortType

INT32

np.int32

IntegerType

INT64

np.int64

LongType

FLOAT

np.float32

FloatType

DOUBLE

np.float64

DoubleType

UINT8

np.uint8

ByteType

UINT16

np.uint16

ShortType

UINT32

np.uint32

IntegerType

UINT64

np.uint64

LongType

BOOL

np.bool_

BooleanType

STRING

np.str_

StringType

BYTES

np.bytes_

BinaryType

TIMESTAMP_NTZ

np.datetime64

TimestampType

对于形状已指定的张量特征,使用 np.object_ 来表示。

缺少值

如果 sample_input_data 用于推理模型签名,它一般不应包含任何 NULL 值。模型注册表试图从所提供的数据中推理签名,但不一定能够如此完全地推理签名。最佳实践是尽早避免将 NULLs 包含在样本数据中,例如在数据输入时。

从 NumPy 转换

如果 NumPy 数据类型可以安全地转换为 列数据类型 中所示的 NumPy 类型,则将其推断为相应的数据类型。

从 PyTorch 转换

PyTorch 类型

模型签名类型

torch.uint8

UINT8

torch.int8

INT8

torch.int16

INT16

torch.int32

INT32

torch.int64

INT64

torch.float32

FLOAT

torch.float64

DOUBLE

torch.bool

BOOL

从 Snowpark 转换

除了 列数据类型 中显示的映射外,还适用以下转换:

  • 标度为 0 的 DecimalType 映射到 INT64。

  • 标度大于 0 的 DecimalType 映射到 DOUBLE。