Einsatz von Modellen für Echtzeit-Inferenz (REST API)

Bemerkung

Allgemein verfügbar ab snowflake-ml-python Version 1.25.0.

Verwenden Sie Echtzeit-Inferenz für interaktive Workflows, die eine geringe Latenzzeit erfordern. Sie können jedes Modell über die Snowflake Model Registry als verwalteten Dienst mit einem dedizierten HTTP-Endpunkt bereitstellen. Verwaltete Dienste verfügen über eine automatische Skalierung, sind vollständig in das Snowflake-Ökosystem integriert und bieten eine umfassende Beobachtbarkeit.

Verwenden Sie die Online-Inferenz in den folgenden Situationen für Ihren Workflow:

  • Ihre Anwendung benötigt eine niedrige Latenz für sofortige Antworten.

  • Ihr Modell dient als Backend für eine auf Benutzende zugeschnittene Webanwendung oder eine mobile Anwendung.

  • Die Eingabe für Ihr Modell kann in die HTTP-Nutzlast der Anforderung übertragen werden.

  • Der Dienst muss automatisch horizontal skaliert werden, um schwankende Anforderungsvolumen zu bewältigen.

Wie es funktioniert

Snowflake vereinfacht die Bereitstellungspipeline, indem Ihr Modell als HTTP-Server innerhalb von Snowpark Container Services (SPCS) gehostet wird. Diese Architektur ermöglicht Folgendes:

  • Komplexität abstrahieren: Bereitstellen von anspruchsvollen Modellen, ohne Docker-Images oder Kubernetes-Cluster verwalten zu müssen.

  • Leistung skalieren: Ausführen umfangreicher Modelle auf verteilten GPU-Clustern für hohe Leistungsanforderungen.

  • Zuverlässigkeit sicherstellen: Verwenden von integrierter Beobachtbarkeit, Aufteilung des Datenverkehrs und Shadow-/Canary-Bereitstellungen für nahtlose Modellaktualisierungen.

Voraussetzungen

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

  • Ein Snowflake-Konto in einer beliebigen kommerziellen Region von AWS, Azure oder Google Cloud. Regionen für Regierungsbehörden werden nicht unterstützt.

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

  • Ein Modell, das bei der Snowflake Model Registry angemeldet ist.

  • Ein Verständnis von -Computepools und den entsprechenden Berechtigungen für SPCS.

Erforderliche Berechtigungen

Model Serving läuft auf Basis von Snowpark Container Services. Sie benötigen die folgenden Berechtigungen, um Model Serving verwenden zu können:

  • USAGE oder OWNERSHIP für den Computepool, in dem der Dienst läuft. Alternativ können Sie auch die Standard-System-Computepools verwenden.

  • BIND SERVICE ENDPOINT-Berechtigung für das Konto, um einen öffentlichen Endpunkt erstellen zu können.

  • OWNER- oder READ-Berechtigung für das Modell.

Einschränkungen

Die folgenden Beschränkungen gelten für die Online-Bereitstellung von Modellen in Snowpark Container Services.

  • Tabellenfunktionen werden nicht unterstützt. Ihr Modell muss eine Tabellenfunktion aufweisen, um in Snowflake bereitgestellt zu werden.

  • 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. Weitere Informationen dazu finden Sie unter Einsatz eines Modells für Online-Inferenz.

Einsatz eines Modells für Online-Inferenz

Snowflake ML verwendet ein Modellversionsobjekt, um einen Modelldienst zu erstellen, der Inferenzanfragen verarbeitet. Um ein Objekt für eine Modellversion zu erstellen, können Sie entweder eine neue Modellversion protokollieren oder einen Verweis auf eine bestehende Modellversion erhalten. Nachdem Sie Ihr Modellversionsobjekt erhalten haben, können Sie den folgenden Python-Code verwenden, um einen Modelldienst zu erstellen und diesen Dienst in SPCS bereitzustellen:

# reg is a snowflake.ml.registry.Registry object
example_mv_object = reg.get_model("mymodel_name").version("version_name") # a snowflake.ml.model.ModelVersion object

example_mv_object.create_service(service_name="myservice",
                  service_compute_pool="my_compute_pool",
                  ingress_enabled=True,
                  gpu_requests=None)
Copy

