View a markdown version of this page

HyperPod 推論的分解預填充和解碼 - Amazon SageMaker AI

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

HyperPod 推論的分解預填充和解碼

分解的預先填充和解碼 (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 協助

當下列所有條件都存在時,DPD 可提供最大效益:

  • 大型密集模型 — 70B+ 參數 (例如 Llama 3.3 70B)。

  • 長輸入 — 4,000+ 個輸入字符。輪換間延遲 (ITL) 改善會隨著輸入長度而擴展,因為在共置時,預先填充時間較長會導致更多解碼干擾。

  • 持續並行 — 每秒 2 個以上的請求。如果沒有在相同 GPU 中競爭的並行請求,則無需分離。

  • 中等或長輸出 — 256+ 個輸出字符。更多輸出字符表示每個字符的穩定延遲能獲得更多累積效益。

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

先決條件

在部署使用分解預先填充和解碼的推論端點之前,您需要在本機開發環境中設定下列元件:

  • 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"}'
重要

分解的預先填充和解碼需要具備 EFA 功能的執行個體,並支援 GPU-Direct RDMA。支援下列執行個體類型:ml.p5.48xlargeml.p5e.48xlargeml.p5en.48xlargeml.p6-b200.48xlargeml.p6-b300.48xlarge。DPD 不支援其他執行個體類型。

部署 DPD 端點

大多數InferenceEndpointConfig欄位會與非 DPD 端點共用,並記錄在 中部署基礎模型和自訂微調模型。若要啟用 DPD,請將下列區段新增至資訊清單。

Prefill-Decode 規格: 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

套用至角色的 Pod 規格。DPD Pod 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,因此每個排名大約 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 一致。

設定路由策略

intelligentRoutingSpec 區段會設定 DPD 路由器用來為每個請求選取預先填入程式的路由策略。路由器pdSpec會在存在時自動建立;本節是選用的,預設為 prefixaware

intelligentRoutingSpec: enabled: true routingStrategy: prefixaware

DPD 也可以與智慧型路由和 KV 快取整合。如需詳細資訊,請參閱設定 KV 快取和智慧型路由

使用單一預填充複本時,所有策略都會路由到該複本。選擇只會影響下列行為prefillSpec.replicas > 1

  • 對於單一預先填入複本,當提示共用常見字首時,請使用 prefixaware(預設值) 將 KV 快取命中最大化,例如系統提示或聊天歷史記錄。

  • 對於多個預填充複本,請使用 roundrobin將負載平均分配到複本,並避免熱灌入單一預填充器。

完成範例

下列資訊清單會在兩個 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

驗證部署

影像提取和模型載入需要幾分鐘的時間。監控 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 角色

確認預填充物報告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'

調用端點

端點就緒後,傳送一小段和長段提示來練習兩個路由路徑,然後檢查日誌以確認透過 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 排名一行):

[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) 部署問題

您也可以在路由器日誌中驗證路由決策:

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 調校參考
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 將負載平均分配到多個預填充複本。使用 prefixawarekvaware搭配單一預填器,或在提示共用常見字首 (系統提示、聊天歷史記錄) 時,將快取命中最大化。

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

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

kubectl apply -f inference_endpoint_dpd_config.yaml

已知限制

  • 對於具有 70B 或更多參數的密集型模型,建議使用 DPD。較小的模型和 Mixture-of-Experts 模型通常不會受益於分解。

  • 目前版本支援每個端點的單一解碼部署。未來版本預計支援多個解碼部署。

  • 效能在 ml.p5.48xlarge 與 Llama 3.3 70B 上驗證最多 64 個並行請求。

  • 若要從 DPD 部署還原至標準共置部署,請套用InferenceEndpointConfig不含 的新 pdSpec

如需 DPD 部署的故障診斷,請參閱 分解預填充和解碼 (DPD) 部署問題