- Published on
Stable Diffusion VRAM 폭주 해결 - xFormers·VAE 타일링
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
Stable Diffusion을 돌리다 보면 같은 프롬프트인데도 어느 순간 VRAM이 급격히 치솟아 CUDA out of memory 로 터지는 경우가 있습니다. 특히 고해상도, 배치 증가, 업스케일, ControlNet, 여러 LoRA를 얹는 순간 “평소엔 되던 설정”이 갑자기 안 되는 일이 흔합니다.
이 글은 VRAM 사용량이 어디서 폭증하는지(UNet, Attention, VAE, 후처리) 구조적으로 분해한 뒤, 실전에서 가장 체감이 큰 두 가지 축인 xFormers 와 VAE 타일링 으로 메모리를 안정화하는 방법을 정리합니다. 추가로 자주 놓치는 설정(해상도/배치/샘플러/하이레즈 픽스)까지 체크리스트로 제공합니다.
성능 튜닝을 “증상 기반으로 병목을 쪼개서” 접근하는 방식은 웹 성능에서 TTFB를 잡는 과정과도 유사합니다. 비슷한 사고방식이 궁금하면 Next.js 14 App Router TTFB 폭증 잡는 RSC 튜닝 도 함께 보시면 도움이 됩니다.
VRAM이 폭주하는 지점부터 정확히 보기
Stable Diffusion 파이프라인을 VRAM 관점으로 단순화하면 아래처럼 나뉩니다.
- 텍스트 인코더: 상대적으로 작지만, 배치/시퀀스 길이/CLIP 스킵 등에 영향
- UNet: 확산 과정의 대부분을 차지. 특히 Attention이 메모리 피크를 만들기 쉬움
- VAE 디코드/인코드: 최종 이미지로 변환할 때 큰 텐서가 생기면서 피크가 튐
- 부가 모듈: ControlNet, IP-Adapter, 여러 LoRA, 업스케일러, 디테일러 등
VRAM 폭주의 전형적인 패턴은 두 가지입니다.
Attention에서 메모리 피크: 고해상도에서 토큰 수가 늘고, Attention의
QK^T중간 텐서가 커지면서 급격히 증가VAE 디코드에서 급증: 샘플링이 끝났는데도 마지막 디코딩에서 OOM. 특히
Hires.fix나 업스케일 후 디코드가 트리거
따라서 해결도 두 갈래로 나뉩니다.
- Attention 최적화:
xFormers또는SDP계열 메모리 효율 Attention - VAE 최적화:
VAE 타일링과VAE half같은 디코드 메모리 절감
xFormers: VRAM 피크를 낮추는 1순위
xFormers 는 메모리 효율적인 Attention 커널을 제공해, 특히 고해상도에서 VRAM 피크를 크게 낮춰줍니다. 체감상 “되던 게 안 되던 상황”을 다시 되게 만드는 가장 확률 높은 옵션입니다.
A1111(Automatic1111)에서 xFormers 적용
A1111 기준으로는 보통 실행 인자에 --xformers 를 추가합니다.
# 예: webui-user.sh 또는 webui-user.bat의 COMMANDLINE_ARGS
COMMANDLINE_ARGS="--xformers --medvram"
--xformers: 메모리 효율 Attention 활성화--medvram: 레이어/모듈 로딩 전략을 바꿔 VRAM을 더 아낌(속도는 일부 손해)
주의할 점:
- 환경에 따라
xFormers빌드/호환 이슈가 있을 수 있습니다. - 최신 PyTorch에서는
SDPA(scaled dot product attention) 최적화가 좋아져서, 어떤 조합에서는xFormers가 반드시 최고는 아닙니다. 하지만 “VRAM 폭주를 막는 안정성” 관점에서는 여전히 강력합니다.
ComfyUI에서 xFormers 또는 Attention 최적화
ComfyUI는 설치 환경에 따라 xFormers 가 이미 포함되거나, 별도 설치가 필요할 수 있습니다. 대체로는 아래처럼 설치합니다.
# venv 활성화 후
pip install -U xformers
그리고 ComfyUI 실행 시 로그에서 xformers enabled 같은 메시지로 적용 여부를 확인합니다.
xFormers가 줄여주는 “진짜 메모리”는 무엇인가
Attention은 단순화하면 아래 계산을 합니다.
Q, K, V텐서 생성QK^T로 attention score 생성- softmax 후
V와 곱
문제는 QK^T 가 공간 해상도에 비례해 매우 커진다는 점입니다. 예를 들어 latent 공간에서 토큰 수가 커지면 중간 행렬이 제곱으로 불어납니다. xFormers 는 이 중간 텐서를 덜 만들거나, 더 효율적으로 처리해 피크를 낮춥니다.
즉, 해상도를 올릴수록 효과가 커지는 경향이 있습니다.
VAE 타일링: “샘플링은 끝났는데 디코드에서 OOM” 해결
VAE 타일링 은 VAE 디코드(또는 인코드) 시 이미지를 한 번에 처리하지 않고, 타일 단위로 쪼개서 처리해 VRAM 피크를 낮추는 기법입니다.
전형적인 증상:
- 샘플링 단계는 잘 도는데 마지막에 OOM
Hires.fix를 켜면 끝에서 터짐- 업스케일 후 디코드에서만 터짐
이때는 Attention 최적화보다 VAE 쪽이 병목인 경우가 많습니다.
A1111에서 VAE 타일링/관련 옵션
A1111은 버전과 확장에 따라 메뉴/옵션명이 조금 다를 수 있지만, 핵심은 아래 세 가지입니다.
VAE in half precision또는--vae-in-fp16VAE tiling(설정 또는 확장)--lowvram또는--medvram(필요 시)
실행 인자 예시는 다음처럼 구성합니다.
COMMANDLINE_ARGS="--xformers --vae-in-fp16 --medvram"
만약 UI 설정에서 VAE 타일링을 켤 수 있다면, 타일 크기를 너무 작게 잡으면 속도가 많이 느려질 수 있습니다. 보통은 “OOM이 안 나는 선에서” 가장 큰 타일 크기를 찾는 방식으로 튜닝합니다.
Diffusers(Python)에서 VAE 타일링 적용 예시
Hugging Face Diffusers를 직접 쓴다면 VAE 타일링은 코드로 명시적으로 켤 수 있습니다.
import torch
from diffusers import StableDiffusionPipeline
model_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionPipeline.from_pretrained(
model_id,
torch_dtype=torch.float16,
)
pipe = pipe.to("cuda")
# Attention 메모리 최적화: 환경에 따라 사용
pipe.enable_xformers_memory_efficient_attention()
# VAE 타일링: 디코드/인코드 피크 감소
pipe.enable_vae_tiling()
image = pipe(
prompt="a photo of a cat, ultra detailed",
num_inference_steps=30,
guidance_scale=7.0,
).images[0]
image.save("out.png")
추가로 VRAM이 정말 빡빡하면 아래도 같이 고려합니다.
pipe.enable_attention_slicing("max")
pipe.enable_model_cpu_offload()
attention slicing은 속도를 희생하고 메모리를 줄이는 옵션cpu offload는 VRAM을 크게 줄이지만 전송 오버헤드로 속도가 크게 떨어질 수 있음
“해상도만 올렸는데 VRAM이 2배 이상”의 이유
Stable Diffusion은 픽셀 공간이 아니라 latent 공간에서 주로 연산하지만, 해상도 증가가 곧바로 텐서 크기 증가로 이어집니다.
- 이미지 해상도
W x H가 커지면 latent도 비례해서 커짐 - Attention은 토큰 수 증가에 민감
- VAE 디코드는 최종 픽셀 공간 텐서가 커서 피크가 생김
실전 팁:
- 512에서 768로 올리는 것은 “1.5배”가 아니라, 면적 기준으로는 더 큽니다.
Hires.fix는 “두 번 그리는 것”에 가깝습니다. 1차 생성 + 업스케일 + 2차 디노이즈로, 중간 텐서가 더 커집니다.
VRAM 폭주를 부르는 대표 설정 7가지
아래 항목은 “갑자기 안 되는” 트리거로 자주 등장합니다.
- 배치 크기 증가: batch는 VRAM을 정직하게 곱합니다.
- 해상도 증가: 면적 증가로 텐서가 커짐.
- Hires.fix: 2패스 처리로 피크가 증가.
- ControlNet 다중 사용: 모듈이 늘면 중간 피처맵이 늘어남.
- 여러 LoRA/텍스트 인버전: 보통은 UNet에 추가 연산/메모리.
- 고스텝 + 특정 샘플러 조합: 일부 구현에서 캐시/버퍼 영향.
- 업스케일러와 후처리 동시 사용: VAE 디코드 타이밍과 겹치면 피크가 커짐.
이런 문제는 “원인 후보를 줄여가며 재현”하는 접근이 중요합니다. 운영 환경에서 타임아웃 원인을 12가지로 분해해 점검하듯, 생성 파이프라인도 체크리스트로 쪼개면 해결이 빨라집니다. 비슷한 진단 방식의 글로 AWS ALB 504 Gateway Timeout 원인·해결 12가지 도 참고할 만합니다.
추천 튜닝 조합(상황별)
8GB VRAM: “일단 안 터지게” 우선
xFormers활성화VAE fp16활성화VAE 타일링활성화- 배치 1 고정, 해상도는 보수적으로 시작
- 필요하면
--medvram또는 offload
A1111 실행 인자 예:
COMMANDLINE_ARGS="--xformers --vae-in-fp16 --medvram"
12GB VRAM: 고해상도/ControlNet을 현실적으로
xFormers는 기본값처럼 켜기- ControlNet은 1개부터 시작해서 늘리기
- Hires.fix는 업스케일 배율을 과하게 잡지 않기
- 디코드 OOM이 보이면
VAE 타일링
24GB VRAM: 속도와 품질의 균형
xFormers는 상황에 따라 속도/호환성 비교- VAE 타일링은 보통 필요 없지만, 초고해상도나 대형 배치에서는 여전히 유효
- 병목이 VRAM이 아니라면, 오히려 CPU offload 같은 옵션은 끄는 게 낫습니다.
VRAM 사용량 측정과 재현: 감이 아니라 로그로 잡기
튜닝은 “체감”으로 하면 끝이 없습니다. 최소한 아래는 고정해두고 비교하는 것을 권합니다.
- 같은 seed
- 같은 해상도
- 같은 steps, sampler
- 같은 ControlNet/LoRA 구성
그리고 VRAM은 nvidia-smi 로 피크를 관찰합니다.
watch -n 0.5 nvidia-smi
더 정밀하게는 PyTorch에서 메모리 피크를 찍을 수도 있습니다.
import torch
torch.cuda.reset_peak_memory_stats()
# ... inference ...
print(torch.cuda.max_memory_allocated() / 1024**3, "GiB")
이렇게 수치로 비교하면, xFormers 가 피크를 얼마나 줄였는지, VAE 타일링 이 디코드 구간에서만 피크를 낮추는지 명확히 보입니다.
자주 묻는 질문
xFormers만 켜면 모든 OOM이 해결되나요
아닙니다. 샘플링 중 OOM 은 Attention 최적화로 해결되는 경우가 많지만, 마지막 디코드에서 OOM 은 VAE 쪽 최적화(타일링, fp16)가 더 직접적입니다.
VAE 타일링은 품질을 떨어뜨리나요
대부분의 경우 눈에 띄는 품질 저하는 크지 않습니다. 다만 타일 경계에서 미세한 이음새가 생길 수 있는 구현도 있어, 타일 크기와 설정에 따라 결과를 확인하는 것이 안전합니다.
속도는 얼마나 느려지나요
xFormers는 보통 속도도 유리하거나 비슷한 경우가 많습니다.VAE 타일링은 디코드/인코드가 타일 단위로 반복되므로 속도 손해가 날 수 있습니다.
결론: OOM을 “Attention”과 “VAE”로 나눠서 잡아라
Stable Diffusion VRAM 폭주는 대부분 두 지점에서 발생합니다.
- 샘플링 중 폭주:
xFormers로 Attention 피크를 낮춘다 - 디코드에서 폭주:
VAE fp16과VAE 타일링으로 디코드 피크를 낮춘다
여기에 배치/해상도/Hires.fix/ControlNet 같은 트리거를 체크리스트로 관리하면 “어제 되던 게 오늘 안 되는” 상황을 훨씬 빠르게 복구할 수 있습니다. 튜닝은 감이 아니라 재현 가능한 실험으로, 피크 메모리를 숫자로 비교하면서 진행하는 것이 가장 확실합니다.