リアルタイム推論のためのモデルの展開( REST API )¶
注釈
snowflake-ml-pythonバージョン1.25.0以降で一般提供されています。
低レイテンシを必要とするインタラクティブなワークフローに、リアルタイム推論を使用します。Snowflakeモデルレジストリ から、専用の HTTP エンドポイントを持つマネージドサービスとして任意のモデルをデプロイできます。マネージドサービスは自動スケーリングを備えており、Snowflakeエコシステム内に完全に統合され、包括的な可観測性を提供します。
次の場合に、ワークフローにオンライン推論を使用します。
アプリケーションで、即座に応答するために低レイテンシが必要
モデルは、ユーザー向けのウェブまたはモバイルアプリケーションのバックエンドとして機能します。
モデルへの入力は、リクエストの HTTP ペイロード内に適合します。
変動するリクエスト量を処理するために、サービスは自動的に水平方向にスケールする必要があります。
仕組み¶
Snowflakeは、モデルを Snowpark Container Services( SPCS ) 内の HTTP サーバーとしてホストすることで、展開パイプラインを簡素化します。このアーキテクチャにより、次のことが可能になります。
複雑さの抽象化: DockerイメージやKubernetesクラスターを管理することなく、高度なモデルをデプロイできます。
パフォーマンスのスケーリング: 高いパフォーマンス要件のために、分散された GPU クラスターで大規模スケールモデルを実行できます。
信頼性の確保: 組み込みの可観測性、トラフィック分割、およびシャドウ/カナリア展開を利用して、モデルをシームレスにアップグレードできます。
前提条件¶
始める前に、以下をご確認ください。
商用の AWS 、Azure、またはGoogle CloudリージョンのSnowflakeアカウント。政府リージョンはサポートされていません。
snowflake-ml-python Pythonパッケージのバージョン1.8.0以降。
Snowflakeモデルレジストリ にログインしたモデル。
コンピューティングプール および SPCS での関連権限に関する理解。
必要な権限¶
Model Servingは Snowpark Container Services 上で実行されます。Model Servingを使用するには以下の権限が必要です。
サービスが実行されるコンピューティングプールに対する USAGE または OWNERSHIP 。または、デフォルトのシステムコンピューティングプールを使用できます。
パブリックエンドポイントを作成できるアカウントに対する BIND SERVICE ENDPOINT 権限。
モデルに対する OWNER または READ 権限
制限事項¶
Snowpark Container Servicesでのオンラインモデルサービングには、以下の制限が適用されます。
テーブル関数はサポートされていません。モデルをSnowflakeに展開するためにはテーブル関数が必要です。
Snowpark ML モデリングクラスを使用して開発されたモデルは、 GPU を持つ環境にはデプロイできません。回避策として、ネイティブモデルを抽出して、それをデプロイすることができます。詳細については、 オンライン推論のためのモデルの展開 をご参照ください。
オンライン推論のためのモデルの展開¶
Snowflake ML は、モデルバージョンオブジェクトを使用して、推論リクエストを処理するモデルサービスを作成します。モデルバージョンオブジェクトを作成するには、新しいモデルバージョンをログに記録するか、既存のモデルバージョンの参照を取得します。モデルのバージョンオブジェクトを取得したら、以下のPythonコードを使ってモデルサービスを作成し、そのサービスを SPCS にデプロイできます:
# 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)
create_service には以下の引数が必要です。
service_name:作成するサービス名。この名前はSnowflakeアカウント内で一意である必要があります。
service_compute_pool:モデルの実行に使用しているコンピューティングプールの名前。コンピューティングプールはすでに存在している必要があります。モデルがシステムコンピューティングプールに適合していれば、それら(
SYSTEM_COMPUTE_POOL_GPUまたはSYSTEM_COMPUTE_POOL_CPU) も使用できます。ingress_enabled:Snowflakeの外部からオンライン推論を呼び出すには、これがTrueである必要があります。
gpu_requests:GPUs の数を指定する文字列。CPU または複数の GPUs のいずれかで実行できるモデルの場合、この引数は、モデルが CPU と GPUs のどちらで実行されるかを決定します。モデルが CPU でのみ実行できる既知のタイプである場合 (scikit-learnモデルなど)、 GPUs をリクエストするとイメージビルドに失敗します。新しいモデルをデプロイする場合、 CPU 駆動型モデルのサービスを作成するのに最大10分、 GPU 駆動型モデルを作成するのに20分かかります。コンピューティングプールがアイドル状態であるか、サイズ変更が必要な場合は、サービスの作成に時間がかかる可能性があります。
前述の例は、必須かつ最もよく使われる引数のみを示しています。引数の完全なリストは ModelVersion API リファレンスをご参照ください。
デフォルトのサービス構成¶
デプロイしたモデルを実行するサーバーは、ほとんどのユースケースで機能するデフォルトを使用します。
ワーカースレッド数:CPU 駆動型モデルの場合、サーバーが使用するプロセス数は CPUs の2倍+1個です。GPU 駆動型はワーカープロセスを1つ使用します。create_serviceコールではnum_workers引数を使用して、これをオーバーライドできます。モデルがメモリに収まる最小 GPU ノードを指定することを お勧め します。インスタンス数を増やしてスケールします。例えば、モデルが GPU_NV_S (Azureの GPU_NV_SM )インスタンスタイプに適合する場合、gpu_requests=1を使用し、max_instancesを増やしてスケールアップします。ただし、利用可能な最小ノードに4個のGPUs があり、必要なものが2つだけの場合は、
num_workers=2(つまり、利用可能なgpu/モデルに必要なgpu)を使用します。スレッドセーフティ:スレッドセーフでないモデルもあります。そのため、サービスはワーカープロセスごとにモデルの別個のコピーをロードします。その結果、大規模なモデルではリソースが枯渇する可能性があります。
ノード利用:デフォルトでは、1つの推論サーバーインスタンスは、実行するノードのすべての CPU とメモリをリクエストすることで、ノード全体をリクエストします。インスタンスごとのリソース割り当てをカスタマイズするには、cpu_requests、memory_requests、gpu_requestsなどの引数を使用します。
エンドポイント:推論エンドポイントはinferenceと名付けられ、ポート5000を使用します。これらはカスタマイズできません。リソースの利用率を最適化するには、モデルがメモリに収まる最小 GPU ノードを指定します。インスタンス数を増やして、ワークロードに合わせてスケールします。例えば、モデルが GPU_NV_S (Azureの GPU_NV_SM )インスタンスタイプに適合する場合、gpu_requests=1を使用し、max_instancesを増やしてスケールアップします。
コンテナイメージのビルド動作¶
Snowflakeのcondaチャネルはウェアハウスでのみ利用可能で、ウェアハウスの依存関係の唯一のソースです。デフォルトでは、 SPCS モデルのconda依存関係はconda-forgeから依存関係を取得します。
デフォルトでは、Snowflake Model Servingは、モデルの実行に使用されるのと同じコンピューティングプールを使用してコンテナイメージを構築します。このコンピューティングプールは、イメージの構築プロセスにはオーバーパワーである可能性が高いです(例えば、 GPUs は、コンテナイメージの構築には使用されません)。ほとんどの場合、これはコンピューティングコストに大きな影響を与えません。それでも心配な場合は、image_build_compute_pool引数を使用してイメージを構築するためによりパワーが控えめのコンピューティングプールを指定できます。
create_service()を複数回呼び出しても、呼び出すたびに構築がトリガーされるわけではありません。
しかし、コンテナイメージは、snowflakeが依存パッケージの脆弱性の修正を含む推論サービスの更新を行った場合、再構築される可能性があります。この場合、create_serviceは自動的にイメージの再構築をトリガーします。
ユーザーインターフェイス¶
展開されたモデルは、Model Registry Snowsight UI で管理できます。詳細については、 モデル推論サービス をご参照ください。
デプロイ済みモデルの呼び出し¶
HTTP エンドポイント¶
すべてのサービスには内部 DNS 名前が付いています。ingress_enabledでサービスをデプロイすると、Snowflake外で利用可能なパブリック HTTP エンドポイントも作成されます。どちらのエンドポイントもサービスを呼び出すのに使用できます。
SHOW ENDPOINTS コマンドを使用して、イングレスを有効にしたサービスのパブリック HTTP エンドポイントを見つけることができます。出力にはingress_url列が含まれ、これには unique-service-id-account-id.snowflakecomputing.app形式のエントリがあります。これは一般に公開されているサービスの HTTP エンドポイントです。プライベートリンクユーザーの場合は、ingress_urlではなくprivatelink_ingress_urlを使用してください。
Snowflakeでの内部 DNS 名を取得するには、 DESCRIBE SERVICE コマンドを使用します。このコマンドによる出力のdns_name列に、サービスの内部 DNS 名が含まれます。サービスのポートを見つけるには、SHOW ENDPOINTS IN SERVICE コマンドを使用します。ポートまたはport_range列には、サービスが使用するポートが含まれています。URL http://dns_name:port を介してサービスを内部で呼び出すことができます。
モデルの特定のメソッドを呼び出すには、メソッド名を URL (例: https://unique-service-id-account-id.snowflakecomputing.app/method-name または http://dns_name:port/<method-name> )へのパスとして使用します。URL で、メソッド名のアンダースコア(_)は URL 内でダッシュ(-)に置き換えられます。たとえば、predict_probのサービス名は、 URL でpredict-probaに変更されます。
簡略化するために、Pythonでは、list_services() API を ModelVersion オブジェクトで呼び出すことができます。
# mv: snowflake.ml.model.ModelVersion
mv.list_services()
これは、パブリックエンドポイント( inference_endpoint )および内部エンドポイント( internal_endpoint )両方を出力します。
認証¶
Snowflakeは複数の認証プロトコルをサポートしています。最もシンプルなのは、トークンを Authorization: Snowflake Token="your_pat_token" としてリクエストヘッダーに単純に渡すことができる プログラムのアクセストークン( PAT ) を使用することです。
注釈
不正なトークンやサービスへのネットワークの欠落など、認証の失敗はすべて404エラーでサービスの結果にルーティングされます。現在、認証エラーと無効な URLs を区別する方法はありません。
リクエスト本文(またはプロトコルまたはデータ形式)¶
Snowflakeは、 REST リクエストについて2種類のデータ形式をサポートしています。特に業界でよく知られており、Pandas DataframeのシンプルなPythonスクリプトを使用して顧客が検証できることから、Pandas Dataframeの影響を受けています。
Tip
メソッドから URL へのマッピング: リクエスト URL 作成時、モデルのメソッド名のアンダースコア( _ )は自動的にダッシュ( - )に置き換えられることに注意してください。例えば、モデルメソッドが predict_proba の場合、エンドポイント URL パスは /predict-proba になります。
形式の詳細は次のとおりです
dataframe_splitは、コンパクトなインデックス/列/データ表現です。
pandas_df.to_json(orient="split")を反映する表現。
dataframe_recordsはキー/値(記録指向)表現です。
df.to_json(orient="records")を反映する表現。
dataframe_split 形式を使用することを お勧め します。dataframe_records は各行で列名を繰り返すため、通常、 dataframe_split よりも大きなリクエスト本文を生成します。これは、大規模なバッチや頻繁な呼び出しのパフォーマンスに影響を与える可能性があります。
モデルエンドポイントは、使用する入力形式に関係なく、 単一の出力形式 を返し続けます。
dataframe_split形式(推奨)
これは、Pandasの「分割」方向によって生成される構造と一致します。リクエスト本文は、 dataframe_split キーの下に以下の構造をラップします:
index:行インデックスのリスト。columns:列名のリスト。data:行のリスト。各行は列に沿った値のリストです。
cURL リクエストの例:
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],
]
}
}'
dataframe_records形式
dataframe_records は、 Pandas記録指向 によって生成される構造と一致します。
記録のリスト では、各記録は 列名 を 値 にマッピングするディクショナリです。
リクエスト本文は dataframe_records キーの下にこのリストをラップします:
cURL リクエストの例:
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,
},
]
}'
パラメーターの引き渡し¶
モデルの署名に、:doc:`ParamSpec</developer-guide/snowflake-ml/model-registry/model-signature>`で定義されたパラメーターが含まれている場合、JSONリクエスト本文のトップレベルに:code:`dataframe_split`または:code:`dataframe_records`と並べて:code:`params`キーを含めることで、パラメーター値を渡すことができます。上書きするパラメーターのみを含めてください。指定しなかったパラメーターについては、署名のデフォルト値が使用されます。
パラメーターを使用した:code:`cURL`リクエストの例:
curl -X POST "<endpoint_url>/predict" \
-H 'Authorization: Snowflake Token="<pat_token>"' \
-H 'Content-Type: application/json' \
-d '{
"dataframe_split": {
"index": [0],
"columns": ["input_text"],
"data": [["Hello, world!"]]
},
"params": {"temperature": 0.9, "max_tokens": 512}
}'
:code:`params`キーは、:code:`dataframe_records`形式においても同様に機能します。
curl -X POST "<endpoint_url>/predict" \
-H 'Authorization: Snowflake Token="<pat_token>"' \
-H 'Content-Type: application/json' \
-d '{
"dataframe_records": [
{"input_text": "Hello, world!"}
],
"params": {"temperature": 0.9, "max_tokens": 512}
}'
Pythonの例¶
dataframe_split形式
Snowflakeは、 Pandas JSON シリアル化 を使用してペイロードを生成し、リクエストを送信する前に json.loads で逆シリアル化することをお勧めしています。これにより、データ型の一貫した処理が保証されます。
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()
重要なポイント:
pd.Dataframe.to_json(例:
df.to_json(orient="split"))を使用して、ネイティブJSONシリアライザーにとってなじみのないタイムスタンプ、浮動小数点数、NULL、カテゴリなどの型を正しく処理します。json.loads(...)は JSON 文字列をPythonディクショナリに変換するので、ペイロードを適切に構築することができます。requests.post(..., json=payload)はディクショナリを HTTP リクエストの JSON にシリアル化します。
パラメーターを含めるには、ペイロードディクショナリに:code:`params`キーを追加します。
payload = {
"dataframe_split": split_obj,
"params": {"temperature": 0.9, "max_tokens": 512}
}
dataframe_records形式
dataframe_split と同様に、Pandas JSON シリアル化と 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()
次のステップ¶
これらの詳細ガイドを調べて、推論サービスを最適化し管理します。
ワークフローの例:XGBoost ( CPU )、Hugging Face(GPU)、および PyTorch モデルのエンドツーエンドコードをご参照ください。
サービス管理とスケーリング: 自動スケーリング、手動停止、ハードウェア構成について学びます。
安定したエンドポイントと API リファレンス: Snowflake Gateway、認証、およびデータプロトコル(
dataframe_split)を掘り下げます。自動キャプチャ推論ログ: モデルモニタリングのために自動ログを設定します。
トラブルシューティング: パッケージの競合、 OOM エラー、ビルドの失敗の一般的な修正。