Model Serving in Snowpark Container Services

Bemerkung

This feature is available in AWS, Azure and Google Cloud commercial regions. It isn’t available in government regions.

Bemerkung

Die Möglichkeit, Modelle in Snowpark Container Services (SPCS) auszuführen, die in diesem Thema beschrieben wird, ist in snowflake-ml-python Version 1.8.0 und später verfügbar.

Die Snowflake Model Registry ermöglicht es Ihnen, Modelle entweder in einem Warehouse (die Standardeinstellung) oder in einem Snowpark Container Services (SPCS) Computepool über Model Serving auszuführen. Die Ausführung von Modellen in einem Warehouse bringt einige Beschränkungen in Bezug auf die Größe und die Art der Modelle mit sich, die Sie verwenden können (insbesondere kleine bis mittelgroße nur-CPU-Modelle, deren Abhängigkeiten von Paketen erfüllt werden können, die im Snowflake conda-Kanal verfügbar sind).

Die Ausführung von Modellen auf Snowpark Container Services (SPCS) erleichtert diese Einschränkungen oder beseitigt sie ganz. Sie können alle Pakete verwenden, die Sie möchten, auch die aus dem Python Package Index (PyPI) oder aus anderen Quellen. Große Modelle können auf verteilten Clustern von GPUs ausgeführt werden. Und Sie müssen nichts über Container-Technologien wie Docker oder Kubernetes wissen. Snowflake Model Serving kümmert sich um alle Details.

Die wichtigsten Konzepte

Nachfolgend finden Sie einen vereinfachten Überblick über die Architektur des Snowflake Modells Serving Inference.

Modellinferenz auf Snowpark Container Services-Architektur

Die Hauptkomponenten der Architektur sind:

  • Inferenzserver: Der Server, der das Modell ausführt und Vorhersagen liefert. Der Inferenzserver kann mehrere Inferenzprozesse verwenden, um die Fähigkeiten des Knotens voll auszuschöpfen. Anfragen an das Modell werden über die Zulassungskontrolle abgewickelt, die die Warteschlange für eingehende Anfragen verwaltet, um zu verhindern, dass der Speicher überlastet wird, und die Clients abweist, wenn der Server überlastet ist. Heute bietet Snowflake einen einfachen und flexiblen Inferenzserver auf Python-Basis, der Inferenzen für alle Arten von Modellen durchführen kann. Snowflake plant, im Laufe der Zeit InferenzsServer anzubieten, die für bestimmte Modelle optimiert sind.

  • Modellspezifische Python-Umgebung: Um die Latenz beim Starten eines Modells zu verringern, zu der auch die Zeit gehört, die für das Herunterladen der Abhängigkeiten und das Laden des Modells benötigt wird, erstellt Snowflake einen Container, der die Abhängigkeiten des spezifischen Modells kapselt.

  • Dienstfunktionen: Um von einem im Warehouse ausgeführten Code aus mit dem Inferenzserver zu kommunizieren, erstellt Snowflake Model Serving-Funktionen, die dieselbe Signatur wie das Modell haben, aber stattdessen den Inferenzserver über das externe Funktionsprotokoll aufrufen.

  • Ingress-Endpunkt: Damit Anwendungen außerhalb von Snowflake das Modell aufrufen können, kann Snowflake Model Serving einen optionalen HTTP Endpunkt bereitstellen, der über das öffentliche Internet zugänglich ist.

Wie funktioniert das?

Das folgende Diagramm zeigt, wie das Snowflake Model Serving Modelle entweder in einem Warehouse oder auf SPCS bereitstellt und bedient.

Modell für den Einsatz auf Snowpark Container Services

Wie Sie sehen, ist der Pfad zur Bereitstellung von SPCS komplexer als der Pfad zur Bereitstellung des Warehouse, aber Snowflake Model Serving übernimmt die gesamte Arbeit für Sie, einschließlich der Erstellung des Container-Images, das das Modell und seine Abhängigkeiten enthält, und der Erstellung des Inferenzservers, der das Modell ausführt.

Voraussetzungen

Bevor Sie beginnen, vergewissern Sie sich, dass Sie Folgendes haben:

  • A Snowflake account in any commercial AWS, Azure or Google Cloud region. Government regions are not supported.

  • Version 1.6.4 oder höher des snowflake-ml-python Python-Pakets.

  • Ein Modell, das Sie auf Snowpark Container Services ausführen möchten.

  • Vertrautheit mit dem Snowflake Model Registry.

  • Vertrautheit mit dem Snowpark Container Services. Insbesondere sollten Sie Computepools, Image-Repositorys und die damit verbundenen Berechtigungen verstehen.

Einen Computepool erstellen

Snowpark Container Services (SPCS) führt Container-Images in Computepools aus. Wenn Sie noch keinen geeigneten Computepool haben, erstellen Sie einen solchen wie folgt:

CREATE COMPUTE POOL IF NOT EXISTS mypool
    MIN_NODES = 2
    MAX_NODES = 4
    INSTANCE_FAMILY = 'CPU_X64_M'
    AUTO_RESUME = TRUE;
Copy

Eine Auflistung der gültigen Instanzfamilien finden Sie in der Familiennamen-Tabelle.

Stellen Sie sicher, dass die Rolle, die das Modell ausführt, Eigentümer des Computepools ist oder die Berechtigung USAGE oder OPERATE für den Pool besitzt.

Erforderliche Berechtigungen

