Proč FLUX.2-dev GGUF Q4_K_M na Apple Silicon spotřebuje 29 GB VRAM
Model FLUX.2-dev v kvantovaném formátu GGUF Q4_K_M by teoreticky měl zabírat kolem 19 GB paměti, ale v praxi na Apple Silicon s čipem M3 Pro dosahuje vrcholu až 28,92 GB. Analýza ukazuje, že přebytečné gigabajty se spotřebují na MPS-ověření, dekvantizaci váh a přenos dat mezi CPU a GPU v unified memory.
Architektura načítání a postupné vykládání
FLUX.2-dev používá textový enkodér Mistral-Small-3.2-24B, který ve své plné verzi vyžaduje 45 GB VRAM. Pro Apple Silicon se používá 4bitová verze prostřednictvím MLX, která spotřebuje 16 GB. Proces je organizován jako sekvenční vykládání:
- Načtení MLX-enkodéru (~13 GB).
- Kódování promptu do embeddings na CPU.
- Vykládání enkodéru s vyčištěním mezipaměti.
- Načtení DiT-modelu GGUF Q4_K_M (~19 GB na disku).
- Inicializace VAE a scheduleru na CPU.
- Přesun celého pipeline na MPS.
Teoretický vrchol je maximální z velikostí komponent, ale realita je jiná kvůli specifickým vlastnostem unified memory.
Testovací prostředí
- macOS: 26.3.1 (Tahoe)
- Čip: Apple M3 Pro, 36 GB unified memory
- Python: 3.14.3
- PyTorch: 2.11.0
- diffusers: 0.38.0.dev
- mlx-lm: 0.31.1
Profiling probíhal prostřednictvím phys_footprint (analog metriky Activity Monitor) a MPS-metrik PyTorch. psutil.rss nepočítá MPS-alokace.
Podrobná analýza spotřeby paměti
Krok za krokem měření
| Krok | phys_footprint | MPS driver | MPS current |
|------|----------------|------------|-------------|
| Základní stav | 0,27 GB | 0 | 0 |
| MLX enkodér načten | 13,22 GB | 0 | 0 |
| GGUF na CPU | 19,23 GB | 0 | 0 |
| pipe.to(mps) | 23,79 GB | 20,06 GB | 18,75 GB |
| Střední fáze inference | 26,50 GB | 25,62 GB | 18,78 GB |
Vrchol 28,92 GB vzniká při pipe.to("mps") kvůli současnému existenci CPU- a MPS-kopií dat.
Anatomie 28 GB
- DiT Q4_K_M (uint8): 18,59 GB
- VAE (bf16): 0,16 GB
- MPS pool overhead: +1,31 GB
- IOKit/Metal graphCache: ~3,73 GB (šadery, page tables, limbo buffers)
Váhy GGUF zůstávají v uint8 na MPS, dekvantizace do bf16 probíhá během forward passu po vrstvách. Mezipaměť dočasných bf16-tensorů (až 6,92 GB) se hromadí.
Optimalizace snížení vrcholu
- Postupný přesun na MPS: Přesun parametrů po jednom s
gc.collect()každých 30 parametrů.
def _move_to_device_incremental(pipe, device):
n = 0
for attr in list(vars(pipe)):
comp = getattr(pipe, attr, None)
if not isinstance(comp, torch.nn.Module):
continue
for param in comp.parameters():
param.data = param.data.to(device)
n += 1
if n % 30 == 0:
gc.collect()
for buf in comp.buffers():
buf.data = buf.data.to(device)
gc.collect()
torch.mps.synchronize()
torch.mps.empty_cache()
- empty_cache() mezi kroky: Callback na kroku inference s
torch.mps.empty_cache()pro vymazání mezipaměti dekvantizace.
- Po-generační flush: Po inference –
gc.collect()+torch.mps.empty_cache().
Výsledky optimalizací
| Metrika | Před | Po | Rozdíl |
|---------|------|----|--------|
| Peak phys_footprint | 28,92 GB | 27,36 GB | -1,56 GB |
| Stabilní stav po inference | 26,25 GB | 21,76 GB | -4,49 GB |
| Čas generace (1 krok) | 2:04 | 2:11 | +7 s |
Vrchol klesá díky inkrementálnímu GC při načítání, stabilní stav díky flushování mezipaměti. Nevyhnutelný overhead MPS/IOKit je přibližně 3,5 GB.
Důležité:
- Minimální stabilní stav: ~24 GB, vrchol inference ~27 GB.
- Hlavní spotřeba: 18,59 GB na uint8-váhy DiT + 3,5 GB MPS-overhead.
- Dekvantizace do bf16 přidá 3–5 GB dočasných bufferů.
- Přenos CPU→MPS zdvojnásobí vrchol kvůli unified memory.
- Optimalizace dává -1,5 GB vrcholu a -4,5 GB stabilního stavu bez ztráty kvality.
Skutečný minimální požadavek pro FLUX.2-dev GGUF na M3 Pro je 24+ GB unified memory. Pro menší objemy je třeba agresivnější kvantizace nebo vykládání na CPU.
— Editorial Team
Zatím žádné komentáře.