

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# HyperPod 推論的分解預填充和解碼
<a name="sagemaker-hyperpod-model-deployment-dpd"></a>

分解的預先填充和解碼 (DPD) 會將 LLM 推論的兩個階段預先填充和解碼分成專用 GPU 集區，並使用 GPU 直接遠端記憶體存取 (RDMA)，在它們之間透過 Elastic Fabric Adapter (EFA) 傳輸金鑰值 (KV) 快取。

在相同 GPU （共置） 上執行預填充和解碼時，單一長內容請求可能會停止其他用戶端的傳輸中權杖串流，在負載下增加每個權杖的延遲。DPD 會在一組 GPUs 上執行運算限制預先填入，並在另一組 GPU 上執行memory-bandwidth-bound解碼，在混合流量下產生更可預測的延遲，並讓您獨立擴展每個階段，藉此消除此干擾。

推論運算子會處理協同運作，包括佈建路由器、透過 LMCache 和 NIXL 將 Pod 預先填充和解碼，以及與 HyperPod 可觀測性整合。您可以將`pdSpec`區段新增至已用於推論端點的相同`InferenceEndpointConfig`資源，以啟用 DPD。

## 當 DPD 協助
<a name="sagemaker-hyperpod-model-deployment-dpd-when"></a>

當下列所有條件都存在時，DPD 可提供最大效益：
+ **大型密集模型** — 70B\+ 參數 （例如 Llama 3.3 70B)。
+ **長輸入** — 4，000\+ 個輸入字符。輪換間延遲 (ITL) 改善會隨著輸入長度而擴展，因為在共置時，預先填充時間較長會導致更多解碼干擾。
+ **持續並行** — 每秒 2 個以上的請求。如果沒有在相同 GPU 中競爭的並行請求，則無需分離。
+ **中等或長輸出** — 256\+ 個輸出字符。更多輸出字符表示每個字符的穩定延遲能獲得更多累積效益。

如果您的工作負載具有短輸入、低並行或使用小型模型，則標準共置部署會更簡單且效能良好。

## 先決條件
<a name="sagemaker-hyperpod-model-deployment-dpd-prereqs"></a>

在部署使用分解預先填充和解碼的推論端點之前，您需要在本機開發環境中設定下列元件：
+ [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"}'
  ```

**重要**  
分解的預先填充和解碼需要具備 EFA 功能的執行個體，並支援 GPU-Direct RDMA。支援下列執行個體類型：`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，請將下列區段新增至資訊清單。

### Prefill-Decode 規格： `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`  
套用至角色的 Pod 規格。DPD Pod `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，因此每個排名大約 0.23 GB 的 6000 個字符提示，而 8 GiB 可容納大約 35 個此類傳輸中。當緩衝區超過容量時，解碼器日誌`Failed to allocate memory object, retrying...`和用戶端會看到延遲峰值。`decodingSpec.replicas` 視需要增加至 16/32 GiB 或擴展。

`LMCACHE_SAVE_DECODE_CACHE`: `"False"`  
停用解碼器上的備援 L1 快取。預填充物是快取命中事件的事實來源。

`PYTHONHASHSEED`: `"0"`  
LMCache 使用 Python 的內建 `hash()`來計算提示詞快取金鑰。根據預設，Python 會隨機化每個程序的雜湊種子，因此相同的提示會在預填充和解碼器和查詢遺漏時產生不同的金鑰。固定種子可讓金鑰跨 Pod 一致。

### 設定路由策略
<a name="sagemaker-hyperpod-model-deployment-dpd-fields-routing"></a>

`intelligentRoutingSpec` 區段會設定 DPD 路由器用來為每個請求選取預先填入程式的路由策略。路由器`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)。

使用單一預填充複本時，所有策略都會路由到該複本。選擇只會影響下列行為`prefillSpec.replicas > 1`：
+ 對於單一預先填入複本，當提示共用常見字首時，請使用 `prefixaware`（預設值） 將 KV 快取命中最大化，例如系統提示或聊天歷史記錄。
+ 對於多個預填充複本，請使用 `roundrobin`將負載平均分配到複本，並避免熱灌入單一預填充器。

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

