Inferenza distribuita: condividi il carico tra più macchine
Prefill in pipeline (veloce)
Section titled “Prefill in pipeline (veloce)”Durante il prefill (elaborazione iniziale del prompt), i worker possono lavorare in pipeline: mentre il coordinator sta processando il chunk N+1, il worker 1 può processare il chunk N, e così via. Questo accelera il prefill, specialmente per prompt lunghi.
Esempio numerico (due Mac M5 Max, Thunderbolt 5):
| Prompt length | Single machine (Q2) | Two machines (Q4) | Speedup |
|---|---|---|---|
| 9,421 token | 421 t/s | 582 t/s | 1.38x |
| 28,684 token | 405 t/s | 674 t/s | 1.66x |
| 63,819 token | 353 t/s | 654 t/s | 1.85x |
Nota: i numeri “single machine” sono con Q2 (più leggero), mentre “two machines” con Q4 (più pesante). A parità di modello, lo speedup sarebbe ancora più marcato.
Generazione token per token (lenta)
Section titled “Generazione token per token (lenta)”La generazione è strettamente autoregressiva: il token N+1 non può iniziare finché il token N non ha completato l’intero percorso attraverso tutti i worker e il coordinator ha effettuato il sampling. Quindi ogni token paga la latenza di rete andata/ritorno tra i worker.
Nello stesso setup Thunderbolt 5 (latenza ~0.45 ms tra le macchine), la generazione passa da 30.59 t/s (single machine, Q2) a 24.67 t/s (distribuita, Q4). Una perdita del 19%. Su reti più lente (WiFi, Internet) il degrado è molto peggiore.
Configurazione pratica: DeepSeek V4 PRO Q4 su due Mac Studio
Section titled “Configurazione pratica: DeepSeek V4 PRO Q4 su due Mac Studio”Questo è l’uso più significativo della distribuzione. Avrai bisogno di:
- Due Mac Studio con almeno 256 GB di RAM ciascuno (meglio 512 GB)
- Una connessione di rete veloce: Thunderbolt 5 (consigliato), Ethernet 10 GbE, o almeno Gigabit
- I due file GGUF specifici per il PRO Q4 diviso
Passo 1: Scaricare i due file GGUF su entrambe le macchine
Section titled “Passo 1: Scaricare i due file GGUF su entrambe le macchine”Su entrambi i Mac, esegui:
cd ds4./download_model.sh pro-q4-layers00-30./download_model.sh pro-q4-layers31-outputQuesto scaricherà due file nella cartella gguf/:
DeepSeek-V4-Pro-Q4K-Layers00-30.gguf(prima metà)DeepSeek-V4-Pro-Q4K-Layers-31-output.gguf(seconda metà + output head)
Passo 2: Decidere chi è coordinator e chi worker
Section titled “Passo 2: Decidere chi è coordinator e chi worker”Scegli una macchina come coordinator (quella da cui darai i comandi). L’altra sarà worker. L’importante è che il coordinator possieda i layer iniziali (0:30) e il worker quelli finali (31:output).
Passo 3: Avviare il worker
Section titled “Passo 3: Avviare il worker”Sulla macchina worker, esegui:
./ds4 \ -m gguf/DeepSeek-V4-Pro-Q4K-Layers-31-output.gguf \ --role worker \ --layers 31:output \ --coordinator <IP_del_coordinator> 1234--role worker: specifica il ruolo--layers 31:output: intervallo di layer (dal layer 31 fino all’output head)--coordinator <IP> 1234: indirizzo e porta del coordinator (aspetterà connessioni su quella porta)
Passo 4: Avviare il coordinator
Section titled “Passo 4: Avviare il coordinator”Sulla macchina coordinator, esegui:
./ds4 \ -m gguf/DeepSeek-V4-Pro-Q4K-Layers00-30.gguf \ --role coordinator \ --layers 0:30 \ --listen 0.0.0.0 1234--role coordinator: ruolo principale--layers 0:30: intervallo di layer (dal layer 0 al 30)--listen 0.0.0.0 1234: aspetta connessioni su tutte le interfacce, porta 1234
Il coordinator, dopo aver ricevuto la registrazione del worker, stamperà un messaggio tipo:
Distributed route: coordinator layers 0-30, worker 192.168.1.100 layers 31-outputPasso 5: Usare il coordinator come se fosse un ds4 normale
Section titled “Passo 5: Usare il coordinator come se fosse un ds4 normale”Ora sulla macchina coordinator puoi usare il CLI normalmente:
./ds4 # (già avviato con i comandi sopra, oppure avvia in modalità interattiva)Puoi anche usare ds4-server o ds4-agent in modalità distribuita (passando gli stessi flag). Tutta l’interazione avviene attraverso il coordinator.
Configurazione per accelerare il prefill (Flash su due Mac)
Section titled “Configurazione per accelerare il prefill (Flash su due Mac)”Se non hai bisogno di far stare un modello enorme, ma vuoi solo accelerare il prefill di prompt lunghissimi (es. 100k token) sul modello Flash, puoi distribuire i layer in modo più equilibrato.
Esempio su due Mac M5 Max con 128 GB, modello Flash Q4:
Worker (possiede la seconda metà):
./ds4 \ -m gguf/DeepSeek-V4-Flash-Q4K...gguf \ --role worker \ --layers 20:output \ --coordinator 169.254.43.68 1234Coordinator (possiede la prima metà + output head? No, l’output head ce l’ha l’ultimo worker):
./ds4 \ -m gguf/DeepSeek-V4-Flash-Q4K...gguf \ --role coordinator \ --layers 0:19 \ --listen 0.0.0.0 1234In questo caso, il worker possiede l’output head (perché 20:output include l’ultimo layer e la testa). I logits vengono calcolati dal worker e restituiti al coordinator.
Variante per link lenti: Su reti molto lente o con bande limitate, puoi usare --layers 20:42 (senza output). In questo caso il coordinator mantiene l’output head e calcola i logits localmente, scambiando meno dati per token ma aggiungendo lavoro al coordinator.
Ottimizzazioni di rete
Section titled “Ottimizzazioni di rete”1. Usare una connessione veloce
Section titled “1. Usare una connessione veloce”| Tipo di connessione | Latenza tipica | Prefill (speedup) | Generazione | Consigliata |
|---|---|---|---|---|
| Thunderbolt 5 (bridge) | 0.45 ms | 1.6-1.8x | -19% | ✅ Ideale |
| Ethernet 10 GbE | 0.3-0.5 ms | simile | simile | ✅ Ottima |
| Gigabit Ethernet | 0.3-0.5 ms | simile | leggermente peggio | 👍 Accettabile |
| WiFi 6 (buon segnale) | 2-5 ms | ~1.3x | -60% | ⚠️ Solo prefill |
| Internet/VPN | 50-150 ms | ~1.1x | -90% | 🔴 Non raccomandato |
2. Ridurre la dimensione delle attivazioni in transito
Section titled “2. Ridurre la dimensione delle attivazioni in transito”Le attivazioni scambiate tra worker sono tensori di hidden state (di solito float32). Puoi comprimerle a 16 o 8 bit per ridurre il traffico di rete:
# Sul coordinator (e si propaga ai worker)./ds4 ... --dist-activation-bits 16--dist-activation-bits 16 dimezza il traffico, con perdita di qualità trascurabile. --dist-activation-bits 8 è più aggressivo, ma antirez segnala che il miglioramento non è enorme, quindi questa opzione potrebbe essere rimossa in futuro.
3. Regolare la profondità della pipeline (--dist-prefill-window)
Section titled “3. Regolare la profondità della pipeline (--dist-prefill-window)”--dist-prefill-window N controlla quanti chunk di prefill possono essere in volo end-to-end tra coordinator e worker. Il default è conservativo e limitato. Aumentarlo può migliorare il throughput su prompt molto lunghi, ma consuma più memoria.
4. Regolare la dimensione dei chunk di prefill
Section titled “4. Regolare la dimensione dei chunk di prefill”Il parametro --dist-prefill-chunk determina quanti token vengono elaborati in pipeline prima di sincronizzarsi. Il default (4096 token) è ottimale. Modificalo solo per esperimenti.
./ds4 ... --dist-prefill-chunk 2048Diagnostica e debug
Section titled “Diagnostica e debug”Aggiungi --debug al coordinator per vedere la telemetria della distribuzione:
./ds4 --role coordinator --layers 0:19 --listen 0.0.0.0 1234 --debugVedrai messaggi come:
[dist] route built: coordinator(0-19) worker(20-output)[dist] prefill chunk 0: local 45.2ms, worker 48.1ms, total 50.3ms[dist] generate token 42: local 39.8ms, worker 44.2ms, total 84.0msQuesti numeri ti aiutano a capire se il bilanciamento dei layer è equilibrato (i tempi local e worker dovrebbero essere simili). Se un worker è molto più lento, sposta più layer sull’altro.
Tolleranza ai guasti e riconnessione
Section titled “Tolleranza ai guasti e riconnessione”Se un worker si disconnette (perché il processo viene ucciso o la rete salta), il coordinator:
- Rimuove quel worker dal route attivo.
- Se c’è un altro worker compatibile (con gli stessi layer), lo reinserisce.
- Se il route diventa incompleto, le richieste successive falliranno finché non si riconnette un worker adeguato.
Quando un worker si riconnette, il coordinator replay i token mancanti dalla cronologia, ricostruendo lo stato KV del worker. Questo è possibile perché il coordinator mantiene una copia di tutti i token della conversazione.
Limitazioni e avvertenze
Section titled “Limitazioni e avvertenze”- Nessuna crittografia o autenticazione – La comunicazione tra coordinator e worker è in chiaro. Usala solo su reti fidate (LAN privata, Thunderbolt, VPN sicura).
- Compatibilità dei binari – Coordinator e worker devono essere compilati dalla stessa versione di ds4. Commit diversi potrebbero avere protocolli incompatibili.
- Latenza di rete imprevedibile – Su WiFi o Internet, la generazione diventa molto lenta. La distribuzione è pensata per laboratori con connessioni ad alta velocità e bassa latenza.
- Memory mapping – Ogni worker mappa in memoria solo il proprio sottoinsieme di layer. Il modello totale non deve essere caricato interamente su nessuna macchina, ma ogni worker deve avere abbastanza RAM per la propria porzione + KV cache.
- KV cache distribuita – Ogni worker mantiene la propria parte di KV cache. Quando viene salvata una sessione (es. con
/savenell’agente), il coordinator raccoglie i tensori da tutti i worker e li unisce in un unico file. Al caricamento, li redistribuisce.
Riferimenti utili
Section titled “Riferimenti utili”- Il README ufficiale, sezione Distributed Inference
ds4_distributed.c– implementazione del protocollods4_distributed.h– strutture dati
📘 Perché la generazione distribuita è più lenta?
In una singola macchina, dopo che il layer N ha finito, il layer N+1
può iniziare immediatamente (sono nello stesso processo). Nella distribuzione,
dopo che il worker A ha finito, deve serializzare le attivazioni, inviarle via
TCP, e il worker B deve deserializzarle prima di iniziare. Anche con una
latenza di 0.5 ms, su 200 layer si perdono 100 ms per token – un’enormità.
Inoltre, il coordinator deve aspettare il logits finale prima di campionare il
prossimo token.
💡 Se devi solo accelerare il prefill, usa la distribuzione anche su reti più lente
Il prefill beneficia della pipeline anche con latenza più alta (es.
WiFi), perché i chunk grandi (4096 token) sono elaborati in parallelo. La
generazione sarà lenta, ma se hai solo bisogno di una risposta lunga (es.
riassunto di un documento), puoi accettare il compromesso.