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 di inferenza LLM, prefill e decodifica, su pool di GPU dedicati e trasferisce la cache chiave-valore (KV) tra di loro tramite Elastic Fabric Adapter (EFA) utilizzando Remote Direct Memory Access (RDMA). GPU-Direct

Quando la precompilazione e la decodifica vengono eseguite sulla stessa GPU (in co-location), una singola richiesta a lungo contesto può bloccare i flussi di token in corso per altri client, aumentando la latenza per token sotto carico. DPD rimuove questa interferenza eseguendo la precompilazione associata al calcolo su un set di GPU e la decodifica limitata alla larghezza di banda di 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 il massimo vantaggio quando sono presenti tutte le seguenti condizioni:

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

  • Ingressi lunghi: oltre 4.000 token di input. Inter-token Il miglioramento della latenza (ITL) varia in base alla lunghezza dell'input, poiché i preriempimenti più lunghi causano maggiori interferenze di decodifica quando vengono collocati in modo codificato.

  • 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 output. Più token di output significano maggiori vantaggi cumulativi derivanti da una latenza stabile per token.

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

Prerequisiti

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

  • AWS Interfaccia a riga di comando (AWS CLI)

  • Accesso al tuo cluster HyperPod Amazon EKS tramite kubectl

  • 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 È installata la versione 3.2 o successiva di Inference Operator. DPD non è supportato nelle versioni precedenti. L'operatore viene installato per impostazione predefinita nei cluster HyperPod Amazon EKS appena creati. Se intendi utilizzare un cluster esistente, segui le istruzioni di installazione riportate inConfigurazione dei HyperPod cluster per l'implementazione 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

La precompilazione e la decodifica disaggregate richiedono 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.

Implementate 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, aggiungete le seguenti sezioni al 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 la precompilazione 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

Scalabilità, 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 verso il percorso disaggregato. Le richieste che non soddisfano questa soglia ignorano il prefiller e vanno direttamente al decoder.

args

Bandiere VLM specifiche per quel ruolo. Uniti 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 d'ambiente

Queste variabili di ambiente vengono applicate in modo identico sia al contenitore del prefiller che al contenitore del decoder; non esiste un campo env-var per ruolo. Per pdSpec.{prefillSpec,decodingSpec}.args un comportamento per ruolo, usa invece.

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 al decoder per i trasferimenti di cache KV in entrata, dimensionato per rank. Per Llama 70B a 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 contiene circa 35 trasferimenti in volo di questo tipo. Quando il buffer supera la capacità, il decoder si registra e i client registrano picchi di latenza. Failed to allocate memory object, retrying... Aumenta a 16/32 GiB o scala decodingSpec.replicas se necessario.

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 la funzionalità integrata di Python per calcolare le chiavi della cache hash() prompt-token. Python randomizza l'hash seed per processo per impostazione predefinita, quindi prompt identici producono chiavi diverse su prefiller e decoder e le ricerche non vengono eseguite. Se si fissa il seme, le chiavi si accordano tra i baccelli.

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 è facoltativa e l'impostazione predefinita è. prefixaware

intelligentRoutingSpec: enabled: true routingStrategy: prefixaware

DPD può anche essere integrato con il routing intelligente e la memorizzazione nella cache KV. Per ulteriori informazioni, consulta Configura la memorizzazione nella cache KV e il routing intelligente.

Con un'unica replica di precompilazione, tutte le strategie vengono indirizzate verso quella replica. La scelta influisce sul comportamento solo quando: prefillSpec.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, utilizzatela per distribuire il carico in modo uniforme tra le repliche ed evitare l'individuazione di un singolo roundrobin prefiller.

Esempio completo

Il seguente manifesto distribuisce 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 alcuni minuti. Monitora lo stato del pod:

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

Una corretta implementazione dimostra:

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, Nginx reverse proxy, collector). OpenTelemetry Il pod del router ha 2 contenitori (router, collector). OpenTelemetry Controlla lo InferenceEndpointConfig stato:

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

Output previsto: DPD prefill and decode deployments are ready

Verifica i ruoli DPD

Conferma i rapporti del precompilatore sender e dei decodificatori. receiver Questo è il segnale di avvio più importante: se entrambi i pod riportano lo stesso ruolo o nessuno dei due riporta la linea, l'operatore non ha cablato DPD correttamente.

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, invia un prompt breve e uno lungo per eseguire entrambi i percorsi di routing, quindi controlla i log per confermare il trasferimento 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 (sotto la soglia, diretta al decoder)