下列資訊清單會在兩個 ml.p5.48xlarge 執行個體 （一個預填充物、一個解碼器） 上部署 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>

影像提取和模型載入需要幾分鐘的時間。監控 Pod 狀態：

```
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
```

每個模型 Pod 都有 3 個容器 (vLLM 工作者、Nginx 反向代理、OpenTelemetry 收集器）。路由器 Pod 有 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`。這是區分程度最高的啟動訊號 - 如果兩個 Pod 都報告相同的角色，或兩者都不列印該行，則運算子未正確連接 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 排名一行）：

```
[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`，解碼器會下降回本機重新計算 — 請參閱 [分解預填充和解碼 (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 調校參考**  

| Config | 它的功能 | 預設 | 何時調整 | 
| --- | --- | --- | --- | 
| pdSpec.routingThreshold | 要透過預填充物路由的最小輸入字符。低於此閾值的請求會直接傳送至解碼器。 | 4096 | 預設值適用於大多數工作負載。由於在短提示上不必要的 KV 傳輸，設定過低會增加 TTFT，同時設定過高限制 TPOT 改善，因為較少的請求會採用 DPD 路徑。 | 
| pdSpec.prefillSpec.replicas | 預填充 Pod 的數量。 | 1 | 如果預填充佇列深度很高，請向上擴展，以改善預填充 TTFT。 | 
| PD\_BUFFER\_SIZE | 用於傳入 KV 傳輸的解碼器 GPU 緩衝區 （每個排名）。8 GiB 會在 TP=8 時為 70B 保留大約 35 個傳輸中的 6K-token傳輸。 | "8589934592" (8 GiB) | 增加 以處理更多並行 KV 傳輸。如果您看到記憶體問題，請減少 。增加時，您可能需要降低解碼器--gpu-memory-utilization上的 ，才能為較大的緩衝區釋放 GPU 記憶體。 | 
| --gpu-memory-utilization | 用於權重、啟用和 KV 快取的 GPU 記憶體 vLLM 分數。 | 0.75 | 在長輸入上增加更多 KV 快取標頭空間。風險：預先填入 OOM，因為預先填入也需要記憶體才能啟用。使用實際輸入長度分佈進行測試。 | 
| --max-num-seqs | 每個工作者批次的最大並行序列數。 | 16 （預填充物）、 32（解碼器） | 提高 以在負載下進行更好的批次處理。如果達到預填充物上的 OOM，則降低。透過 設定每個角色pdSpec.{prefillSpec,decodingSpec}.args。 | 
| intelligentRoutingSpec.routingStrategy | 當有多個複本存在時，路由器如何選取預填器。 | prefixaware | 使用 roundrobin 將負載平均分配到多個預填充複本。使用 prefixaware或 kvaware搭配單一預填器，或在提示共用常見字首 （系統提示、聊天歷史記錄） 時，將快取命中最大化。 | 

使用實際工作負載和輸入長度分佈進行測試。

若要套用組態變更，請編輯您的部署 YAML 並重新套用：

```
kubectl apply -f inference_endpoint_dpd_config.yaml
```

## 已知限制
<a name="sagemaker-hyperpod-model-deployment-dpd-limitations"></a>
+ 對於具有 70B 或更多參數的密集型模型，建議使用 DPD。較小的模型和 Mixture-of-Experts 模型通常不會受益於分解。
+ 目前版本支援每個端點的單一解碼部署。未來版本預計支援多個解碼部署。
+ 效能在 ml.p5.48xlarge 與 Llama 3.3 70B 上驗證最多 64 個並行請求。
+ 若要從 DPD 部署還原至標準共置部署，請套用`InferenceEndpointConfig`不含 的新 `pdSpec`。

如需 DPD 部署的故障診斷，請參閱 [分解預填充和解碼 (DPD) 部署問題](sagemaker-hyperpod-model-deployment-ts-dpd.md)。