View a markdown version of this page

Precompilazione e decodifica disaggregate per l'inferenza HyperPod - Amazon SageMaker AI

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Precompilazione e decodifica disaggregate per l'inferenza HyperPod

Disaggregated Prefill and Decode (DPD) separa le due fasi dell'inferenza LLM, precompilazione e decodifica, su pool GPU dedicati e trasferisce la cache chiave-valore (KV) tra di esse tramite Elastic Fabric Adapter (EFA) utilizzando GPU-Direct Remote Direct Memory Access (RDMA).

Quando la precompilazione e la decodifica vengono eseguite sulla stessa GPU (in colocation), una singola richiesta di contesto lungo può bloccare i flussi di token in corso per altri client, aumentando la latenza per token sotto carico. DPD elimina questa interferenza eseguendo il prefill associato al calcolo su un set di GPU e la decodifica associata alla larghezza di banda della memoria su un altro, producendo una latenza più prevedibile in caso di traffico misto e consentendo di scalare ogni fase in modo indipendente.

L'operatore di inferenza gestisce l'orchestrazione, che include il provisioning del router, il cablaggio dei pod di precompilazione e decodifica tramite LMCache e NIXL e l'integrazione con l'osservabilità. HyperPod Puoi abilitare DPD aggiungendo una sezione alla stessa risorsa che già utilizzi per gli endpoint di inferenza. pdSpec InferenceEndpointConfig

Quando DPD aiuta

DPD offre i maggiori vantaggi quando sono presenti tutte le seguenti condizioni:

  • Modelli ad alta densità: parametri 70B+ (ad esempio, Llama 3.3 70B).

  • Input lunghi: oltre 4.000 token di input. Inter-token il miglioramento della latenza (ITL) varia in base alla lunghezza dell'input, poiché precompilazioni più lunghe causano maggiori interferenze di decodifica quando vengono collocate.

  • Concorrenza sostenuta: più di 2 richieste al secondo. Senza richieste simultanee in competizione per la stessa GPU, non c'è nulla da disaggregare.

  • Uscite moderate o lunghe: oltre 256 token di uscita. Un numero maggiore di token di output significa un maggiore vantaggio cumulativo derivante da una latenza stabile per token.

Se il carico di lavoro prevede input brevi, bassa concorrenza o utilizza modelli di piccole dimensioni, una distribuzione standard in colocation è più semplice e offre buone prestazioni.

Prerequisiti

Prima di implementare endpoint di inferenza che utilizzano Disaggregated Prefill and Decode, è necessario configurare i seguenti componenti nell'ambiente di sviluppo locale:

  • AWS Interfaccia AWS a riga di comando (CLI)

  • Accesso al tuo cluster HyperPod Amazon EKS tramite kubectl

  • https://huggingface.co/Token Hugging Face che consente l'accesso in lettura al rispettivo checkpoint del modello. Questo non è necessario se il checkpoint del modello si trova già in un bucket Amazon S3.

  • Un'immagine di lavoro che include vLLM, LMCache, NVIDIA NIXL e il provider EFA libfabric. Sono supportate le seguenti opzioni di immagine:

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

    • Cache LM: lmcache/vllm-openai:v0.4.3

    Entrambe le immagini includono LMCache 0.4.3, vLLM 0.19.0 e NIXL 1.0.0.

  • HyperPod Inference Operator versione 3.2 o successiva installata. DPD non è supportato nelle versioni precedenti. L'operatore è installato di default nei cluster HyperPod Amazon EKS appena creati. Se intendi utilizzare un cluster esistente, segui le istruzioni di installazione inConfigurazione dei HyperPod cluster per la distribuzione dei modelli. Verifica la tua versione:

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

Disaggregated Prefill and Decode richiede EFA-capable istanze con supporto RDMA. GPU-Direct Sono supportati i seguenti tipi di istanza:,,,,. ml.p5.48xlarge ml.p5e.48xlarge ml.p5en.48xlarge ml.p6-b200.48xlarge ml.p6-b300.48xlarge Altri tipi di istanza non sono supportati per DPD.

Implementa un endpoint DPD

La maggior parte dei InferenceEndpointConfig campi è condivisa con endpoint non DPD e documentata in. Implementazione di modelli di fondazione e di modelli ottimizzati con fine-tuning personalizzati Per abilitare DPD, aggiungi le seguenti sezioni al tuo manifesto.

Prefill-Decode Specifiche: PDSpec

Dichiara la topologia e specifica gli prefill/decode argomenti. La presenza di questo campo è ciò che rende l'endpoint disaggregato: l'operatore crea implementazioni separate per il preriempimento e la decodifica e le collega tra loro tramite il router e il backend 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

Scala, precompilazione e decodifica in modo indipendente.

resources

Applicato alle specifiche del pod del ruolo. Top-levelworker.resourcesviene ignorato per i pod DPD; i valori per ruolo hanno la precedenza.

routingThreshold