Le richieste con un numero di token inferiore a quello di routingThreshold bypassano il prefiller e vanno direttamente al decoder:

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 inoltrate attraverso il prefiller per il calcolo della cache KV, quindi verso il decoder per la generazione di 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 una richiesta lunga, conferma che la cache KV è stata trasferita controllando i registri del decoder:

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

Output previsto (una riga per grado 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 correttamente il canale NIXL. Se vediRetrieved 0 out of N, il decoder è tornato alla ricalcolo locale: vedi. Problemi di implementazione 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 richiamare tramite un endpoint SageMaker AI, imposta endpointName il tuo. InferenceEndpointConfig Se non endpointName è impostato, non viene creato alcun endpoint SageMaker AI AI ed è disponibile solo la chiamata ALB diretta.

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à inferenziale sui cluster HyperPod.

Sono disponibili le seguenti DPD-specific metriche:

DPD-specific metriche
Metrica Description
E2E TTFT Tempo complessivo necessario alla creazione del primo token (precompilazione, trasferimento KV, routing)
Precompila 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 della precompilazione
Latenza di decodifica Per-token latenza di uscita (TPOT)
Tempo di trasferimento KV È ora di trasferire la cache KV dal prefiller al decoder
Il routing DPD conta Richieste disaggregate e richieste di fallback (al di sotto della soglia)

Ottimizzate la distribuzione di DPD

La tabella seguente fornisce un riferimento rapido per ottimizzare DPD in base ai sintomi osservati nella dashboard delle metriche.

Riferimento per l'ottimizzazione DPD
Config Cosa fa Predefinita Quando sintonizzarsi
pdSpec.routingThreshold Token di input minimi da instradare attraverso il prefiller. Le richieste al di sotto di questa soglia vengono inviate direttamente al decoder. 4096 L'impostazione predefinita funziona bene per la maggior parte dei carichi di lavoro. Impostarlo su un valore troppo basso aumenta il TTFT a causa di trasferimenti KV non necessari su prompt brevi, mentre impostarlo su un valore troppo alto limita il miglioramento del TPOT perché il percorso DPD è composto da un minor numero di richieste.
pdSpec.prefillSpec.replicas Numero di pod di preriempimento. 1 Aumenta se la profondità della coda di precompilazione è elevata per migliorare il TTFT di precompilazione.
PD_BUFFER_SIZE Buffer GPU di decodifica per trasferimenti KV in entrata (per rank). 8 GiB detiene circa 35 K-token trasferimenti in volo 6 per 70 B a TP=8. "8589934592"(8 GiB) Aumenta per gestire più trasferimenti KV simultanei. Riduci se riscontri problemi di memoria. Quando si aumenta, potrebbe essere necessario --gpu-memory-utilization abbassare il livello del decoder per liberare memoria della GPU per un buffer più grande.
--gpu-memory-utilization Frazione della memoria GPU utilizzata da VLLm per pesi, attivazioni e cache KV. 0.75 Aumentalo per avere più spazio nella cache KV su ingressi lunghi. Rischio: prefiller OOM perché il prefill necessita anche di memoria per le attivazioni. Esegui il test con la distribuzione effettiva della lunghezza in ingresso.
--max-num-seqs Numero massimo di sequenze simultanee per batch di lavoro. 16(precompilatore), (decodificatore) 32 Aumenta per una migliore dosatura sotto carico. Si accende premendo OK sul prefiller. Imposta per ruolo tramite. pdSpec.{prefillSpec,decodingSpec}.args
intelligentRoutingSpec.routingStrategy In che modo il router seleziona un prefiller quando esistono più repliche. prefixaware Utilizzato roundrobin per distribuire uniformemente il carico su più repliche di prefiller. Utilizzalo prefixaware o kvaware con un singolo prefiller o quando i prompt condividono prefissi comuni (istruzioni di sistema, cronologia chat) per massimizzare gli accessi alla cache.

Esegui il test con il carico di lavoro effettivo e la distribuzione della lunghezza di input.

Per applicare le modifiche alla configurazione, modifica il codice YAML della tua implementazione e riapplica:

kubectl apply -f inference_endpoint_dpd_config.yaml

Limiti noti

  • DPD è consigliato per modelli ad alta densità con 70 B 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 le future release.

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

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

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