View a markdown version of this page

HyperPod 推論の集約解除された事前入力とデコード - Amazon SageMaker AI

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

HyperPod 推論の集約解除された事前入力とデコード

非集約事前入力とデコード (DPD) は、LLM 推論の 2 つのフェーズである事前入力とデコードを専用の GPU プールに分割し、GPU-Direct Remote Direct Memory Access (RDMA) を使用して Elastic Fabric Adapter (EFA) 経由でキーバリュー (KV) キャッシュを転送します。

同じ GPU (コロケーション) で事前入力とデコードを実行すると、1 つのロングコンテキストリクエストで他のクライアントの処理中のトークンストリームが停止し、ロード中のトークンごとのレイテンシーが増大する可能性があります。DPD は、ある GPU のセットでコンピューティングバウンドプリフィルを実行し、別の GPUs のセットでmemory-bandwidth-boundドデコードを実行することで、この干渉を排除し、混合トラフィックでより予測可能なレイテンシーを生成し、各フェーズを個別にスケールできるようにします。

推論演算子はオーケストレーションを処理します。これには、ルーターのプロビジョニング、LMCache と NIXL を介したポッドの事前入力とデコードの配線、HyperPod オブザーバビリティとの統合が含まれます。推論エンドポイントに既に使用しているのと同じInferenceEndpointConfigリソースにpdSpecセクションを追加することで、DPD を有効にできます。

DPD が役立つ場合

DPD は、以下の条件がすべて存在する場合に最大の利点を提供します。

  • 高密度モデル — 70B 以上のパラメータ (Llama 3.3 70B など)。

  • 長い入力 — 4,000 個以上の入力トークン。トークン間レイテンシー (ITL) の改善は、入力の長さに合わせてスケールされます。これは、事前入力が長くなると、コロケーション時にデコードの干渉が増えるためです。

  • 持続的な同時実行 — 1 秒あたり 2 件以上のリクエスト。同じ GPU に対して競合する同時リクエストがないと、分解するものはありません。

  • 中程度または長い出力 — 256 個以上の出力トークン。出力トークンが多いほど、トークンごとのレイテンシーが安定することによる累積的な利点が増えます。

ワークロードの入力が短い、同時実行性が低い、または小さなモデルを使用している場合、標準のコロケーションデプロイはより簡単でうまく機能します。

前提条件

Disaggregated Prefill and Decode を使用する推論エンドポイントをデプロイする前に、ローカル開発環境で以下のコンポーネントを設定する必要があります。

  • AWS コマンドラインインターフェイス (AWS CLI)

  • kubectl を介した HyperPod Amazon EKS クラスターへのアクセス

  • それぞれのモデルチェックポイントへの読み取りアクセスを許可する Hugging Face トークン。これは、モデルチェックポイントが既に Amazon S3 バケットにある場合は必要ありません。

  • vLLM、LMCache、NVIDIA NIXL、および EFA libfabric プロバイダーを含むワーカーイメージ。次のイメージオプションがサポートされています。

    • DLC: public.ecr.aws/deep-learning-containers/vllm:server-hyperpod-cuda-v1.1

    • LMCache: lmcache/vllm-openai:v0.4.3

    どちらのイメージにも、LMCache 0.4.3、vLLM 0.19.0、NIXL 1.0.0 が含まれます。

  • HyperPod Inference Operator バージョン 3.2 以降がインストールされている。DPD は以前のバージョンではサポートされていません。演算子は、新しく作成された HyperPod Amazon EKS クラスターにデフォルトでインストールされます。既存のクラスターを使用する場合は、「」のインストール手順に従ってくださいモデルデプロイ用の HyperPod クラスターの設定。バージョンを確認します。

    kubectl get deployment hyperpod-inference-operator-controller-manager \ -n hyperpod-inference-system \ -o jsonpath='{.spec.template.spec.containers[?(@.name=="manager")].image}{"\n"}'
重要

集約解除された事前入力とデコードには、GPU-Direct RDMA をサポートする EFA 対応インスタンスが必要です。次のインスタンスタイプがサポートされています: ml.p5.48xlargeml.p5e.48xlargeml.p5en.48xlargeml.p6-b200.48xlargeml.p6-b300.48xlarge。他のインスタンスタイプは DPD ではサポートされていません。

DPD エンドポイントをデプロイする