create_service erfordert die folgenden Argumente:

  • service_name: Der Name des Dienstes, den Sie erstellen. Dieser Name muss innerhalb Ihres Snowflake-Kontos eindeutig sein.

  • service_compute_pool: Der Name des Computepools, den Sie für die Ausführung des Modells verwenden. Der Computepool muss bereits existieren. Wenn das Modell gut für System-Computepools passt, können Sie diese (SYSTEM_COMPUTE_POOL_GPU oder SYSTEM_COMPUTE_POOL_CPU) auch verwenden.

  • ingress_enabled: Der Wert muss „True“ sein, um Online-Inferenz von außerhalb von Snowflake aufzurufen.

  • gpu_requests: Eine Zeichenfolge, die die Anzahl der GPUs angibt. Bei einem Modell, das entweder auf einer CPU oder auf mehreren GPUs ausgeführt werden kann, bestimmt dieses Argument, ob das Modell auf der CPU oder auf den GPUs ausgeführt wird. Wenn es sich bei dem Modell um einen bekannten Typ handelt, der nur auf einer CPU ausgeführt werden kann (z. B. scikit-learn-Modelle), schlägt die Image-Erstellung fehl, wenn GPUs angefordert werden. Wenn Sie ein neues Modell bereitstellen, kann es bis zu 10 Minuten dauern, bis der Service für CPU-gestützte Modelle erstellt worden ist und 20 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.

Das vorangehende Beispiel zeigt nur die erforderlichen und am häufigsten verwendeten Argumente. Eine vollständige Auflistung der Argumente finden Sie in der ModelVersion API-Referenz.

Standard Konfiguration des Dienstes

Der Server, der das von Ihnen bereitgestellte Modell ausführt, verwendet Standardwerte, die für die meisten Anwendungsfälle geeignet sind:

  • Anzahl der Worker-Threads: Bei einem CPU-gestützten Modell ist die Anzahl der Prozesse, die der Server verwendet, doppelt so groß wie die Anzahl der CPUs plus einem Prozess. GPU-gestützte Modelle verwenden einen Worker-Prozess. Sie können dies mit dem Argument num_workers im create_service-Aufruf überschreiben. Es wird empfohlen, den kleinsten GPU-Knoten anzugeben, bei dem das Modell in den Speicher passt. Skalieren Sie, indem Sie die Anzahl der Instanzen erhöhen. Wenn das Modell beispielsweise in GPU_NV_S (GPU_NV_SM in Azure) passt, verwenden Sie gpu_requests=1 und skalieren nach oben, indem Sie den Wert für max_instances erhöhen. Wenn der kleinste verfügbare Knoten jedoch 4 GPUs hat und Sie nur 2 benötigen, verwenden Sie num_workers=2 (d. h. GPU verfügbar / GPUs, die vom Modell benötigt werden).

  • 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. Für eine optimale Ressourcennutzung geben Sie den kleinsten GPU-Knoten an, bei dem das Modell in den Speicher passen kann. Erhöhen Sie die Anzahl der Instanzen, die an Ihre Workload angepasst werden. Wenn das Modell beispielsweise in GPU_NV_S (GPU_NV_SM in Azure) passt, verwenden Sie gpu_requests=1 und skalieren nach oben, indem Sie den Wert für max_instances erhöhen.

Verhaltensweise bei der Erstellung von Container-Images

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.

Standardmäßig erstellt Snowflake Model Serving das Container-Image unter Verwendung desselben Computepools, der für die Ausführung des Modells verwendet wird. Der Computepool ist für den Prozess der Image-Erstellung vermutlich überdimensioniert (zum Beispiel werden GPUs nicht für die Erstellung von Container-Images verwendet). In den meisten Fällen wird dies keine wesentlichen Auswirkungen auf die Computekosten haben. Wenn Sie jedoch Bedenken haben, können Sie mit dem Argument image_build_compute_pool einen weniger leistungsfähigen Pool für die Erstellung von Images angeben.

Auch wenn create_service() mehrfach aufgerufen wird, wird nicht jedes Mal ein neuer Image-Erstellungsprozess ausgelöst.

Container-Images können jedoch neu erstellt werden, wenn Snowflake Aktualisierungen am Inference-Service vorgenommen hat, einschließlich Korrekturen für Sicherheitslücken in abhängigen Paketen. Wenn dies geschieht, löst create_service automatisch eine Neuerstellung des Images aus.

Benutzeroberfläche

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

Aufrufen des bereitgestellten Modells

HTTP-Endpunkte

Jeder Service verfügt über einen internen DNS-Namen. Das Bereitstellen eines Service mit ingress_enabled erstellt auch einen öffentlichen HTTP-Endpunkt, der außerhalb von Snowflake verfügbar ist. Jeder Endpunkt kann verwendet werden, um einen Service aufzurufen.

Sie finden den öffentlichen HTTP-Endpunkt eines Service mit aktiviertem Eingang über den Befehl SHOW ENDPOINTS. Die Ausgabe enthält eine Spalte „ingress_url“, die einen Eintrag im Format eindeutige-service-id-konto-id.snowflakecomputing.app enthält. Dies ist der öffentlich zugängliche HTTP-Endpunkt für Ihren Service. Für Benutzende von Private Link verwenden Sie „privatelink_ingress_url“ anstelle von „ingress_url“.