Model Serving läuft auf Snowpark Container Services. Um Model Serving zu verwenden, benötigt ein Benutzer die folgenden Berechtigungen:

  • USAGE oder OWNERSHIP auf einem Computepool, auf dem der Dienst laufen wird.

  • Wenn ein Ingress-Endpunkt auf dem Model Serving gewünscht wird, muss der Benutzer über die Berechtigung BIND SERVICE ENDPOINT auf dem Konto verfügen.

  • Modelleigentümer oder Benutzer mit der Berechtigung :doc:` für das Modell kann das Modell in Serving bereitstellen. Um einer anderen Rolle den Zugriff auf Inferenz zu ermöglichen, können Service-Eigentümer die Servicerolle INFERENCE_SERVICE_FUNCTION_USAGE gewähren, um Servicefunktionen zu teilen und ALL_ENDPOINTS_USAGE zu gewähren, um Eingangsendpunkte gemeinsam zu nutzen.

Einschränkungen

Die folgenden Einschränkungen gelten für Modelle, die in Snowpark Container Services eingesetzt werden.

  • Nur der Eigentümer eines Modells oder von Rollen mit der READ-Berechtigung für das Modell kann es in Snowpark Container Services einsetzen.

  • Die Größe des Compute-Clusters wird nicht automatisch skaliert. Sie können die Anzahl der Instanzen zur Laufzeit mit ALTER SERVICE myservice MIN_INSTANCES = n manuell ändern. In einigen Fällen führt dies dazu, dass bestehende Knoten ausfallen.

  • Die Skalierung von Services und Computepools verläuft langsamer als erwartet.

  • Die Bilderstellung schlägt fehl, wenn sie mehr als eine Stunde dauert.

  • Tabellenfunktionen werden nicht unterstützt. Modelle ohne Non-Table-Funktionen können derzeit nicht in Snowpark Container Services eingesetzt werden.

Ein Modell für SPCS bereitstellen

Entweder protokolliert eine neue Version des Modells (über reg.log_model) oder erhält einen Verweis auf eine bestehende Version des Modells (reg.get_model(...).version(...)). In beiden Fällen erhalten Sie einen Verweis auf ein ModelVersion-Objekt.

Modell-Abhängigkeiten und Eignung

Die Abhängigkeiten eines Modells bestimmen, ob es in einem Warehouse, in einem SPCS-Dienst oder in beiden laufen kann. Sie können bei Bedarf absichtlich Abhängigkeiten angeben, um ein Modell für die Ausführung in einer dieser Umgebungen ungeeignet zu machen.

Der Snowflake conda-Kanal ist nur in Warehouses verfügbar und ist die einzige Quelle für Abhängigkeiten von Warehouses. Standardmäßig beziehen die conda-Abhängigkeiten für SPCS-Modelle ihre Abhängigkeiten aus conda-forge.

Wenn Sie eine Modellversion protokollieren, werden die Abhängigkeiten des Modells mit dem Snowflake conda-Kanal abgeglichen. Wenn alle Abhängigkeiten des Modells dort verfügbar sind, kann das Modell in einem Warehouse ausgeführt werden. Er kann auch in einem SPCS-Dienst laufen, wenn alle seine Abhängigkeiten in der conda-forge verfügbar sind. Dies wird jedoch erst geprüft, wenn Sie einen Dienst erstellen.

Modelle, die mit PyPI Abhängigkeiten protokolliert wurden, müssen auf SPCS ausgeführt werden. Die Angabe von mindestens einer PyPI-Abhängigkeit ist eine Möglichkeit, ein Modell von der Ausführung in einem Warehouse auszuschließen. Wenn Ihr Modell nur Abhängigkeiten von conda hat, geben Sie mindestens eine mit einem expliziten Kanal an (auch conda-forge), wie im folgenden Beispiel gezeigt.

# reg is a snowflake.ml.registry.Registry object
reg.log_model(
    model_name="my_model",
    version_name="v1",
    model=model,
    conda_dependencies=["conda-forge::scikit-learn"])
Copy

Für SPCS-bereitgestellte Modelle werden zuerst die conda-Abhängigkeiten, falls vorhanden, installiert, dann werden alle PyPI-Abhängigkeiten in der conda-Umgebung mit pip installiert.

Dienst erstellen

Um einen SPCS-Dienst zu erstellen und das Modell darin einzusetzen, rufen Sie die create_service-Methode der Modellversion auf, wie im folgenden Beispiel gezeigt.

# mv is a snowflake.ml.model.ModelVersion object
mv.create_service(service_name="myservice",
                  service_compute_pool="my_compute_pool",
                  ingress_enabled=True,
                  gpu_requests=None)
Copy

Nachfolgend sind die erforderlichen Arguments an create_service zu sehen:

  • service_name: Der Name des zu erstellenden Services. Dieser Name muss innerhalb des Kontos eindeutig sein.

  • service_compute_pool: Der Name des Computepools, der für die Ausführung des Modells verwendet werden soll. Der Computepool muss bereits existieren.

  • ingress_enabled: Wenn „True“, wird der Dienst über einen HTTP-Endpunkt zugänglich gemacht. Um den Endpunkt zu erstellen, muss der Benutzer über die Berechtigung BIND SERVICE ENDPOINT verfügen.

  • gpu_requests: Eine Zeichenfolge, die die Anzahl der GPUs angibt. Bei einem Modell, das entweder auf CPU oder GPU ausgeführt werden kann, bestimmt dieses Argument, ob das Modell auf CPU oder auf GPUs ausgeführt wird. Wenn es sich bei dem Modell um einen bekannten Typ handelt, der nur auf CPU ausgeführt werden kann (z. B. scikit-learn-Modelle), schlägt die Image-Erstellung fehl, wenn GPUs angefragt wird.

Wenn Sie ein neues Modell bereitstellen, kann es bis zu 5 Minuten dauern, bis der Service für CPU-gestützte Modelle erstellt worden ist und 10 Minuten für GPU-gestützte Modelle. Wenn der Computepool im Leerlauf ist oder eine Größenänderung erforderlich ist, kann die Service-Erstellen länger dauern.

This example shows only the required and most commonly used arguments. See the ModelVersion API reference for a complete list of arguments.

Standard Konfiguration des Dienstes

Standardmäßig verwendet Inferenzserver benutzerfreundliche Standardeinstellungen, die für die meisten Anwendungsfälle geeignet sind. Diese Einstellungen sind:

  • Anzahl der Worker-Threads: Bei CPU-gestützten Modell verwendet der Server die doppelte Anzahl von CPUs plus einen Worker-Prozess. GPU-gestützte Modelle verwenden einen Worker-Prozess. Sie können dies mit dem num_workers-Argument im Aufruf create_service überschreiben.

  • Threadsicherheit: Einige Modelle sind nicht Thread-sicher. Daher lädt der Dienst für jeden Worker-Prozess eine eigene Kopie des Modells. Dies kann bei großen Modellen zu einer Erschöpfung der Ressourcen führen.

  • Knotennutzung: Standardmäßig fordert eine Inferenzserverinstanz den gesamten Knoten an, indem sie die gesamte CPU und den gesamten Speicher des Knotens anfordert, auf dem sie läuft. Um die Ressourcenzuweisung pro Instanz anzupassen, verwenden Sie Argumente wie cpu_requests, memory_requests, und gpu_requests.

  • Endpunkt: Der Endpunkt hat den Namen inference und verwendet Port 5000. Diese können nicht angepasst werden.

  • Auto Suspend: Inferenzservices werden standardmäßig nach 30 Minuten Inaktivität automatisch angehalten. Ein unterbrochener Service wird automatisch fortgesetzt, wenn er eine Anfrage erhält.

Verhaltensweise bei der Erstellung von Container-Images

Standardmäßig erstellt Snowflake Model Serving das Container-Image unter Verwendung desselben Computepools, der für die Ausführung des Modells verwendet wird. Dieser Inferenz-Computepool ist für diese Aufgabe wahrscheinlich überfordert (zum Beispiel werden GPUs nicht für die Erstellung von Container-Images verwendet). In den meisten Fällen wird dies keine nennenswerten Auswirkungen auf die Kosten haben, aber wenn es ein Problem darstellt, können Sie einen weniger leistungsfähigen Pool für die Erstellung von Images wählen, indem Sie das Argument image_build_compute_pool angeben.

create_service ist eine idempotente Funktion. Ein mehrfacher Aufruf löst nicht jedes Mal die Image-Erstellung aus. Container-Images können jedoch auf der Grundlage von Updates im Inferenzdienst neu erstellt werden, einschließlich Korrekturen für Sicherheitslücken in abhängigen Paketen. Wenn dies geschieht, löst create_service automatisch eine Neuerstellung des Images aus.

Bemerkung

Modelle, die mit Snowpark ML-Modellierungsklassen entwickelt wurden, können nicht in Umgebungen eingesetzt werden, die eine GPU haben. Als Problemumgehung können Sie das native Modell extrahieren und es bereitstellen. Beispiel:

# Train a model using Snowpark ML
from snowflake.ml.modeling.xgboost import XGBRegressor
regressor = XGBRegressor(...)
regressor.fit(training_df)

# Extract the native model
xgb_model = regressor.to_xgboost()
# Test the model with pandas dataframe
pandas_test_df = test_df.select(['FEATURE1', 'FEATURE2', ...]).to_pandas()
xgb_model.predict(pandas_test_df)

# Log the model in Snowflake Model Registry
mv = reg.log_model(xgb_model,
                   model_name="my_native_xgb_model",
                   sample_input_data=pandas_test_df,
                   comment = 'A native XGB model trained from Snowflake Modeling API',
                   )
# Now we should be able to deploy to a GPU compute pool on SPCS
mv.create_service(
    service_name="my_service_gpu",
    service_compute_pool="my_gpu_pool",
    image_repo="my_repo",
    max_instances=1,
    gpu_requests="1",
)
Copy

Benutzeroberfläche

Sie können eingesetzte Modelle in der Modellregistrierung Snowsight UI verwalten. Weitere Informationen dazu finden Sie unter Dienste zur Modellinferenz.

Verwendung eines Modells, eingesetzt für SPCS

Sie können die Methoden eines Modells über SQL, Python oder einen HTTP-Endpunkt aufrufen.

SQL

Snowflake Model Serving erstellt Funktionen für Dienste, wenn ein Modell auf SPCS bereitgestellt wird. Diese Funktionen dienen als Brücke von SQL zu dem Modell, das im SPCS-Computepool läuft. Für jede Methode des Modells wird eine Dienstfunktion erstellt, die wie service_name!method_name benannt ist. Wenn das Modell beispielsweise zwei Methoden mit den Namen PREDICT und EXPLAIN hat und für einen Dienst mit dem Namen MY_SERVICE bereitgestellt wird, lauten die resultierenden Funktionen des Dienste MY_SERVICE!PREDICT und MY_SERVICE!EXPLAIN.

Bemerkung

Die Dienstefunktionen sind im Service enthalten. Aus diesem Grund haben sie nur einen einzigen Punkt für die Zugriffssteuerung, den Service. Sie können keine unterschiedlichen Zugriffssteuerungsrechte für verschiedene Funktionen in einem einzigen Dienst haben.

Der Aufruf der Dienstfunktionen eines Modells in SQL erfolgt über Code wie den folgenden:

-- See signature of the inference function in SQL.
SHOW FUNCTIONS IN SERVICE MY_SERVICE;

-- Call the inference function in SQL following the same signature (from `arguments` column of the above query)
SELECT MY_SERVICE!PREDICT(feature1, feature2, ...) FROM input_data_table;
Copy

Python

Rufen Sie die Methoden eines Service mit der Methode run eines Objekts der Modellversion auf, einschließlich des Arguments service_name zur Angabe des Serfvices, in dem die Methode ausgeführt wird. Beispiel:

# Get signature of the inference function in Python
# mv: snowflake.ml.model.ModelVersion
mv.show_functions()
# Call the function in Python
service_prediction = mv.run(
    test_df,
    function_name="predict",
    service_name="my_service")
Copy

Wenn Sie das Argument service_name nicht angeben, läuft das Modell in einem Warehouse.

HTTP endpoints

Every service comes with its internal DNS name. Deploying a service with ingress_enabled also creates a public HTTP endpoint available outside of Snowflake. Either endpoint can be used to call a service.

Endpoint names

You can find the public HTTP endpoint of a service with ingress enabled using the SHOW ENDPOINTS command or the list_services() method of a model version object.

# mv: snowflake.ml.model.ModelVersion
mv.list_services()
Copy

The output of both contains an ingress_url column, which has an entry of the format unique-service-id-account-id.snowflakecomputing.app. This is the publicly available HTTP endpoint for your service. The DNS name limitations apply. In a URL, underscores (_) in the method name are replaced by dashes (-) in the URL. For example, the service name predict_probability is changed to predict-probability in the URL.

To get the internal DNS name on Snowflake, use the DESCRIBE SERVICE command. The dns_name column of output from this command contains a service’s internal DNS name. To find your service’s port, use the SHOW ENDPOINTS IN SERVICE command. The port or port_range column contains the port used by a service. You can make internal calls to your service through the URL https://dns_name:port/<method_name>.

Request body

All inference requests must use the POST HTTP method with a Content-Type: application/json header, and the message body follows the data format described in Eingabe- und Ausgabedatenformate von Remotediensten.

The first column of your input is an INTEGER number representing the row number in the batch, and the remaining columns must match your service’s signature. The following request body is an example for a model with the signature predict(INTEGER, VARCHAR, TIMESTAMP):

{
    "data": [
                [0, 10, "Alex", "2014-01-01 16:00:00"],
                [1, 20, "Steve", "2015-01-01 16:00:00"],
                [2, 30, "Alice", "2016-01-01 16:00:00"],
                [3, 40, "Adrian", "2017-01-01 16:00:00"]
            ]
}
Copy

Calling the service

Users can call a service using the public endpoint programmatically in the following ways:

  • With a Programmatic Access Token (PAT), authentication based on a token you generate on Snowflake. For information on setting up a PAT for use with Snowflake services, see Verwenden von programmatische Zugriffstoken für die Authentifizierung. To use a PAT when calling a service, include the token in your Authorization request header:

    Authorization: Snowflake Token="<your_token>"
    
    Copy

    For example, with a PAT stored in the environment variable SNOWFLAKE_SERVICE_PAT and the predict(INTEGER, VARCHAR, TIMESTAMP) function signature used in previous examples, you could make a request to the endpoint random-id.myaccount.snowflakecomputing.app/predict with the following curl command:

    curl \
     -X POST \
     -H "Content-Type: application/json" \
     -H "Authorization: Snowflake Token=\"$SNOWFLAKE_SERVICE_PAT\"" \
     -d '{
           "data": [
                       [0, 10, "Alex", "2014-01-01 16:00:00"],
                       [1, 20, "Steve", "2015-01-01 16:00:00"],
                       [2, 30, "Alice", "2016-01-01 16:00:00"],
                       [3, 40, "Adrian", "2017-01-01 16:00:00"]
                   ]
       }' \
     random-id.myaccount.snowflakecomputing.app/predict/predict
    
    Copy
  • With a JSON Web Token (JWT), generated after key-pair authentication. Your application authenticates requests to the public endpoint by generating a JWT from your key-pair, exchanging it with Snowflake for an OAuth token, and then that OAuth token is used to authenticate with the public endpoint directly.

    For an example of using JWT to authenticate with a public endpoint, see Snowpark Container Services Tutorial – Access the public endpoint programmatically.

    For more information on key-pair authentication in Snowflake, see Schlüsselpaar-Authentifizierung und Schlüsselpaar-Rotation.

Bemerkung

There are no side effects when calling the service over HTTP. All authorization failures such as an incorrect token or lack of network route to the service result in a 404 error. The service may return 400 or 429 errors when the request body is invalid or the service is busy.

Unter Einsatz eines Hugging Face-Satzumwandlers für GPU-gestützte Inferenz finden Sie ein Beispiel für die Verwendung eines Modelldienst-HTTP-Endpunkts.

Latency considerations

You can use the following options to run inference while hosting a model in Snowpark Container Services. They have different trade-offs with regard to latency expectation and use cases.

HTTP endpoints

HTTP endpoints are best for online or real-time inference and offer the lowest latency of your options. Traffic doesn’t go through a warehouse or global Snowflake services, and input data is directly sent to the server after authentication.

SQL

SQL commands are best for batch inference. Input data is sent to the server from a warehouse, which compiles and executes the query. Response data is then written to a cache in the warehouse before being returned to the server. Warehouse transfers, compilation, and execution incur latency. Execution latency is always lower when a cached result is used.

Snowpark Python APIs

Python APIs are backed by SQL commands executed on Snowflake and best-suited for the same purposes as direct SQL. However, latency is affected by the type of DataFrame used as input. Snowpark DataFrames use data already available in Snowflake and can operate entirely in the same manner as direct SQL. Pandas DataFrames upload their in-memory data to a temporary Snowflake table, which incurs transfer latency.

For the lowest latency when using Python APIs, prepare your pandas DataFrames as Snowpark DataFrames before hosting your model.

Bemerkung

Performance evaluations you conduct locally using a pandas DataFrame won’t match performance with the same pandas DataFrame that is running on Snowpark Container Services, due to the latency of temporary table creation. For an accurate performance evaluation of your model, use a Snowpark DataFrame as input.

Verwalten von Diensten

Snowpark Container-Dienste bieten eine SQL-Weboberfläche für die Verwaltung von Diensten. Sie können die Befehle DESCRIBE SERVICE und ALTER SERVICE für SPCS-Dienste verwenden, die von Snowflake Model Serving erstellt wurden, genauso wie für die Verwaltung aller anderen SPCS-Dienste. Sie können beispielsweise Folgendes tun:

  • Ändern Sie MIN_INSTANCES und andere Eigenschaften eines Dienstes

  • Einen Dienst verwerfen (löschen)

  • Einen Dienst für ein anderes Konto freigeben

  • Änderung der Eigentümerschaft eines Services (der neue Eigentümer muss READ-Zugriff auf das Modell haben)

Bemerkung

Wenn der Eigentümer eines Dienstes aus irgendeinem Grund den Zugriff auf das zugrunde liegende Modell verliert, funktioniert der Dienst nach einem Neustart nicht mehr. Er läuft weiter, sobald er neu gestartet wird.

Um die Reproduzierbarkeit und Fehlersuche zu gewährleisten, können Sie die Spezifikation eines bestehenden Inferenzdienstes nicht ändern. Sie können jedoch die Spezifikation kopieren, sie anpassen und die angepasste Spezifikation verwenden, um Ihren eigenen Dienst zum Hosten des Modells zu erstellen. Diese Methode schützt jedoch nicht davor, dass das zugrunde liegende Modell gelöscht wird. Darüber hinaus verfolgt es nicht die Abstammung. Am besten ist es, wenn Sie Snowflake Model Serving erlauben, Dienste zu erstellen.

Aussetzen von Diensten

Die Services sind zunächst so konfiguriert, dass sie nach 30 Minuten Inaktivität ausgesetzt werden. Der Service wird nach Erhalt einer neuen Anfrage fortgesetzt, vorbehaltlich der Zeitpläne und Startverzögerungen. Die verzögerte Zeitplanung hängt von der Verfügbarkeit des Computepools ab, und die Startverzögerung hängt von der Größe des Modells ab.

Um einen Service manuell anzuhalten oder fortzusetzen, verwenden Sie den Befehl ALTER SERVICE.

ALTER SERVICE my_service [ SUSPEND | RESUME ];
Copy

Um das Verhalten bei automatischem Anhalten manuell festzulegen, verwenden Sie den Befehl ALTER SERVICE Befehl mit dem Parameter AUTO_SUSPEND_SECS.

ALTER SERVICE my_service SET AUTO_SUSPEND_SECS = <timeout_in_seconds>;
Copy

Um das automatische Anhalten zu deaktivieren, stellen Sie AUTO_SUSPEND_SECS auf 0. Um das automatische Anhalten wieder zu aktivieren, geben Sie ein Timeout von mindestens 300 Sekunden an.

Weitere Informationen dazu finden Sie unter ALTER SERVICE.

Löschen von Modellen

Sie können Modelle und Modellversionen wie gewohnt über die SQL-Weboberfläche oder die Python-API verwalten, mit der Einschränkung, dass ein Modell oder eine Modellversion, das/die von einem Dienst verwendet wird (unabhängig davon, ob es/sie läuft oder ausgesetzt ist), nicht gelöscht werden kann. Um ein Modell oder eine Version zu löschen, müssen Sie zuerst den Dienst löschen.

Beispiele

Diese Beispiele gehen davon aus, dass Sie bereits einen Computepool und ein Image-Repository erstellt und die erforderlichen Berechtigungen erteilt haben. Weitere Informationen dazu finden Sie unter Voraussetzungen.

Einsatz eines XGBoost-Modells für CPU-gestützte Inferenz

Der folgende Code veranschaulicht die Schlüsselschritte bei der Bereitstellung eines XGBoost-Modells für die Inferenz in SPCS und der anschließenden Verwendung des bereitgestellten Modells für die Inferenz. Ein Notizbuch für dieses Beispiel ist verfügbar unter.

from snowflake.ml.registry import registry
from snowflake.ml.utils.connection_params import SnowflakeLoginOptions
from snowflake.snowpark import Session

from xgboost import XGBRegressor

# your model training code here output of which is a trained xgb_model

# Open model registry
reg = registry.Registry(session=session, database_name='my_registry_db', schema_name='my_registry_schema')

# Log the model in Snowflake Model Registry
model_ref = reg.log_model(
    model_name="my_xgb_forecasting_model",
    version_name="v1",
    model=xgb_model,
    conda_dependencies=["scikit-learn","xgboost"],
    sample_input_data=pandas_test_df,
    comment="XGBoost model for forecasting customer demand"
)

# Deploy the model to SPCS
model_ref.create_service(
    service_name="forecast_model_service",
    service_compute_pool="my_cpu_pool",
    ingress_enabled=True)

# See all services running a model
model_ref.list_services()

# Run on SPCS
model_ref.run(pandas_test_df, function_name="predict", service_name="forecast_model_service")

# Delete the service
model_ref.delete_service("forecast_model_service")
Copy

Since this model has ingress enabled, you can call its public HTTP endpoint. The following example uses a PAT stored in the environment variable PAT_TOKEN to authenticate with a public Snowflake endpoint:

import os
import json
import numpy as np
from pprint import pprint
import requests

def get_headers(pat_token):
    headers = {'Authorization': f'Snowflake Token="{pat_token}"'}
    return headers

headers = get_headers(os.getenv("PAT_TOKEN"))

# Put the endpoint url with method name `predict`
# The endpoint url can be found with `show endpoints in service <service_name>`.
URL = 'https://<random_str>-<organization>-<account>.snowflakecomputing.app/predict'

# Prepare data to be sent
data = {"data": np.column_stack([range(pandas_test_df.shape[0]), pandas_test_df.values]).tolist()}

# Send over HTTP
def send_request(data: dict):
    output = requests.post(URL, json=data, headers=headers)
    assert (output.status_code == 200), f"Failed to get response from the service. Status code: {output.status_code}"
    return output.content

# Test
results = send_request(data=data)
print(json.loads(results))
Copy

Einsatz eines Hugging Face-Satzumwandlers für GPU-gestützte Inferenz

Der folgende Code trainiert und setzt einen Hugging Face Satzumwandler ein, einschließlich eines HTTP-Endpunkts.

Dieses Beispiel erfordert das Paket sentence-transformers, einen GPU Computepool und ein Image-Repository.

from snowflake.ml.registry import registry
from snowflake.ml.utils.connection_params import SnowflakeLoginOptions
from snowflake.snowpark import Session
from sentence_transformers import SentenceTransformer

session = Session.builder.configs(SnowflakeLoginOptions("connection_name")).create()
reg = registry.Registry(session=session, database_name='my_registry_db', schema_name='my_registry_schema')

# Take an example sentence transformer from HF
embed_model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')

# Have some sample input data
input_data = [
    "This is the first sentence.",
    "Here's another sentence for testing.",
    "The quick brown fox jumps over the lazy dog.",
    "I love coding and programming.",
    "Machine learning is an exciting field.",
    "Python is a popular programming language.",
    "I enjoy working with data.",
    "Deep learning models are powerful.",
    "Natural language processing is fascinating.",
    "I want to improve my NLP skills.",
]

# Log the model with pip dependencies
pip_model = reg.log_model(
    embed_model,
    model_name="sentence_transformer_minilm",
    version_name="pip",
    sample_input_data=input_data,  # Needed for determining signature of the model
    pip_requirements=["sentence-transformers", "torch", "transformers"], # If you want to run this model in the Warehouse, you can use conda_dependencies instead
)

# Force Snowflake to not try to check warehouse
conda_forge_model = reg.log_model(
    embed_model,
    model_name="sentence_transformer_minilm",
    version_name="conda_forge_force",
    sample_input_data=input_data,
    # setting any package from conda-forge is sufficient to know that it can't be run in warehouse
    conda_dependencies=["sentence-transformers", "conda-forge::pytorch", "transformers"]
)

# Deploy the model to SPCS
pip_model.create_service(
    service_name="my_minilm_service",
    service_compute_pool="my_gpu_pool",  # Using GPU_NV_S - smallest GPU node that can run the model
    ingress_enabled=True,
    gpu_requests="1", # Model fits in GPU memory; only needed for GPU pool
    max_instances=4, # 4 instances were able to run 10M inferences from an XS warehouse
)

# See all services running a model
pip_model.list_services()

# Run on SPCS
pip_model.run(input_data, function_name="encode", service_name="my_minilm_service")

# Delete the service
pip_model.delete_service("my_minilm_service")
Copy

In SQL können Sie die Dienstfunktion wie folgt aufrufen:

SELECT my_minilm_service!encode('This is a test sentence.');
Copy

Auf ähnliche Weise können Sie den HTTP-Endpunkt wie folgt aufrufen.

import json
from pprint import pprint
import requests

# Put the endpoint url with method name `encode`
URL='https://<random_str>-<account>.snowflakecomputing.app/encode'

# Prepare data to be sent
data = {
    'data': []
}
for idx, x in enumerate(input_data):
    data['data'].append([idx, x])

# Send over HTTP
def send_request(data: dict):
    output = requests.post(URL, json=data, headers=headers)
    assert (output.status_code == 200), f"Failed to get response from the service. Status code: {output.status_code}"
    return output.content

# Test
results = send_request(data=data)
pprint(json.loads(results))
Copy

Einsatz eines PyTorch-Modells für GPU-gestützte Inferenz

Unter finden Sie in diesem Quickstart ein Beispiel für das Training und den Einsatz eines PyTorch Deep Learning-Empfehlungsmodells (DLRM) auf SPCS für GPU-Inferenz.

Best Practices

Gemeinsame Nutzung des Image-Repositorys

Es ist üblich, dass mehrere Benutzer oder Rollen dasselbe Modell verwenden. Durch die Verwendung eines einzigen Image-Repositorys kann das Image einmal erstellt und von allen Benutzern wiederverwendet werden, was Zeit und Kosten spart. Alle Rollen, die das Repository verwenden, benötigen die Berechtigungen SERVICE READ, SERVICE WRITE, READ und WRITE für das Repository. Da das Image möglicherweise neu erstellt werden muss, um Abhängigkeiten zu aktualisieren, sollten Sie die Schreibrechte behalten und sie nicht widerrufen, nachdem das Image ursprünglich erstellt wurde.

Skalierung des Inferencedienstes

Die automatische Skalierung von Snowpark Container-Dienstets ist sehr konservativ und skaliert nicht schnell genug für die meisten ML-Workloads. Aus diesem Grund empfiehlt Snowflake, sowohl MIN_INSTANCES als auch MAX_INSTANCES auf denselben Wert einzustellen und diese Werte so zu wählen, dass Sie die Leistung erhalten, die Sie für Ihre typischen Workloads benötigen. Verwenden Sie SQL wie folgt:

ALTER SERVICE myservice
    SET MIN_INSTANCES = <new_num>
        MAX_INSTANCES = <new_num>;
Copy

Aus demselben Grund akzeptiert die Methode create_service bei der anfänglichen Erstellung des Dienstes mit Python API nur max_instances und verwendet denselben Wert für min_instances.

Auswahl des Knotentyps und der Anzahl der Instanzen

Verwenden Sie den kleinsten GPU-Knoten, bei dem das Modell in den Speicher passt. Skalieren Sie, indem Sie die Anzahl der Instanzen erhöhen, im Gegensatz zur Erhöhung von num_workers in einem größeren GPU-Knoten. Wenn das Modell beispielsweise in den Instanztyp GPU_NV_S (GPU_NV_SM auf Azure) passt, verwenden Sie gpu_requests=1 und skalieren Sie durch Erhöhen von max_instances, anstatt eine Kombination aus gpu_requests und num_workers auf einer größeren GPU-Instanz zu verwenden.

Wahl der Warehouse-Größe

Je größer das Warehouse ist, desto mehr parallele Anfragen werden an die Inferenzserver gesendet. Die Inferenz ist eine teure Operation, verwenden Sie daher nach Möglichkeit ein kleineres Warehouse. Die Verwendung einer Warehouse-Größe, die größer als mittel ist, beschleunigt die Leistung der Abfrage nicht und verursacht zusätzliche Kosten.

Problembehandlung

Überwachen der SPCS-Bereitstellungen

Sie können die Bereitstellung überwachen, indem Sie die Dienste, die gestartet werden, mit der folgenden SQL-Abfrage überprüfen.

SHOW SERVICES IN COMPUTE POOL my_compute_pool;
Copy

Zwei Jobs werden gestartet:

  • MODEL_BUILD_xxxxx: Die letzten Zeichen des Namens werden randomisiert, um Namenskonflikte zu vermeiden. Dieser Job erstellt das Image und endet, nachdem das Image erstellt wurde. Wenn bereits ein Image existiert, wird der Job übersprungen.

    Die Protokolle sind nützlich, um Probleme wie Konflikte in Paketabhängigkeiten zu beheben. Um die Protokolle dieses Jobs zu sehen, führen Sie die folgende SQL aus. Achten Sie darauf, dass Sie die gleichen letzten Zeichen verwenden:

    CALL SYSTEM$GET_SERVICE_LOGS('MODEL_BUILD_xxxxx', 0, 'model-build');
    
    Copy
  • MYSERVICE: Der Name des Dienstes, wie er im Aufruf von create_service angegeben ist. Dieser Job wird gestartet, wenn der MODEL_BUILD-Job erfolgreich ist oder übersprungen wird. Um die Protokolle dieses Jobs zu sehen, führen Sie die folgende SQL aus:

    CALL SYSTEM$GET_SERVICE_LOGS('MYSERVICE', 0, 'model-inference');
    
    Copy

    Wenn die Protokolle nicht über SYSTEM$GET_SERVICE_LOG verfügbar sind, weil der Build Job oder Dienst gelöscht wurde, können Sie unter die Ereignistabelle (falls aktiviert) aufrufen, um die Protokolle anzuzeigen:

    SELECT RESOURCE_ATTRIBUTES, VALUE
    FROM <EVENT_TABLE_NAME>
    WHERE true
        AND timestamp > dateadd(day, -1, current_timestamp())  -- choose appropriate timestamp range
        AND RESOURCE_ATTRIBUTES:"snow.database.name" = '<db of the service>'
        AND RESOURCE_ATTRIBUTES:"snow.schema.name" = '<schema of the service>'
        AND RESOURCE_ATTRIBUTES:"snow.service.name" = '<Job or Service name>'
    AND RESOURCE_ATTRIBUTES:"snow.service.container.instance" = '0'  -- choose all instances or one particular
    AND RESOURCE_ATTRIBUTES:"snow.service.container.name" != 'snowflake-ingress' --skip logs from internal sidecar
    ORDER BY timestamp ASC;
    
    Copy

Paketkonflikte

Zwei Systeme bestimmen, welche Pakete im Service Container installiert werden: das Modell selbst und der Inferenzserver. Um Konflikte mit den Abhängigkeiten Ihres Modells zu minimieren, benötigt der Inferenzserver nur die folgenden Pakete:

  • gunicorn<24.0.0

  • starlette<1.0.0

  • uvicorn-standard<1.0.0

Vergewissern Sie sich, dass Ihre Modellabhängigkeiten, zusammen mit den oben genannten, von pip oder conda aufgelöst werden können.

Wenn ein Modell sowohl conda_dependencies als auch pip_requirements eingestellt hat, werden diese über conda wie folgt installiert:

Kanäle:

  • conda-forge

  • nodefaults

Abhängigkeiten:

  • all_conda_packages

  • pip :
    • all_pip_packages

Snowflake bezieht Anacaonda-Pakete von conda-forge, wenn es Container-Images erstellt, da der Snowflake-Conda-Kanal nur in Warehouses verfügbar ist und der defaults -Kanal von den Benutzern verlangt, dass sie die Anaconda-Nutzungsbedingungen akzeptieren, was während eines automatisierten Builds nicht möglich ist. Um Pakete von einem anderen Kanal zu erhalten, wie z. B. defaults, geben Sie jedes Paket mit dem Namen des Kanals an, wie in defaults::pkg_name.

Bemerkung

Wenn Sie sowohl conda_dependencies als auch pip_requirements angeben, wird das Container-Image erfolgreich erstellt, auch wenn die beiden Sätze von Abhängigkeiten nicht kompatibel sind, was dazu führen kann, dass das resultierende Container-Image nicht so funktioniert, wie Sie es erwarten. Snowflake empfiehlt, nur conda_dependencies oder nur pip_requirements zu verwenden, nicht beides.

Dienst außerhalb des Speichers

Einige Modelle sind nicht Thread-sicher, so dass Snowflake für jeden Worker-Prozess eine eigene Kopie des Modells in den Speicher lädt. Dies kann bei großen Modellen mit einer größeren Anzahl von Workern dazu führen, dass der Speicher überlastet wird. Versuchen Sie, num_workers zu reduzieren.

Unbefriedigende Leistung bei Abfragen

Normalerweise wird die Inferenz durch die Anzahl der Instanzen im Inferenzdienst behindert. Versuchen Sie, einen höheren Wert für max_instances anzugeben, wenn Sie das Modell einsetzen.

Sie können die Dienstspezifikation nicht ändern

Die Dienstspezifikationen für die Modellerstellung und die Inferenz können nicht über ALTER SERVICE geändert werden. Sie können nur Attribute wie TAG, MIN_INSTANCES und so weiter ändern. Da das Image jedoch im Image Repository veröffentlicht ist, können Sie die Spezifikation kopieren, sie ändern und daraus einen neuen Dienst erstellen, den Sie manuell starten können.

Paket nicht gefunden

Die Modellbereitstellung ist während der Image-Erstellungsphase fehlgeschlagen. Die Protokolle von model-build deuten darauf hin, dass ein angefordertes Paket nicht gefunden wurde. (Dieser Schritt verwendet standardmäßig conda-forge, wenn das Paket in conda_dependencies erwähnt wird)

Die Paketinstallation kann aus einem der folgenden Gründe fehlschlagen:

  • Der Paketname oder die Version ist ungültig. Überprüfen Sie die Schreibweise und die Version des Pakets.

  • Die angeforderte Version des Pakets existiert nicht in conda-forge. Sie können versuchen, die Versionsangabe zu entfernen, um die neueste Version zu erhalten, die in conda-forge verfügbar ist, oder stattdessen pip_requirements verwenden. Sie können alle verfügbaren Pakete hier einsehen.

  • Manchmal benötigen Sie vielleicht ein Paket von einem speziellen Kanal (z. B. pytorch). Fügen Sie der Abhängigkeit ein channel_name:: Präfix hinzu, z. B. pytorch::torch.

Huggingface Hub-Version stimmt nicht überein

Ein Hugging Face-Modellinferenzdienst kann mit der folgenden Fehlermeldung fehlschlagen:

ImportError: huggingface-hub>=0.30.0,<1.0 is required for a normal functioning of this module, but found huggingface-hub==0.25.2

Das liegt daran, dass das transformers-Paket nicht die korrekten Abhängigkeiten von huggingface-hub angibt, sondern stattdessen im Code überprüft. Um dieses Problem zu beheben, protokollieren Sie das Modell erneut, wobei Sie dieses Mal die erforderliche Version von huggingface-hub in den conda_dependencies oder pip_requirements explizit angeben.

Torch kann nicht mit CUDA kompiliert werden

Die typische Ursache für diesen Fehler ist, dass Sie sowohl conda_dependencies als auch pip_requirements angegeben haben. Wie im Abschnitt Paketkonflikte erwähnt, ist conda der Paketmanager, der für die Erstellung des Container-Images verwendet wird. Anaconda löst Pakete von conda_dependencies und pip_requirements nicht gemeinsam auf und gibt conda-Paketen den Vorrang. Dies kann dazu führen, dass die conda-Pakete nicht mit den pip-Paketen kompatibel sind. Möglicherweise haben Sie torch in den pip_requirements angegeben, nicht in den conda_dependencies. Ziehen Sie in Erwägung, die Abhängigkeiten entweder in conda_dependencies oder pip_requirements zu konsolidieren. Wenn das nicht möglich ist, geben Sie lieber die wichtigsten Pakete in conda_dependencies an.

Verwenden eines kundenspezifischen Image Repository für Inferenz-Images

Wenn Sie ein Modell in Snowpark Container Services bereitstellen, erstellt Snowflake Model Serving ein Container-Image, das das Modell und seine Abhängigkeiten enthält. Um dieses Image zu speichern, benötigen Sie ein Image-Repository. Snowflake bietet ein Standard Image Repository, das automatisch verwendet wird, wenn Sie bei der Erstellung des Services kein Repository angeben. Um ein anderes Repository zu verwenden, übergeben Sie dessen Namen in das Argument image_repo der create_service-Methode.

Wenn Sie ein Image Repository verwenden, dessen Eigentümer Sie nicht sind, stellen Sie sicher, dass die Rolle, die das Container-Image erstellt, über die Berechtigungen READ, WRITE, SERVICE READ und SERVICE WRITE für das Repository verfügt. Gewähren Sie diese Berechtigungen wie folgt:

GRANT READ ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
GRANT WRITE ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
GRANT SERVICE READ ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
GRANT SERVICE WRITE ON IMAGE REPOSITORY my_inference_images TO ROLE myrole;
Copy