ほとんどのInferenceEndpointConfigフィールドは、DPD 以外のエンドポイントと共有され、「」で説明されています基盤モデルとカスタムファインチューニングされたモデルをデプロイする。DPD を有効にするには、マニフェストに以下のセクションを追加します。

事前入力/デコード仕様: pdSpec

事前入力/デコードトポロジを宣言し、引数を指定します。このフィールドが存在すると、エンドポイントが分離されます。オペレータは、事前入力とデコード用に個別のデプロイを作成し、ルーターと LMCache PD バックエンドを介してそれらを接続します。

pdSpec: prefillSpec: replicas: 1 resources: limits: nvidia.com/gpu: ${GPUS_PER_NODE} requests: nvidia.com/gpu: ${GPUS_PER_NODE} args: - "--gpu-memory-utilization" - "0.75" decodingSpec: replicas: 1 resources: limits: nvidia.com/gpu: ${GPUS_PER_NODE} requests: nvidia.com/gpu: ${GPUS_PER_NODE} routingThreshold: 4096
replicas

事前入力とデコードを個別にスケールします。

resources

ロールのポッド仕様に適用されます。DPD ポッドでは最上位worker.resourcesは無視されます。ロールごとの値は上書きされます。

routingThreshold

リクエストを集約解除されたパスにルーティングするトークン長のしきい値。このしきい値を満たさないリクエストは、プリフィラーをバイパスし、デコーダーに直接移動します。

args

そのロールに固有の vLLM フラグ。起動worker.args時に にマージ: に既に存在するフラグworker.argsはロールごとの値に置き換えられます。存在しないフラグは追加されます。

DPD 環境変数: environmentVariables

これらの環境変数は、プリフィラーコンテナとデコーダーコンテナの両方に同じように適用されます。ロールごとの env-var フィールドはありません。ロールごとの動作には、pdSpec.{prefillSpec,decodingSpec}.args代わりに を使用します。

environmentVariables: - name: PD_BUFFER_SIZE value: "8589934592" - name: LMCACHE_SAVE_DECODE_CACHE value: "False" - name: PYTHONHASHSEED value: "0"
PD_BUFFER_SIZE (8 GiB)

受信 KV キャッシュ転送用にデコーダーに予約された GPU バッファ。ランクごとにサイズ指定されます。TP=8 の Llama 70B の場合、各トークンの KV キャッシュはランクあたり約 40 KB であるため、6000 トークンプロンプトはランクあたり約 0.23 GB を占有し、8 GiB は 35 個の転送を保持します。バッファが容量を超えると、デコーダーログFailed to allocate memory object, retrying...とクライアントにレイテンシーのスパイクが表示されます。必要に応じて、 を 16/32 GiB に増やすか、スケールdecodingSpec.replicasします。

LMCACHE_SAVE_DECODE_CACHE: "False"

デコーダーの冗長 L1 キャッシュを無効にします。プリフィラーは、キャッシュヒットの信頼できるソースです。

PYTHONHASHSEED: "0"

LMCache は、Python の組み込み hash() を使用してプロンプトトークンキャッシュキーを計算します。Python はデフォルトでプロセスごとにハッシュシードをランダム化するため、同一のプロンプトはプリフィラー、デコーダー、ルックアップミスに対して異なるキーを生成します。シードをピン留めすると、キーはポッド間で一致します。

ルーティング戦略を設定する

このセクションでは、DPD ルーターが各リクエストのプリフィラーを選択するために使用するルーティング戦略intelligentRoutingSpecを設定します。ルーターは、 pdSpecが存在するときに自動的に作成されます。このセクションはオプションで、デフォルトは ですprefixaware

intelligentRoutingSpec: enabled: true routingStrategy: prefixaware

DPD は、インテリジェントなルーティングと KV キャッシュと統合することもできます。詳細については、「KV キャッシュとインテリジェントルーティングを設定する」を参照してください。

1 つのプリフィルレプリカでは、すべての戦略がそのレプリカにルーティングされます。この選択は、 の場合にのみ動作に影響しますprefillSpec.replicas > 1

  • 1 つのプリフィルレプリカの場合、 prefixaware (デフォルト) を使用して、プロンプトがシステムプロンプトやチャット履歴などの一般的なプレフィックスを共有するときに KV キャッシュヒットを最大化します。

  • 複数のプリフィルレプリカの場合、 を使用してレプリカ全体に負荷roundrobinを均等に分散し、1 つのプリフィラーをホットスポッティングしないようにします。

