Spécification des signatures de modèles

Pour garantir une expérience cohérente quel que soit l’endroit où un modèle est exécuté, le registre de modèles de Snowflake doit connaître le schéma d’entrée et de sortie des méthodes d’inférence du modèle : c’est-à-dire le nom et le type de toutes les colonnes du DataFrame d’entrée ou de sortie. Cela permet de mapper ces colonnes entre les types de données Python et SQL si nécessaire. Ce schéma est appelé signature par analogie avec les arguments d’une fonction et leurs types.

Pour certains cadres ML, le registre des modèles peut déduire ces schémas, soit à partir des structures de données du modèle lui-même, soit à partir d’un échantillon de données d’entrée. Cependant, les modèles acceptent ou renvoient souvent des objets dépourvus de ces informations, tels que les tableaux NumPy. Dans ces cas, Snowpark ML déduit les noms des fonctions d’entrée comme input_feature_1, input_feature_2, et ainsi de suite. De même, les fonctionnalités de sortie sont nommées output_feature_1, output_feature_2, etc.

Pour utiliser des noms plus significatifs dans vos modèles personnalisés, vous pouvez procéder de l’une des manières suivantes :

  • Mettez à jour sample_input_data avec les noms des colonnes, généralement en le convertissant au format pandas ou Snowpark DataFrame.

  • Transmettez explicitement les signatures à log_model. Lorsqu’un modèle ne produit pas de noms dans ses sorties, les signatures explicites peuvent être la seule option.

Déduire une signature

Tout comme le registre des modèles, vous pouvez générer des signatures automatiquement. Utilisez snowflake.ml.model.model_signature.infer_signature pour déduire une signature basée sur les noms d’entrée, de sortie et de colonne de l’échantillon fourni, puis appliquez cette signature aux méthodes appropriées lors de l’enregistrement du modèle, comme dans l’exemple ci-dessous :

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,
    labels_df,
    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

Cet exemple applique la signature à une seule méthode, mais vous pouvez déduire une signature pour chaque méthode exposée par votre modèle. Vous pouvez utiliser le même objet de signature (sig dans l’exemple) pour toutes les méthodes qui ont la même signature.

Note

Pour Snowpark DataFrames, infer_signature doit exécuter la requête de DataFramepour obtenir les données à partir desquelles la signature est déduite. Cela peut entraîner des coûts importants en fonction de la taille de l’ensemble de données. La plupart des ensembles de données d’entraînement sont suffisamment importants pour que cela soit pris en considération.

Pour éviter des requêtes aussi larges, infer_signature ne prend en compte que les cent premières lignes des données en ajoutant une LIMIT de 100 à la requête. Toutefois, si ces lignes ne sont pas représentatives des données, la signature déduite risque de ne pas être exacte. Cela se produit généralement lorsque l’ensemble de données contient de nombreuses valeurs NULL et qu’une colonne de l’ensemble de données ne contient que des valeurs NULL dans les cent premières lignes. Dans ce cas, la signature déduite omet à tort cette colonne. Pour éviter ce problème, indiquez la signature de manière explicite, comme indiqué dans la section suivante.

Construction d’une signature

Vous pouvez également construire manuellement une signature à l’aide de snowflake.ml.model.model_signature.ModelSignature. Les types scalaires et tensoriels (y compris les tenseurs en escalier) sont pris en charge.

Exemple :

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

Transmettez ensuite l’objet de signature, sig, à log_model avec l’argument signatures comme dans l’exemple ci-dessus pour les méthodes auxquelles il s’applique.

Mappages de types de données

Cette section décrit l’équivalence des types dans le registre de modèles de Snowflake pour les systèmes de types pris en charge.

Types de données de colonnes

Le tableau suivant montre l’équivalence entre le type de signature de modèle (SQL), le type pandas DataFrames (NumPy) et le type Snowpark Python.

Type de signature du modèle (SQL)

Type pandas DataFrame (NumPy)

Type 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

La représentation des fonctions tensorielles dont la forme est spécifiée utilise np.object_.

Valeurs manquantes

Si sample_input_data est utilisé pour déduire la signature du modèle, il ne doit généralement pas contenir de valeurs NULL. Le registre des modèles tente de déduire les signatures à partir des données fournies, mais il n’y parvient pas toujours complètement. Une bonne pratique consiste à empêcher les valeurs NULLs d’être incluses dans les données d’échantillon le plus tôt possible, par exemple au moment de l’entrée des données.

Conversion depuis NumPy

Si le type de données NumPy peut être converti en toute sécurité en un type NumPy indiqué dans Types de données de colonnes, il est considéré comme le type de données correspondant.

Conversion depuis PyTorch

Type PyTorch

Type de signature du modèle (SQL)

torch.uint8

UINT8

torch.int8

INT8

torch.int16

INT16

torch.int32

INT32

torch.int64

INT64

torch.float32

FLOAT

torch.float64

DOUBLE

torch.bool

BOOL

Conversion depuis Snowpark

Outre les mappages indiqués dans Types de données de colonnes, les conversions suivantes s’appliquent :

  • DecimalType avec une échelle de 0 correspond à INT64.

  • DecimalType avec une échelle supérieure à 0 correspond à DOUBLE.