홈으로 돌아가기

M1에서 SD 3.5 Medium: 11.6 GB로 최적화

이 글은 Apple Silicon에서 Stable Diffusion 3.5 Medium의 메모리 최적화를 분석합니다. T5와 DiT의 순차 로딩으로 피크 사용량을 21.4 GB에서 11.6 GB로 줄였습니다. M1 16 GB용 작동 코드와 벤치마크 제공.

M1 16 GB에서 OOM 없이 SD 3.5 Medium 실행
Advertisement 728x90

Apple Silicon M1에서 스테이블 디퓨전 3.5 미디엄 메모리 최적화 가이드

25억 파라미터를 가진 스테이블 디퓨전 3.5 미디엄 모델은 T5-XXL 인코더(10.75GB, fp16 기준)로 인해 애플 실리콘 환경에서 최대 21GB의 통합 메모리를 소비할 수 있습니다. 최적화된 로딩 전략을 적용하면 피크 메모리 사용량을 단 11.6GB로 줄일 수 있어, 16GB RAM을 가진 M1 맥에서도 원활한 작동이 가능합니다. 본 가이드에서는 문제의 핵심 원인을 분석하고, 단계별 메모리 효율화 전략을 소개합니다.

메모리 급증의 주요 원인:

  • 가중치 중복: 모델이 CPU에 로드된 후 MPS로 복사됨.
  • enable_model_cpu_offload()는 효과 없음 — CPU와 MPS가 통합 메모리를 경쟁함.
  • Accelerate의 device_map 훅은 강한 참조를 유지해 가비지 컬렉션을 방해함.

기본 코드:

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

num_inference_steps와 무관하게 피크 메모리: 21.4GB.

해결책: 순차적 로딩 전략

프롬프트 인코딩(T5) → 언로드 → 생성(DiT + VAE) 단계로 분리하여 처리합니다.

1. device_map="balanced"으로 로딩

CPU 스테이징 없이 직접 MPS에 로드:

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

T5 피크 메모리: 약 11GB.

2. 올바른 훅 제거

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()

이 단계를 생략하면 T5가 메모리에 계속 남아 있음(10.75GB).

3. 완전한 순차 워크플로우

단계 1: 인코더 로딩

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="a warrior with a sword",
    prompt_2="a warrior with a sword",
    prompt_3="a warrior with a sword",
    device="mps", num_images_per_prompt=1)

이 단계 이후 즉시 언로드.

단계 2: 생성기 로딩

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")는 T5 캐시를 재사용해, DiT 메모리 사용량을 11.5GB에서 6GB로 대폭 감소시킴.

메모리 사용량 비교표

| 단계 | 최적화 전 | 최적화 후 |

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

| T5 로드 | 15.3 GB | 11.5 GB |

| T5 언로드 후 | 10.75 GB | 0.01 GB |

| DiT + 디퓨전 | 8.9 GB | 8.9 GB |

| 피크 메모리 | 21.4 GB | 11.6 GB |

하드웨어 성능 비교

  • M1 16GB: 4분 54초 (T5: 1분 6초, DiT: 3분 34초), 피크 메모리 11–13GB.
  • M3 Pro 36GB: 1분 47초 (T5: 14초, DiT: 1분 27초), 피크 메모리 9–11GB.

해상도: 512x512, 추론 단계: 40회.

핵심 요약:

  • T5-XXL이 전체 메모리 사용의 약 71%를 차지함.
  • device_map="balanced"과 훅 제거 조합이 언로드에 필수적임.
  • 순차적 로딩으로 피크 메모리 사용량 45% 감소.
  • 스왑 없이도 M1 16GB 맥에서 안정적으로 작동.
  • DiT에 .to("mps") 적용 시 캐시 재사용이 효율적임.

— Editorial Team

Advertisement 728x90

다음 읽기