完全な例

次のマニフェストは、2 つの ml.p5.48xlarge インスタンス (1 つのプリフィラー、1 つのデコーダー) に Llama 3.3 70B をデプロイします。

apiVersion: inference.sagemaker.aws.amazon.com/v1 kind: InferenceEndpointConfig metadata: name: dpd-test namespace: default spec: endpointName: dpd-test instanceType: ml.p5.48xlarge invocationEndpoint: v1/chat/completions modelName: Llama-3.3-70B-Instruct modelSourceConfig: modelSourceType: s3 modelLocation: Llama-3.3-70B-Instruct s3Storage: bucketName: <YOUR_BUCKET> region: <YOUR_REGION> loadBalancer: healthCheckPath: /health metrics: enabled: true kvCacheSpec: enableL1Cache: true intelligentRoutingSpec: enabled: true routingStrategy: prefixaware pdSpec: prefillSpec: replicas: 1 resources: requests: nvidia.com/gpu: "8" limits: nvidia.com/gpu: "8" decodingSpec: replicas: 1 resources: requests: nvidia.com/gpu: "8" limits: nvidia.com/gpu: "8" routingThreshold: 4096 worker: image: public.ecr.aws/deep-learning-containers/vllm:server-hyperpod-cuda-v1.1 args: - "--model" - "/opt/ml/model" - "--host" - "0.0.0.0" - "--port" - "8000" - "--tensor-parallel-size" - "8" - "--max-model-len" - "16384" - "--gpu-memory-utilization" - "0.75" modelInvocationPort: name: http containerPort: 8000 modelVolumeMount: name: model-weights mountPath: /opt/ml/model resources: requests: cpu: "96" memory: 1024Gi nvidia.com/gpu: "8" limits: cpu: "96" memory: 1024Gi nvidia.com/gpu: "8" environmentVariables: - name: HF_HOME value: /tmp/hf_home - name: PD_BUFFER_SIZE value: "8589934592" - name: LMCACHE_SAVE_DECODE_CACHE value: "False" - name: PYTHONHASHSEED value: "0"

マニフェストを適用します。

kubectl apply -f inference_endpoint_dpd_config.yaml

デプロイメントを確認する

イメージのプルとモデルのロードには数分かかります。ポッドのステータスをモニタリングします。

kubectl get pods -A \ | grep -E "prefill-|decode-|router"

正常なデプロイでは、以下が表示されます。

NAMESPACE NAME READY STATUS RESTARTS AGE default prefill-dpd-test-XXXX 3/3 Running 0 7m default decode-dpd-test-XXXX 3/3 Running 0 7m hyperpod-inference-system dpd-test-router-XXXX 2/2 Running 0 7m

各モデルポッドには 3 つのコンテナ (vLLM ワーカー、Nginx リバースプロキシ、OpenTelemetry コレクター) があります。ルーターポッドには 2 つのコンテナ (ルーター、OpenTelemetry コレクター) があります。InferenceEndpointConfig ステータスを確認します。

kubectl get inferenceendpointconfig dpd-test -n default \ -o jsonpath='{.status.conditions[0].message}{"\n"}'

正常な出力: DPD prefill and decode deployments are ready

DPD ロールを検証する

プリフィラーレポートsenderとデコーダーレポートを確認しますreceiver。これは最も区別のつかない単一の起動シグナルです。両方のポッドが同じロールを報告するか、どちらのポッドも行を出力しない場合、オペレータは DPD を正しくワイヤリングしませんでした。

PREFILL_POD=$(kubectl get pod -n ${NAMESPACE} \ -l 'inference.sagemaker.aws.amazon.com/dpd-role=prefill' \ -o jsonpath='{.items[0].metadata.name}') DECODE_POD=$(kubectl get pod -n ${NAMESPACE} \ -l 'inference.sagemaker.aws.amazon.com/dpd-role=decode' \ -o jsonpath='{.items[0].metadata.name}') kubectl logs $PREFILL_POD -n ${NAMESPACE} -c prefill-${DEPLOYMENT_NAME} \ | grep -oE "'pd_role': '[a-z]+'" | sort -u kubectl logs $DECODE_POD -n ${NAMESPACE} -c decode-${DEPLOYMENT_NAME} \ | grep -oE "'pd_role': '[a-z]+'" | sort -u