Um den internen DNS-Namen in Snowflake abzurufen, verwenden Sie den Befehl DESCRIBE SERVICE. Die Spalte „dns_name“ der Ausgabe dieses Befehls enthält den internen DNS-Namen des Service. Um den Port Ihres Service zu finden, verwenden Sie die den Befehl SHOW ENDPOINTS IN SERVICE. Die Spalte „port“ oder „port_range“ enthält den von einem Dienst verwendeten Port. Sie können Ihren Service über die URL http://dns_name:port aufrufen.

Um eine bestimmte Methode des Modells aufzurufen, verwenden Sie den Methodennamen als Pfad zur URL (z. B. https://unique-service-id-account-id.snowflakecomputing.app/method-name oder http://dns_name:port/<method-name>). In einer URL werden Unterstriche (_) im Methodennamen durch Bindestriche (-) in der URL ersetzt. So wird beispielsweise der Name des Dienstes „predict_prob“ in „prediction-proba“ in der URL geändert.

Zur Vereinfachung kann in Python die list_services()-API für das ModelVersion-Objekt aufgerufen werden:

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

Sie liefert Ausgaben sowohl für den öffentlichen Endpunkt (inference_endpoint) als auch für den internen Endpunkt (internal_endpoint).

Authentifizierung

Snowflake unterstützt mehrere Authentifizierungsprotokolle. Am einfachsten ist die Verwendung von programmgesteuerten Zugriffstoken (PAT), wobei ein Token hierbei einfach als Authorization: Snowflake Token="your_pat_token" an den Anforderungs-Header übergeben werden kann.

Bemerkung

Alle Autorisierungsfehler wie ein falsches Token oder das Fehlen einer Netzwerkverbindung zum Service führen zu einem 404-Fehler. Es gibt derzeit keine Möglichkeit, Authentifizierungsfehler von ungültigen URLs zu unterscheiden.

Autorisierung

Standardmäßig können nur Personen mit den entsprechenden Eigentumsrechten am Dienst den Endpunkt verwenden. Um einer anderen Rolle den Zugriff auf den Endpunkt zu ermöglichen, können diese Personen die Dienstrolle ALL_ENDPOINTS_USAGE gewähren.

Anforderungstext (oder Protokoll oder Datenformat)

Snowflake unterstützt zwei Arten von Datenformaten für REST-Anforderungen. Sie orientieren sich an pandas-Datenframes, da sie in der Branche sehr bekannt sind und von Kunden mithilfe einfacher Python-Skripte mit einem pandas-Datenframe überprüft werden können.

Tipp

Methode-zu-URL-Zuordnung: Beachten Sie bei der Erstellung Ihrer Anforderungs-URL, dass Unterstriche (_) in den Methodennamen Ihres Modells automatisch durch Bindestriche (-) ersetzt werden. Wenn Ihre Modellmethode z. B. predict_proba ist, wird der Endpunkt-URL-Pfad zu /predict-proba.

Hier finden Sie die Details zu den Formaten

  1. dataframe_split ist eine kompakte, Index/Spalten/Daten-Darstellung.

  • Eine Darstellung, die pandas_df.to_json(orient="split") spiegelt.

  1. dataframe_records ist eine Schlüssel/Wert-Darstellung (datensatzorientiert).

  • Eine Darstellung, die df.to_json(orient="records") spiegelt.

Es wird empfohlen, das dataframe_split-Format zu verwenden. Da dataframe_records die Spaltennamen für jede Zeile wiederholt, erzeugt diese Darstellung normalerweise einen größeren Anforderungstext als dataframe_split. Dies kann sich bei großen Batches oder häufigen Aufrufen auf die Leistung auswirken.

Modell-Endpunkte geben weiterhin ein einziges Ausgabeformat zurück, unabhängig davon, welches Eingabeformat Sie verwenden.

  1. dataframe_split-Format (empfohlen)

Dies entspricht der Struktur, die durch die „split“-Ausrichtung von pandas erzeugt wird. Der Anforderungstext ist unter einem:code:dataframe_split-Schlüssel in der folgenden Struktur organisiert:

  • index: Eine Liste von Zeilenindizes.

  • columns: Eine Liste der Spaltennamen.

  • data: Eine Liste von Zeilen, wobei jede Zeile eine Liste von Werten ist, die auf die Spalten abgestimmt sind.

Beispiel für eine cURL-Anforderung:

curl -X POST "<endpoint_url>" \
  -H 'Authorization: Snowflake Token="<pat_token>"' \
  -H 'Content-Type: application/json' \
  -w "\n\n=== RESULT ===\nHTTP Status: %{http_code}\nTotal Time: %{time_total}s\nConnect Time: %{time_connect}s\nServer Processing: %{time_starttransfer}s\nResponse Size: %{size_download} bytes\nRequest Size: %{size_upload} bytes\n" \
 -d '{
       "dataframe_split": {
         "index": [0, 1],
         "columns": ["customer_id", "age", "monthly_spend"],
         "data": [
            [101, 32, 85.5],
            [102, 45, 120.0],
         ]
       }
     }'
