Speichern von kundenspezifischen Modellen in der Snowflake Model Registry¶
Die Snowflake Model Registry ermöglicht es Ihnen, Modelle zu registrieren (zu protokollieren) und sie für Inferenz in Snowflake zu verwenden. Die Registry unterstützt mehrere Typen von Modellen:
scikit-learn
XGBoost
LightGBM
CatBoost
PyTorch
TensorFlow
MLFlow PyFunc
Sentence Transformer
Hugging Face-Pipeline
Die Modell-Registry-API ermöglicht auch die Protokollierung weiterer Typen von Modellen, einschließlich solcher, die mit externen Tools trainiert wurden oder aus Open-Source-Repositorys stammen, solange sie serialisierbar sind und von der Klasse snowflake.ml.model.custom_model.CustomModel
abgeleitet wurden.
Bemerkung
Diese Anleitung enthält ein Beispiel für die Protokollierung eines kundenspezifischen Modells.
Informationen zum Import von Modellen aus AWS SageMaker oder aus Azure ML finden Sie in diesem Blogbeitrag und in den entsprechenden Quickstarts.
Unter diesem Thema wird erklärt, wie Sie Modelle erstellen, diese in der Snowflake Model Registry protokollieren und dann bereitstellen. Ein gängiger Anwendungsfall für dieses Feature ist das Definieren von Pipelines mit mehreren Klassen, z. B. einige Transformer oder Imputer gefolgt von einem Prädiktor oder Klassifikator. In solchen Fällen ist die kundenspezifische Modellklasse selbst relativ einfach: Sie ruft diese Klassen nacheinander auf und übergibt das Ergebnis einer Klasse als Eingabe an die nächste.
Definieren des Modellkontexts¶
Modelle benötigen oft zusätzlich zum Code eine oder mehrere statische Dateien, wie z. B. Konfigurationsdateien oder Modellgewichtungen. Kundenspezifische Modelle müssen Informationen zu allen diesen Artefakte liefern, damit die Registry weiß, dass sie mit dem Modell gepackt werden sollen. Artefakte können mit der Klasse ModelContext
wie folgt deklariert werden.
from snowflake.ml.model import custom_model
mc = custom_model.ModelContext(
artifacts={
'config': 'local_model_dir/config.json'
},
)
Die Pfade zu Artefaktdateien im Modellkontext sind relativ zum aktuellen Verzeichnis der Umgebung, aus der das Modell protokolliert wird. Die Snowflake Model Registry verwendet diese Informationen, um sicherzustellen, dass alle erforderlichen Codes und Daten in dem Warehouse bereitgestellt werden, in dem Ihr Modell ausgeführt werden soll. Zur Laufzeit kann das Modell diese Artefakte finden, indem es self.context.path('config')
aufruft (der Wert 'config'
ist derselbe wie der Schlüssel in dem an ModelContext
übergebenen Dictionary).
Neben statischen Dateien kann ein Modell auch andere Modelle oder Pipelines eines unterstützten Typs zusammenstellen (z. B. eine snowflake.ml.modeling.pipeline
oder ein scikit-learn-Modell). Die Registry weiß bereits, wie diese Typen von Objekten protokolliert werden. Daher können Sie die Python-Objekte direkt im Modellkontext mit model_refs
übergeben, wie hier gezeigt. Sie brauchen diese Objekte nicht selbst zu packen. Dies kann für die Bootstrap-Aggregation (Bagging) oder für die Vor- oder Nachbearbeitung nützlich sein.
Bemerkung
model1
und model2
sind Objekte eines beliebigen Modelltyps, der von der Registry nativ unterstützt wird. feature_preproc
ist ein snowflake.ml.modeling.pipeline
-Objekt.
mc = custom_model.ModelContext(
artifacts={
'config': 'local_model_dir/config.json'
},
models={
'm1': model1,
'm2': model2,
'feature_preproc': preproc
}
)
Die Modell-Registry serialisiert diese Modellreferenzen beim Protokollieren des Modells und rehydriert sie zur Laufzeit. Ihr Modell kann Referenzen auf diese untergeordneten Modelle abrufen, z. B. mit self.context.model_ref('m1')
. Wenn das Modell eine Methode predict
zur Verfügung stellt, kann Ihr Code diese direkt aus der abgerufenen Modellreferenz aufrufen, zum Beispiel mit self.context.model_ref('m1').predict()
.
Zusammenfassend lässt sich sagen, dass der Kontext eines kundenspezifischen Modells die Python-Objekte deklariert, die zusammen mit den Artefakten des Modells serialisiert werden sollen. Dabei handelt es sich um lokale Dateien, die vom Modell verwendet werden und die zusammen mit dem Code in Snowflake gespeichert werden müssen. Ihre Modellklasse verwendet den Kontext, um den Code und die Artefakte zu lokalisieren. Dies funktioniert unabhängig davon, ob Ihr Modell lokal oder in Snowflake ausgeführt wird.
Schreiben der kundenspezifischen Modellklasse¶
Um der Modell-Registry mitzuteilen, wie Ihr kundenspezifisches Modell protokolliert und bereitgestellt werden soll, erben Sie von snowflake.ml.model.custom_model.CustomModel
.
Modelle können mehrere Inferenzmethoden anbieten (z. B. bieten scikit-learn-Modelle die Methoden predict
und predict_proba
an). Um Inferenzfunktionen in Ihrem kundenspezifischen Modell zu deklarieren, definieren Sie diese als öffentliche Methoden Ihrer Unterklasse und dekorieren sie mit @custom_model.inference_api
. Dieser Decorator zeigt an, dass eine Methode Teil der öffentlichen API des Modells ist, sodass sie von Python oder SQL über die Modell-Registry aufgerufen werden kann. Methoden, die mit inference_api
dekoriert sind, müssen ein pandas-DataFrame akzeptieren und zurückgeben. Eine beliebige Anzahl von Methoden kann mit inference_api
dekoriert werden.
Bemerkung
Die Anforderung an die öffentliche API, einen Pandas-DataFrame zu akzeptieren und zurückzugeben, ist die gleiche wie für vektorisierte UDFs. Wie bei vektorisierten UDFs können diese Inferenz-APIs auch von Python aus aufgerufen werden, wobei ein Snowpark-DataFrame übergeben wird.
Nachfolgend sehen Sie ein Skeleton einer kundenspezifischen Modellklasse mit einer öffentlichen API.
Beachten Sie die Verwendung von context.path
, um die Bias-Datei, und die Verwendung von self.context.model_ref
, um Verweise auf die untergeordneten Modellklassen zu erhalten, damit deren predict
-Methoden aufgerufen werden können.
from snowflake.ml.model import custom_model
import pandas as pd
class ExamplePipelineModel(custom_model.CustomModel):
@custom_model.inference_api
def predict(self, input: pd.DataFrame) -> pd.DataFrame:
...
return pd.DataFrame(...)
Wenn Sie alle Teile zusammenfügen, erhalten Sie ein voll funktionsfähiges kundenspezifisches Modell.
class ExamplePipelineModel(custom_model.CustomModel):
def __init__(self, context: custom_model.ModelContext) -> None:
super().__init__(context)
v = open(context.path('config')).read()
self.bias = json.loads(v)['bias']
@custom_model.inference_api
def predict(self, input: pd.DataFrame) -> pd.DataFrame:
features = self.context.model_ref('feature_preproc').transform(input)
model_output = self.context.model_ref('m2').predict(
self.context.model_ref('m1').predict(features)
)
return pd.DataFrame({
'output': model_output + self.bias})
Verwenden des kundenspezifischen Modells¶
Sie können Ihr neues kundenspezifisches Modell (Pipeline) testen, indem Sie es wie folgt lokal ausführen:
my_model_pipeline = ExamplePipelineModel(mc)
output_df = my_model_pipeline.predict(input_df)
Oder Sie protokollieren es in der Registry, und stellen Sie es in Snowflake bereit. Wie im nächsten Codebeispiel gezeigt, geben Sie conda_dependencies
(oder pip_requirements
) an, um die Bibliotheken anzugeben, die die Modellklasse benötigt.
Stellen Sie sample_input_data
(ein pandas-DataFrame) zur Verfügung, um die Signatur der Eingabe für das Modell abzuleiten. Alternativ können Sie auch eine Modellsignatur bereitstellen.
reg = Registry(session=sp_session, database_name="ML", schema_name="REGISTRY")
mv = reg.log_model(my_model_pipeline,
model_name="my_custom_model_pipeline",
version_name="v1",
conda_dependencies=["scikit-learn"],
comment="My Custom ML Model Pipeline",
sample_input_data=train_features)
output_df = mv.run(input_df)
Tabellenfunktion: Inferenz¶
Ab Snowpark-ML 1.5.4 können Sie Modelle mit Inferenzmethoden protokollieren, die mehrere Spalten zurückgeben. Dazu protokollieren Sie Ihr Modell mit der {"function_type": "TABLE_FUNCTION"}
-Option und verwenden das @inference_api
-Decorator-Element, wie oben beschrieben. Im folgenden Beispiel gibt die dekorierte Methode ein pandas-DataFrame zurück, das zwei Ausgabespalten enthält.
class ExampleTableFunctionModel(custom_model.CustomModel):
@custom_model.inference_api
def predict(self, input: pd.DataFrame) -> pd.DataFrame:
output_df = pandas.DataFrame([{"OUTPUT1": input["INPUT1"] + 1, input["INPUT2"] + 1}])
return output_df
my_model = ExampleTableFunctionModel()
reg = Registry(session=sp_session, database_name="ML", schema_name="REGISTRY")
mv = reg.log_model(my_model,
model_name="my_custom_table_function_model",
version_name="v1",
options={"function_type": "TABLE_FUNCTION"},
sample_input_data=train_features
)
output_df = mv.run(input_df)
Wenn das Modell mehrere Inferenzmethoden enthält, verwenden Sie die method_options
-Option, um das Modell zu protokollieren und anzugeben, welche FUNCTION
und welche TABLE_FUNCTION
sind:
reg = Registry(session=sp_session, database_name="ML", schema_name="REGISTRY")
mv = reg.log_model(my_model,
model_name="my_custom_table_function_model",
version_name="v1",
options={
"method_options": { ###
"METHOD1": {"function_type": "TABLE_FUNCTION"}, ###
"METHOD2": {"function_type": "FUNCTION"} ###
}
},
sample_input_data=train_features
)
Die protokollierte Modelltabellenfunktion kann auch über SQL wie folgt aufgerufen werden:
SELECT OUTPUT1, OUTPUT2
FROM input_table,
table(
MY_MODEL!PREDICT(input_table.INPUT1, input_table.INPUT2)
)
Weitere Informationen zu Inferenzmethoden für partitionierte Modelle, bei denen die Inferenzmethode eine Datenpartition als Eingabe verwendet und mehrere Zeilen und Spalten ausgibt, finden Sie unter Partitionierte benutzerdefinierte Modelle.