正常な出力:

'pd_role': 'sender' 'pd_role': 'receiver'

エンドポイントの呼び出し

エンドポイントの準備ができたら、短いプロンプトと長いプロンプトを送信して両方のルーティングパスを実行し、ログをチェックして EFA 経由の KV 転送を確認します。

PREFILL_POD=$(kubectl get pod -n ${NAMESPACE} \ -l 'inference.sagemaker.aws.amazon.com/dpd-role=prefill' \ -o jsonpath='{.items[0].metadata.name}') DECODE_POD=$(kubectl get pod -n ${NAMESPACE} \ -l 'inference.sagemaker.aws.amazon.com/dpd-role=decode' \ -o jsonpath='{.items[0].metadata.name}') ROUTER_POD=$(kubectl get pods -n hyperpod-inference-system -o name \ | grep -- "${DEPLOYMENT_NAME}-${NAMESPACE}-router" | head -1) ROUTER_URL=http://${DEPLOYMENT_NAME}-${NAMESPACE}-routing-service.hyperpod-inference-system.svc.cluster.local:443/v1/chat/completions

短いプロンプト (しきい値未満、デコーダーに直接送信)

プリフィラーをroutingThresholdバイパスするよりも少ないトークンを持つリクエストは、デコーダーに直接移動します。

kubectl run curl-short --rm -it --image=curlimages/curl --restart=Never -- \ curl -s -k -X POST "$ROUTER_URL" \ -H "Content-Type: application/json" \ -d '{ "model": "/opt/ml/model", "messages": [{"role": "user", "content": "What is disaggregated prefill-decode in one sentence?"}], "max_tokens": 80, "temperature": 0.0 }'

長いプロンプト (しきい値、DPD パスを超過)

しきい値を超えるリクエストは、KV キャッシュ計算用のプリフィラーを経由し、トークン生成用のデコーダーにルーティングされます。

kubectl run curl-long --rm -it --image=curlimages/curl --restart=Never -- sh -c ' LONG="" i=0; while [ $i -lt 600 ]; do LONG="${LONG}The quick brown fox jumps over the lazy dog. "; i=$((i+1)); done curl -s -k -X POST "'"$ROUTER_URL"'" \ -H "Content-Type: application/json" \ -d "{\"model\":\"/opt/ml/model\",\"messages\":[{\"role\":\"user\",\"content\":\"${LONG}\"}],\"max_tokens\":30,\"temperature\":0.0}" '

KV 転送を検証する

長いプロンプトを送信した後、デコーダーログをチェックして KV キャッシュが転送されたことを確認します。

kubectl logs $DECODE_POD -n ${NAMESPACE} -c decode-${DEPLOYMENT_NAME} \ | grep -E "Retrieved.*tokens.*throughput" | tail -2

予想される出力 (TP ランクごとに 1 行):

[Worker_TP5] [LMCache INFO] [req_id=cmpl-...] Retrieved 6035 out of 6035 required tokens (from 6035 total tokens). size: 0.2344 gb, cost 1.3304 ms, throughput: 176.1686 GB/s

Retrieved N out of N required tokens N > 0 の場合、KV キャッシュが NIXL チャネルを正常に通過したことを確認します。が表示された場合Retrieved 0 out of N、デコーダーはローカル再計算にフォールバックします。「」を参照してくださいDisaggregated Prefill and Decode (DPD) デプロイの問題

ルーターログでルーティングの決定を確認することもできます。

kubectl logs $ROUTER_POD -n hyperpod-inference-system -c router-container --tail=20 \ | grep -E "Conditional routing"

長いプロンプトでは、以下が表示されます。

[INFO] Conditional routing: estimated_tokens=6750, threshold=4096, disaggregate=True

短いプロンプトの場合:

[INFO] Conditional routing: estimated_tokens=12, threshold=4096, disaggregate=False
注記

SageMaker AI エンドポイントを介して を呼び出すには、 endpointName で を設定しますInferenceEndpointConfig。が設定されendpointNameていない場合、SageMaker AI エンドポイントは作成されず、直接 ALB 呼び出しのみを使用できます。

オブザーバビリティ