Copy
  1. dataframe_records-Format

dataframe_records entspricht der Struktur, die durch die „records“-Ausrichtung von pandas erzeugt wird.

  • Eine Liste von Datensätzen, wobei jeder Datensatz ein Wörterbuch ist, das Spaltennamen zu Werten zuordnet.

Der Anforderungstext ist unter dem dataframe_records-Schlüssel in der folgenden Liste organisiert:

Beispiel für eine cURL-Anforderung:

curl -X POST "<endpoint_url>" \
  -H 'Authorization: Snowflake Token="<pat_token>"' \
  -H 'Content-Type: application/json' \
  -w "\n\n=== RESULT ===\nHTTP Status: %{http_code}\nTotal Time: %{time_total}s\nConnect Time: %{time_connect}s\nServer Processing: %{time_starttransfer}s\nResponse Size: %{size_download} bytes\nRequest Size: %{size_upload} bytes\n" \
 -d '{
       "dataframe_records": [
          {
            "customer_id": 101,
            "age": 32,
            "monthly_spend": 85.5,
          },
          {
            "customer_id": 102,
            "age": 45,
            "monthly_spend": 120.0,
          },
        ]
     }'
Copy

Python-Beispiele

  1. dataframe_split-Format

Snowflake empfiehlt, die Payload mithilfe der JSON-Serialisierung von pandas zu erzeugen und vor dem Senden der Anforderung mit json.loads zu deserialisieren. Dadurch wird sichergestellt, dass die Datentypen konsistent gehandhabt werden.

import json
import pandas as pd
import requests

# Example DataFrame
df = pd.DataFrame(
    {
        "customer_id": [101, 102],
        "age": [32, 45],
        "monthly_spend": [85.5, 120.0],
    }
)

ENDPOINT_URL = "<your endpoint URL>"
HEADERS = {
    "Authorization": f'Snowflake Token="{PAT}"',
    "Content-Type": "application/json"
}

# Use Pandas to generate the JSON, then load it back to a Python dict
split_obj = json.loads(df.to_json(orient="split"))

payload = {
    "dataframe_split": split_obj
}

response = requests.post(
    ENDPOINT_URL,
    headers=HEADERS,
    json=payload,
    timeout=30,
)

result = response.json()
Copy

Wichtigste Punkte:

  • Verwenden Sie pd.Dataframe.to_json (z. B. df.to_json(orient="split") ), um Typen wie Zeitstempel, Floats, Nullen, Kategoriale usw. korrekt zu verarbeiten, mit denen das native JSON-Serialisierungsprogramm nicht vertraut ist.

  • json.loads(...) konvertiert die JSON-Zeichenfolge in ein Python-Wörterbuch, damit die Nutzlast korrekt erstellt werden kann.

  • requests.post(..., json=payload) serialisiert das Wörterbuch für die HTTP-Anforderung zurück nach JSON.

  1. dataframe_records-Format

Verwenden Sie wie auch bei dataframe_split die JSON-Serialisierung von pandas und json.loads:

import json
import pandas as pd
import requests

df = pd.DataFrame(
    {
        "customer_id": [101, 102],
        "age": [32, 45],
        "monthly_spend": [85.5, 120.0],
    }
)

ENDPOINT_URL = "<your endpoint invoke URL>"
HEADERS = {
    "Authorization": "Bearer <your token>",
    "Content-Type": "application/json",
}

records_obj = json.loads(df.to_json(orient="records"))

payload = {
    "dataframe_records": records_obj
}

response = requests.post(
    ENDPOINT_URL,
    headers=HEADERS,
    json=payload,
    timeout=30,
)

response.raise_for_status()
result = response.json()
Copy

Nächste Schritte

Erkunden Sie diese detaillierten Anleitungen zur Optimierung und Verwaltung Ihrer Inferenzdienste:

  • Beispiel-Workflows: Siehe End-to-End-Code für XGBoost (CPU), Hugging Face (GPU) und PyTorch-Modelle.

  • Service Management und Skalierung: Erfahren Sie mehr über die automatische Skalierung, manuelles Anhalten und die Hardware-Konfiguration.

  • Stabile Endpunkte und API-Referenz: Erhalten Sie detaillierte Einblicke in das Snowflake Gateway, die Authentifizierung und Datenprotokolle (dataframe_split).

  • Automatische Erfassung von Inferenzprotokollen: Richten Sie die automatische Protokollierung für die Modellüberwachung ein.

  • Problembehandlung: Gängige Korrekturen für Paketkonflikte, OOM- und Build-Fehler.