Soglia di lunghezza del token che indirizza le richieste al percorso disaggregato. Le richieste che non soddisfano questa soglia bypassano il precompilatore e vanno direttamente al decodificatore.

args

Flag vLLM specifici per quel ruolo. Unito worker.args all'avvio: i flag già presenti worker.args vengono sostituiti con il valore per ruolo; i flag non presenti vengono aggiunti.

Variabili di ambiente DPD: variabili di ambiente

Queste variabili di ambiente vengono applicate in modo identico sia ai contenitori di precompilazione che di decodifica; non esiste un campo env-var per ruolo. Per il comportamento in base al ruolo, usa invece. 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)

Buffer GPU riservato sul decoder per i trasferimenti di cache KV in entrata, dimensionato per rango. Per Llama 70B con TP=8, la cache KV di ogni token è di circa 40 KB per rank, quindi un prompt da 6000 token occupa circa 0,23 GB per rank e 8 GiB contengono circa 35 trasferimenti in volo di questo tipo. Quando il buffer supera la capacità, i log del decodificatore e i client registrano picchi di latenza. Failed to allocate memory object, retrying... Aumentate fino a 16/32 GiB o scalate se necessario. decodingSpec.replicas

LMCACHE_SAVE_DECODE_CACHE: "False"

Disattiva la memorizzazione nella cache L1 ridondante sul decoder. Il prefiller è la fonte di verità per gli accessi alla cache.

PYTHONHASHSEED: "0"

LMCache utilizza l'integrazione di Python per calcolare le chiavi di cache hash() prompt-token. Per impostazione predefinita, Python randomizza quel seme di hash per processo, quindi prompt identici producono chiavi diverse in fase di precompilazione e decodifica e le ricerche non vanno a buon fine. Appuntando il seme, le chiavi convergono tra i pod.

Configura la strategia di routing

La intelligentRoutingSpec sezione imposta la strategia di routing utilizzata dal router DPD per selezionare un prefiller per ogni richiesta. Il router viene creato automaticamente quando è presente; questa sezione pdSpec è opzionale e per impostazione predefinita è. prefixaware

intelligentRoutingSpec: enabled: true routingStrategy: prefixaware

DPD può anche essere integrato con il routing intelligente e il caching KV. Per ulteriori informazioni, consulta Configura il caching KV e il routing intelligente.

Con una singola replica precompilata, tutte le strategie vengono indirizzate a quella replica. La scelta influisce sul comportamento solo quandoprefillSpec.replicas > 1:

  • Per una singola replica di precompilazione, utilizza prefixaware (impostazione predefinita) per massimizzare gli accessi alla cache KV quando i prompt condividono prefissi comuni come i prompt di sistema o la cronologia chat.

  • Per più repliche di precompilazione, usalo per distribuire il carico in modo uniforme tra le repliche ed evitare roundrobin di individuare un singolo precompilatore.

Esempio completo

Il seguente manifest implementa Llama 3.3 70B su due istanze ml.p5.48xlarge (un prefiller, un decoder):

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"

Applica il manifesto:

kubectl apply -f inference_endpoint_dpd_config.yaml

Verifica della distribuzione

L'estrazione dell'immagine e il caricamento del modello richiedono diversi minuti. Monitora lo stato del pod:

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

Una distribuzione corretta mostra:

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

Ogni pod modello ha 3 contenitori (vLLM worker, reverse proxy Nginx, collector). OpenTelemetry Il router pod ha 2 contenitori (router, collector). OpenTelemetry Controlla lo InferenceEndpointConfig stato:

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

Risultato previsto: DPD prefill and decode deployments are ready

Verifica i ruoli DPD

Conferma i report di precompilazione sender e i report del decodificatore. receiver Questo è il segnale di avvio più discriminante: se entrambi i pod segnalano lo stesso ruolo o nessuno dei due stampa la linea, l'operatore non ha collegato correttamente il 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

Output previsto:

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

Richiamare l'endpoint

Una volta che l'endpoint è pronto, inviate un prompt breve e uno lungo per eseguire entrambi i percorsi di routing, quindi controllate i log per confermare il trasferimento di KV tramite EFA.

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

Richiesta breve (al di sotto della soglia, diretta al decoder)

Le richieste con un numero inferiore di token routingThreshold bypassano il precompilatore e vanno direttamente al decodificatore:

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 }'

Richiesta lunga (supera la soglia, percorso DPD)

Le richieste che superano la soglia vengono indirizzate al precompilatore per il calcolo della cache KV, quindi al decoder per la generazione dei token:

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}" '

Verifica il trasferimento KV

Dopo aver inviato un lungo prompt, conferma che la cache KV è stata trasferita controllando i log del decodificatore:

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

