

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

# HyperPod 推論の集約解除された事前入力とデコード
<a name="sagemaker-hyperpod-model-deployment-dpd"></a>

非集約事前入力とデコード (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 が役立つ場合
<a name="sagemaker-hyperpod-model-deployment-dpd-when"></a>

DPD は、以下の条件がすべて存在する場合に最大の利点を提供します。
+ **高密度モデル** — 70B 以上のパラメータ (Llama 3.3 70B など）。
+ **長い入力** — 4,000 個以上の入力トークン。トークン間レイテンシー (ITL) の改善は、入力の長さに合わせてスケールされます。これは、事前入力が長くなると、コロケーション時にデコードの干渉が増えるためです。
+ **持続的な同時実行 —** 1 秒あたり 2 件以上のリクエスト。同じ GPU に対して競合する同時リクエストがないと、分解するものはありません。
+ **中程度または長い出力** — 256 個以上の出力トークン。出力トークンが多いほど、トークンごとのレイテンシーが安定することによる累積的な利点が増えます。

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

## 前提条件
<a name="sagemaker-hyperpod-model-deployment-dpd-prereqs"></a>

Disaggregated Prefill and Decode を使用する推論エンドポイントをデプロイする前に、ローカル開発環境で以下のコンポーネントを設定する必要があります。
+ [AWS コマンドラインインターフェイス (AWS CLI)](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html)
+ [kubectl](https://kubernetes.io/docs/tasks/tools/) を介した HyperPod Amazon EKS クラスターへのアクセス
+ それぞれのモデルチェックポイントへの読み取りアクセスを許可する [Hugging Face](https://huggingface.co/) トークン。これは、モデルチェックポイントが既に 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 クラスターの設定](sagemaker-hyperpod-model-deployment-setup.md)。バージョンを確認します。

  ```
  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.48xlarge`、`ml.p5e.48xlarge`、`ml.p5en.48xlarge`、`ml.p6-b200.48xlarge`、`ml.p6-b300.48xlarge`。他のインスタンスタイプは DPD ではサポートされていません。

## DPD エンドポイントをデプロイする
<a name="sagemaker-hyperpod-model-deployment-dpd-deploy"></a>

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

### 事前入力/デコード仕様: `pdSpec`
<a name="sagemaker-hyperpod-model-deployment-dpd-fields-pdspec"></a>

事前入力/デコードトポロジを宣言し、引数を指定します。このフィールドが存在すると、エンドポイントが分離されます。オペレータは、事前入力とデコード用に個別のデプロイを作成し、ルーターと 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`
<a name="sagemaker-hyperpod-model-deployment-dpd-fields-env"></a>

これらの環境変数は、プリフィラーコンテナとデコーダーコンテナの両方に同じように適用されます。ロールごとの 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 はデフォルトでプロセスごとにハッシュシードをランダム化するため、同一のプロンプトはプリフィラー、デコーダー、ルックアップミスに対して異なるキーを生成します。シードをピン留めすると、キーはポッド間で一致します。

### ルーティング戦略を設定する
<a name="sagemaker-hyperpod-model-deployment-dpd-fields-routing"></a>

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

```
intelligentRoutingSpec:
  enabled: true
  routingStrategy: prefixaware
```

DPD は、インテリジェントなルーティングと KV キャッシュと統合することもできます。詳細については、「[KV キャッシュとインテリジェントルーティングを設定する](sagemaker-hyperpod-model-deployment-caching-routing.md#sagemaker-hyperpod-model-deployment-deploy-ftm-cache-route)」を参照してください。

1 つのプリフィルレプリカでは、すべての戦略がそのレプリカにルーティングされます。この選択は、 の場合にのみ動作に影響します`prefillSpec.replicas > 1`。
+ 1 つのプリフィルレプリカの場合、 `prefixaware` (デフォルト) を使用して、プロンプトがシステムプロンプトやチャット履歴などの一般的なプレフィックスを共有するときに KV キャッシュヒットを最大化します。
+ 複数のプリフィルレプリカの場合、 を使用してレプリカ全体に負荷`roundrobin`を均等に分散し、1 つのプリフィラーをホットスポッティングしないようにします。

### 完全な例
<a name="sagemaker-hyperpod-model-deployment-dpd-deploy-example"></a>

次のマニフェストは、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
```

## デプロイメントを確認する
<a name="sagemaker-hyperpod-model-deployment-dpd-verify"></a>

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

```
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 ロールを検証する
<a name="sagemaker-hyperpod-model-deployment-dpd-verify-roles"></a>

プリフィラーレポート`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'
```

## エンドポイントの呼び出し
<a name="sagemaker-hyperpod-model-deployment-dpd-invoke"></a>

エンドポイントの準備ができたら、短いプロンプトと長いプロンプトを送信して両方のルーティングパスを実行し、ログをチェックして 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
```

### 短いプロンプト (しきい値未満、デコーダーに直接送信)
<a name="sagemaker-hyperpod-model-deployment-dpd-invoke-short"></a>

プリフィラーを`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 パスを超過)
<a name="sagemaker-hyperpod-model-deployment-dpd-invoke-long"></a>

しきい値を超えるリクエストは、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 転送を検証する
<a name="sagemaker-hyperpod-model-deployment-dpd-invoke-verify-kv"></a>

長いプロンプトを送信した後、デコーダーログをチェックして 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) デプロイの問題](sagemaker-hyperpod-model-deployment-ts-dpd.md)。

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

```
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 呼び出しのみを使用できます。

## オブザーバビリティ
<a name="sagemaker-hyperpod-model-deployment-dpd-observability"></a>

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

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


**DPD 固有のメトリクス**  

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

## DPD デプロイを調整する
<a name="sagemaker-hyperpod-model-deployment-dpd-tuning"></a>

次の表は、メトリクスダッシュボードで観察した症状に基づいて 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
```

## 既知の制限事項
<a name="sagemaker-hyperpod-model-deployment-dpd-limitations"></a>
+ DPD は、70B 以上のパラメータを持つ高密度モデルに推奨されます。小規模なモデルと Mixture-of-Experts モデルは、通常、分離の恩恵を受けません。
+ 現在のリリースでは、エンドポイントごとに 1 つのデコードデプロイがサポートされています。複数のデコードデプロイのサポートは、今後のリリースで予定されています。
+ パフォーマンスは、Llama 3.3 70B で ml.p5.48xlarge に対して最大 64 件の同時リクエストが検証されます。
+ DPD デプロイから標準のコロケーションデプロイに戻すには、 `InferenceEndpointConfig`なしで新しい を適用します`pdSpec`。

DPD デプロイのトラブルシューティングについては、「」を参照してください[Disaggregated Prefill and Decode (DPD) デプロイの問題](sagemaker-hyperpod-model-deployment-ts-dpd.md)。