metrics.enabled: true で を設定してメトリクスを有効にしますInferenceEndpointConfig。DPD メトリクスは、HyperPod 推論ダッシュボードで使用できます。詳細については、「HyperPod クラスターでの推論オブザーバビリティの実装」を参照してください。

次の DPD 固有のメトリクスを使用できます。

DPD 固有のメトリクス
メトリクス 説明
E2E TTFT 最初のトークンまでの全体的な時間 (事前入力 + KV 転送 + ルーティング)
事前入力 TTFT プリフィラーのみのレイテンシー
事前入力キュー 事前入力を待っているリクエストの数
デコードキュー デコーダーを待機しているリクエストの数
事前入力時間 事前入力計算に費やされた時間
デコードレイテンシー トークンごとの出力レイテンシー (TPOT)
KV 転送時間 KV キャッシュをプリフィラーからデコーダーに転送する時間
DPD ルーティング数 非集計リクエストとフォールバックリクエスト (しきい値未満)

DPD デプロイを調整する

次の表は、メトリクスダッシュボードで観察した症状に基づいて DPD を調整するためのクイックリファレンスです。

DPD チューニングリファレンス
構成 その内容 デフォルト 調整するタイミング
pdSpec.routingThreshold プリフィラーをルーティングする最小入力トークン。このしきい値を下回るリクエストは、デコーダーに直接送信されます。 4096 デフォルトは、ほとんどのワークロードに適しています。これを低すぎると、短いプロンプトでの不要な KV 転送のために TTFT が増加し、高すぎると、DPD パスを取るリクエストが少なくなるため、TPOT の改善が制限されます。
pdSpec.prefillSpec.replicas 事前入力ポッドの数。 1 プリフィル TTFT を改善するために、プリフィルキューの深さが高い場合はスケールアップします。
PD_BUFFER_SIZE 受信 KV 転送のデコーダー GPU バッファ (ランクあたり)。8 GiB は、TP=8 で 70B の 6K-token転送を約 35 回保持します。 "8589934592" (8 GiB) を増やして、より多くの同時 KV 転送を処理します。メモリの問題が発生した場合は減らします。増加すると、デコーダー--gpu-memory-utilizationの を下げて、より大きなバッファの GPU メモリを解放する必要がある場合があります。
--gpu-memory-utilization vLLM が重み、アクティベーション、KV キャッシュに使用する GPU メモリの割合。 0.75 長い入力で KV キャッシュヘッドルームを増やす。リスク: プリフィルにはアクティベーション用のメモリも必要であるため、プリフィラー OOM。実際の入力長分布でテストします。
--max-num-seqs ワーカーバッチあたりの最大同時シーケンス数。 16 (プリフィラー)、 32 (デコーダー) をレイズすると、ロード時のバッチ処理が向上します。プリフィラーの OOM にヒットした場合は低くします。経由でロールごとに設定しますpdSpec.{prefillSpec,decodingSpec}.args
intelligentRoutingSpec.routingStrategy 複数のレプリカが存在する場合にルーターがプリフィラーを選択する方法。 prefixaware を使用してroundrobin、複数のプリフィラーレプリカに負荷を均等に分散します。キャッシュヒットを最大化するために、 プロンプトが共通のプレフィックス (システムプロンプト、チャット履歴) を共有する場合は、単一のプリフィラーprefixawarekvawareで または を使用します。

実際のワークロードと入力長の分布でテストします。

設定変更を適用するには、デプロイ YAML を編集して再適用します。

kubectl apply -f inference_endpoint_dpd_config.yaml

既知の制限事項

  • DPD は、70B 以上のパラメータを持つ高密度モデルに推奨されます。小規模なモデルと Mixture-of-Experts モデルは、通常、分離の恩恵を受けません。

  • 現在のリリースでは、エンドポイントごとに 1 つのデコードデプロイがサポートされています。複数のデコードデプロイのサポートは、今後のリリースで予定されています。

  • パフォーマンスは、Llama 3.3 70B で ml.p5.48xlarge に対して最大 64 件の同時リクエストが検証されます。

  • DPD デプロイから標準のコロケーションデプロイに戻すには、 InferenceEndpointConfigなしで新しい を適用しますpdSpec

DPD デプロイのトラブルシューティングについては、「」を参照してくださいDisaggregated Prefill and Decode (DPD) デプロイの問題