Risultato previsto (una riga per rango 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 tokenscon N > 0 conferma che la cache KV ha attraversato con successo il canale NIXL. Se vediRetrieved 0 out of N, il decoder è tornato al ricalcolo locale, vedi. Problemi di distribuzione di Disaggregated Prefill and Decode (DPD)

Puoi anche verificare la decisione di routing nei log del router:

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

Per il prompt lungo, dovresti vedere:

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

Per il prompt breve:

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

Per richiamarlo tramite un endpoint SageMaker AI AI, imposta endpointName il tuo. InferenceEndpointConfig Se non endpointName è impostato, non viene creato alcun endpoint SageMaker AI AI ed è disponibile solo l'invocazione diretta ALB.

Osservabilità

Abilita le metriche impostando il tuo. metrics.enabled: true InferenceEndpointConfig Le metriche DPD sono disponibili nella dashboard di inferenza. HyperPod Per ulteriori informazioni, consulta Implementazione dell'osservabilità dell'inferenza sui cluster HyperPod.

Sono disponibili le seguenti DPD-specific metriche:

DPD-specific metriche
Metrica Description
E2E TTFT Tempo complessivo per il primo token (precompilazione + trasferimento KV + routing)
Precompilazione TTFT Prefiller-only latenza
Coda di precompilazione Numero di richieste in attesa di precompilazione
Coda di decodifica Numero di richieste in attesa sul decoder
Tempo di precompilazione Tempo impiegato per il calcolo del preriempimento
Latenza di decodifica Per-token latenza di uscita (TPOT)
Tempo di trasferimento KV È ora di trasferire la cache KV dal precompilatore al decoder
Il routing DPD conta Richieste disaggregate e richieste fallback (inferiori alla soglia)

Ottimizza la tua implementazione DPD

La tabella seguente fornisce un riferimento rapido per l'ottimizzazione del DPD in base ai sintomi osservati nella dashboard delle metriche.

Riferimento per l'ottimizzazione di DPD
Config Cosa fa Predefinita Quando sintonizzarsi
pdSpec.routingThreshold Token di input minimi da indirizzare attraverso il precompilatore. Le richieste al di sotto di questa soglia vanno direttamente al decoder. 4096 L'impostazione predefinita funziona bene per la maggior parte dei carichi di lavoro. Impostandolo su un valore troppo basso si aumenta il TTFT a causa dei trasferimenti KV non necessari su prompt brevi, mentre impostandolo su un valore troppo alto si limita il miglioramento del TPOT poiché un numero inferiore di richieste segue il percorso DPD.
pdSpec.prefillSpec.replicas Numero di pod di precompilazione. 1 Aumenta se la profondità della coda di precompilazione è elevata per migliorare il TTFT di precompilazione.
PD_BUFFER_SIZE Buffer GPU di decodifica per i trasferimenti KV in entrata (per rango). 8 GiB contiene circa 35 trasferimenti in volo (6) per 70 B a TP=8. K-token "8589934592"(8 GiB) Aumento per gestire più trasferimenti KV simultanei. Diminuisci se riscontri problemi di memoria. Quando si aumenta, potrebbe essere necessario abbassare --gpu-memory-utilization il valore del decoder per liberare memoria della GPU per il buffer più grande.
--gpu-memory-utilization Frazione della memoria GPU utilizzata da vLLM per pesi, attivazioni e cache KV. 0.75 Aumento per aumentare lo spazio di cache in KV su ingressi lunghi. Rischio: precompilatore OOM perché il preriempimento richiede anche memoria per le attivazioni. Effettua il test con la distribuzione effettiva della lunghezza di input.
--max-num-seqs Numero massimo di sequenze simultanee per batch di lavoratori. 16(precompilatore), (decodificatore) 32 Aumentate per un migliore dosaggio sotto carico. Abbassalo premendo OOM sul prefiller. Impostato per ruolo tramite. pdSpec.{prefillSpec,decodingSpec}.args
intelligentRoutingSpec.routingStrategy Come il router seleziona un prefiller quando esistono più repliche. prefixaware roundrobinDa utilizzare per distribuire uniformemente il carico su più repliche precompilate. Usa prefixaware o kvaware con un singolo precompilatore o quando i prompt condividono prefissi comuni (prompt di sistema, cronologia chat) per massimizzare gli accessi alla cache.

Esegui il test in base al carico di lavoro effettivo e alla distribuzione della lunghezza di input.

Per applicare le modifiche alla configurazione, modifica lo YAML di distribuzione e riapplica:

kubectl apply -f inference_endpoint_dpd_config.yaml

Limiti noti

  • DPD è consigliato per modelli ad alta densità con 70B o più parametri. I modelli e Mixture-of-Experts i modelli più piccoli in genere non traggono vantaggio dalla disaggregazione.

  • La versione corrente supporta una singola implementazione di decodifica per endpoint. Il supporto per più implementazioni di decodifica è previsto per una versione futura.

  • Le prestazioni sono convalidate fino a 64 richieste simultanee su ml.p5.48xlarge con Llama 3.3 70B.

  • Per tornare da una distribuzione DPD a una distribuzione standard in colocation, applica una nuova distribuzione senza. InferenceEndpointConfig pdSpec

Per la risoluzione dei problemi relativi alle implementazioni DPD, vedere. Problemi di distribuzione di Disaggregated Prefill and Decode (DPD)