- Published on
SDXL VRAM OOM 해결 9가지 실전 체크리스트
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
SDXL(Stable Diffusion XL)은 기본적으로 UNet이 크고(파라미터 규모), 해상도도 1024x1024를 기본 타깃으로 잡는 경우가 많아 VRAM 사용량이 급격히 치솟습니다. 그래서 CUDA out of memory 또는 RuntimeError: CUDA error: out of memory 같은 OOM이 흔하게 발생합니다.
이 글은 “무조건 배치 줄이세요” 같은 뻔한 팁을 넘어서, 어떤 설정이 VRAM을 얼마나 건드리는지를 기준으로 9가지를 우선순위대로 정리합니다. WebUI(AUTOMATIC1111), ComfyUI, Diffusers(Python) 어디에서든 통하는 원리 위주로 설명합니다.
참고: OOM은 단순히 VRAM이 부족한 것뿐 아니라, 메모리 단편화, 피크 메모리 급등, 백그라운드 프로세스 점유가 겹쳐서 발생하는 경우가 많습니다. 따라서 한 가지 처방이 아니라 “피크를 깎는 조합”이 정답인 경우가 많습니다.
관련해서 장애를 빠르게 진단하는 접근은 쿠버네티스의 크래시 분석과도 비슷합니다. 원인 분류 후 체크리스트로 좁혀가는 방식이 도움이 됩니다: Kubernetes CrashLoopBackOff 10가지 원인과 15분 진단
1) 해상도와 픽셀 수를 먼저 줄여 피크를 깎기
SDXL에서 VRAM을 가장 크게 좌우하는 건 **해상도(정확히는 latent 공간의 토큰 수)**입니다. 1024x1024에서 1152x896, 1216x832처럼 조금만 올려도 VRAM 피크가 급증합니다.
- 가장 확실한 처방:
1024x1024를896x896또는832x1216같은 “비슷한 픽셀 수”로 낮추기 - 업스케일은 **후처리(Hi-Res fix 또는 별도 업스케일러)**로 분리하기
WebUI라면 우선 Width/Height를 낮춰 1장이라도 안정적으로 생성되는 기준점을 만든 뒤, 다른 최적화를 얹는 게 좋습니다.
2) Batch size와 Batch count를 분리해서 생각하기
OOM은 대부분 동시에 올리는 텐서 수 때문에 납니다.
Batch size는 VRAM에 직접적으로 큰 영향을 줍니다(동시 샘플 수 증가)Batch count는 순차 생성이라 VRAM 영향이 상대적으로 작습니다
따라서 “여러 장이 필요”하면 Batch size=1을 유지하고 Batch count를 늘리는 방향이 안전합니다.
3) SDXL에서 Hi-Res fix는 “2차 생성”이라 VRAM 폭탄이 될 수 있음
Hi-Res fix는 보통
- 저해상도에서 1차 생성
- 업스케일 후 2차로 다시 디노이즈
를 수행합니다. 이 2차 단계가 고해상도 latent + UNet 조합으로 피크가 터지기 쉽습니다.
권장 전략:
- OOM이 나면 Hi-Res fix를 끄고 1차 생성만 성공시키기
- 꼭 필요하면
Denoising strength를 낮추고(예:0.35근처), 업스케일 배율을 줄이기(예:1.5x) - 업스케일러를 별도 파이프라인(ESRGAN, 4x-UltraSharp 등)으로 분리
4) Attention 최적화: xFormers 또는 SDP로 메모리 사용량 줄이기
SDXL은 attention 메모리 비중이 큽니다. 따라서 attention 구현을 바꾸는 것만으로도 OOM이 해결되는 경우가 많습니다.
WebUI(AUTOMATIC1111)
--xformers옵션 사용(환경에 따라 설치 필요)- 또는 PyTorch의 SDP(Scaled Dot-Product Attention) 최적화를 활용
Diffusers(Python) 예시
아래는 Diffusers에서 메모리 효율 attention을 켜는 대표 패턴입니다.
import torch
from diffusers import StableDiffusionXLPipeline
pipe = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
).to("cuda")
# 1) xFormers (설치되어 있을 때)
pipe.enable_xformers_memory_efficient_attention()
# 2) 또는 attention slicing
pipe.enable_attention_slicing("auto")
image = pipe(
prompt="cinematic photo, 35mm",
width=1024,
height=1024,
num_inference_steps=30,
).images[0]
주의할 점:
- xFormers는 드라이버, CUDA, PyTorch 버전에 따라 설치 난이도가 있습니다.
- 성능과 품질은 대체로 유지되지만, 일부 환경에서는 미세한 차이가 날 수 있습니다.
5) VAE가 의외의 복병: VAE를 FP16으로, 필요 시 타일링 사용
OOM이 “거의 다 됐는데 마지막에 터지는” 패턴이라면 VAE 디코딩이 트리거인 경우가 있습니다. 특히 고해상도 디코딩에서 VRAM이 순간적으로 튀는 일이 있습니다.
해결책:
- VAE를
fp16으로 운용 - VAE tiling(타일 단위 디코딩) 지원 시 활성화
Diffusers 예시:
import torch
from diffusers import StableDiffusionXLPipeline
pipe = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
).to("cuda")
pipe.vae.enable_tiling() # VRAM 절약, 약간 느려질 수 있음
img = pipe("a portrait photo", width=1024, height=1024).images[0]
6) Gradient checkpointing은 학습용, 추론에는 다른 레버가 더 큼
가끔 “체크포인팅 켜면 VRAM 줄죠?”라는 질문이 있는데, **학습(training)**에서는 강력하지만 **추론(inference)**에서는 체감이 제한적입니다.
추론에서 더 효과적인 순서는 보통 이렇습니다.
- 해상도 / 배치
- attention 최적화(xFormers/SDP)
- fp16/bf16
- VAE 타일링
- CPU offload
즉, 추론 OOM이면 체크포인팅보다 offload나 attention 최적화부터 보세요.
7) CPU offload / sequential offload로 “VRAM 상주 모델”을 줄이기
VRAM이 작은 GPU(예: 8GB, 6GB)에서 SDXL을 돌릴 때는 오프로딩이 현실적인 해법입니다. 속도는 느려지지만 “돌아가게” 만들 수 있습니다.
Diffusers 예시:
import torch
from diffusers import StableDiffusionXLPipeline
pipe = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
)
# VRAM이 매우 빡빡할 때
pipe.enable_model_cpu_offload()
img = pipe("ultra detailed", width=1024, height=1024, num_inference_steps=25).images[0]
ComfyUI도 노드 그래프 구성에 따라 VRAM 상주량이 달라집니다. 동일한 결과를 내더라도
- refiner를 항상 붙여 두는 그래프
- 필요할 때만 로드/실행하는 그래프
는 VRAM 피크가 달라질 수 있습니다.
8) SDXL Refiner는 ‘옵션’이 아니라 ‘두 번째 파이프라인’이다
SDXL은 base와 refiner를 함께 쓰면 품질이 좋아지지만, 구조적으로는 큰 모델을 두 개 운용하는 셈입니다.
OOM이 난다면 우선순위는 다음입니다.
- refiner를 끄고 base만으로 안정화
- refiner를 쓰더라도
refiner switch비율을 조정해 refiner 구간을 줄이기 - 혹은 refiner를 별도 실행(이미지 저장 후 refiner-only 파이프라인)
특히 VRAM 8GB 이하에서는 base+refiner 동시 운용이 사실상 불가능한 조합이 자주 나옵니다.
9) 메모리 단편화와 백그라운드 점유: “남아 있는 VRAM”을 의심하기
nvidia-smi를 보면 VRAM이 조금 남아 있는데도 OOM이 나는 경우가 있습니다. 이때는
- PyTorch CUDA allocator 단편화
- 다른 프로세스(브라우저, 게임 런처, 녹화툴)의 VRAM 점유
- WebUI 확장(extensions) 또는 미리보기 기능이 만든 추가 텐서
가 원인일 수 있습니다.
즉시 점검 체크리스트
nvidia-smi로 불필요 프로세스 종료- WebUI라면 확장 비활성화 후 재시도(특히 ControlNet, 애니메이션 계열)
- 세션을 오래 켜뒀다면 프로세스 재시작(누수/캐시로 피크가 커질 수 있음)
PyTorch 쪽에서는 환경 변수로 allocator 동작을 조정하기도 합니다(환경/버전에 따라 효과 차이).
# 예: 단편화 완화에 도움이 될 수 있는 설정(환경에 따라 다름)
export PYTORCH_CUDA_ALLOC_CONF="max_split_size_mb:128"
운영 환경에서 “원인 추적 후 빠르게 차단”하는 방식은 프론트 성능 병목을 추적하는 접근과도 비슷합니다. 한 번에 감으로 고치기보다, 지표를 보고 피크를 줄이는 쪽이 성공률이 높습니다: Chrome LCP 느림? Render‑Blocking 리소스 추적법
실전 권장 적용 순서(가장 덜 아픈 것부터)
Batch size=1고정, 해상도1024x1024이하로 기준점 만들기- refiner 끄기(또는 switch 구간 축소)
- Hi-Res fix 끄고 1차 생성만 성공시키기
- xFormers 또는 SDP 계열 attention 최적화
- VAE
fp16및 VAE tiling - CPU offload로 “돌아가게” 만들기
- 확장/백그라운드 프로세스 정리, 프로세스 재시작
마무리: OOM은 ‘총량’보다 ‘피크’ 문제다
SDXL OOM은 단순히 “VRAM이 부족해서”가 아니라, 특정 단계(attention, VAE 디코딩, Hi-Res 2차 디노이즈, refiner 전환)에서 순간 피크가 튀면서 발생하는 경우가 많습니다. 그래서 해결도 “한 방 옵션”보다 피크를 만드는 기능을 분리하고, 메모리 효율 attention과 오프로딩을 조합하는 쪽이 재현성과 성공률이 높습니다.
다음에 OOM이 났을 때는 에러 로그를 보고 “어느 단계에서 터졌는지”부터 잡아보세요. 그 다음 이 글의 9가지 중 해당되는 레버를 순서대로 적용하면, 같은 GPU에서도 훨씬 안정적으로 SDXL을 굴릴 수 있습니다.