Zurück zur Startseite

SD 3.5 Medium auf M1: Optimierung auf 11,6 GB

Der Artikel analysiert die Speicheroptimierung für Stable Diffusion 3.5 Medium auf Apple Silicon. Spitzenverbrauch von 21,4 GB auf 11,6 GB durch sequentielles Laden von T5 und DiT reduziert. Funktionsfähiger Code und Benchmarks für M1 16 GB werden bereitgestellt.

Ausführen von SD 3.5 Medium auf M1 16 GB ohne OOM
Advertisement 728x90

Speicheroptimierung für Stable Diffusion 3.5 Medium auf Apple Silicon M1

Das Stable Diffusion 3.5 Medium-Modell mit 2,5 Milliarden Parametern kann bis zu 21 GB Unified Memory auf Apple Silicon verbrauchen, hauptsächlich aufgrund des T5-XXL-Encoders (10,75 GB im fp16-Format). Durch optimiertes Laden lässt sich der Spitzenverbrauch auf nur noch 11,6 GB reduzieren – das ermöglicht eine reibungslose Nutzung auf M1-Macs mit 16 GB RAM. Dieser Leitfaden erläutert die Ursachen und stellt eine schrittweise Ladestrategie vor.

Ursachen für den Speicherspitzen:

  • Gewichtsduplikation: Modell wird zunächst auf dem CPU geladen, dann kopiert nach MPS.
  • enable_model_cpu_offload() ist wirkungslos – CPU und MPS konkurrieren um den Unified Memory.
  • Beschleunigungs-Hooks mit device_map halten starke Referenzen, was die Garbage Collection verhindern.

Standardcode:

Google AdInline article slot
pipe = StableDiffusion3Pipeline.from_pretrained(
    "stabilityai/stable-diffusion-3.5-medium",
    torch_dtype=torch.float16, variant="fp16")
pipe.to("mps")

Spitzen-Speicherbedarf: 21,4 GB unabhängig von num_inference_steps.

Lösung: Schrittweises Laden

Aufteilung in Phasen: Prompt-Encoding (T5), Entladen, dann Generierung (DiT + VAE).

1. Laden mit device_map="balanced"

Direktes Laden in MPS ohne CPU-Staging:

Google AdInline article slot
pipe = StableDiffusion3Pipeline.from_pretrained(
    path, torch_dtype=torch.float16, device_map="balanced")

T5-Spitze: ~11 GB.

2. Korrekte Hook-Entfernung

from accelerate.hooks import remove_hook_from_submodules

for attr in list(vars(pipe)):
    comp = getattr(pipe, attr, None)
    if isinstance(comp, torch.nn.Module):
        remove_hook_from_submodules(comp)
        setattr(pipe, attr, None)

del pipe
gc.collect()
torch.mps.synchronize()
torch.mps.empty_cache()

Ohne diesen Schritt bleibt T5 im Speicher (10,75 GB).

3. Vollständiger schrittweiser Ablauf

Phase 1: Encoder

Google AdInline article slot
enc_pipe = StableDiffusion3Pipeline.from_pretrained(path,
    transformer=None, vae=None,
    text_encoder=None, text_encoder_2=None,
    tokenizer=None, tokenizer_2=None,
    variant="fp16", torch_dtype=torch.float16,
    device_map="balanced")

prompt_embeds, neg_embeds, pooled, neg_pooled = enc_pipe.encode_prompt(
    prompt="ein Krieger mit Schwert",
    prompt_2="ein Krieger mit Schwert",
    prompt_3="ein Krieger mit Schwert",
    device="mps", num_images_per_prompt=1)

Nach diesem Schritt entladen.

Phase 2: Generator

gen_pipe = StableDiffusion3Pipeline.from_pretrained(path,
    text_encoder=None, text_encoder_2=None, text_encoder_3=None,
    tokenizer=None, tokenizer_2=None, tokenizer_3=None,
    variant="fp16", torch_dtype=torch.float16)
gen_pipe.to("mps")

image = gen_pipe(
    prompt_embeds=prompt_embeds,
    negative_prompt_embeds=neg_embeds,
    pooled_prompt_embeds=pooled,
    negative_pooled_prompt_embeds=neg_pooled,
    num_inference_steps=40).images[0]

.to("mps") nutzt den T5-Cache wieder, senkt den DiT-Verbrauch von 11,5 GB auf 6 GB.

Speicherverbrauchsvergleich

| Phase | Vor Optimierung | Nach Optimierung |

|-------------------|------------------|-------------------|

| T5-Laden | 15,3 GB | 11,5 GB |

| T5 nach Entladen | 10,75 GB | 0,01 GB |

| DiT + Diffusion | 8,9 GB | 8,9 GB |

| Spitze | 21,4 GB | 11,6 GB |

Leistung auf Hardware

  • M1 16 GB: 4:54 min (T5: 1:06, DiT: 3:34), Spitze 11–13 GB.
  • M3 Pro 36 GB: 1:47 min (T5: 0:14, DiT: 1:27), Spitze 9–11 GB.

Auflösung: 512x512, 40 Inferenzschritte.

Wichtige Erkenntnisse:

  • T5-XXL ist der Hauptverbraucher (~71 % des Gesamtspeichers).
  • device_map="balanced" kombiniert mit Hook-Entfernung ist entscheidend für das Entladen.
  • Schrittweises Laden senkt die Spitzenbelastung um 45 %.
  • Funktioniert zuverlässig auf M1 16 GB Macs ohne Swapping.
  • .to("mps") bei DiT ermöglicht effiziente Cache-Wiederverwendung.

— Editorial Team

Advertisement 728x90

Weiterlesen