- Published on
Stable Diffusion VRAM 부족? xFormers·VAE 타일링
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
Stable Diffusion을 로컬 GPU에서 돌리다 보면 가장 흔히 마주치는 문제가 VRAM 부족입니다. 특히 1024x1024 같은 고해상도, 배치 증가, 고스텝, Hires.fix, ControlNet/LoRA 동시 사용을 얹는 순간 CUDA out of memory가 터지기 쉽습니다.
이 글은 “무작정 해상도 낮추기” 대신, 어텐션 메모리를 줄이는 xFormers와 VAE 디코딩을 쪼개는 VAE 타일링을 중심으로 VRAM 사용량을 안정적으로 낮추는 방법을 다룹니다. 마지막에는 OOM이 계속 날 때 점검 순서까지 제공합니다.
관련해서 시스템이 메모리 압박을 받을 때 원인을 추적하는 관점은 리눅스 OOM 글도 도움이 됩니다: 리눅스 OOM Killer로 프로세스 죽을 때 원인 추적
VRAM은 어디서 터질까: SD 메모리 지형
Stable Diffusion 파이프라인에서 VRAM을 크게 먹는 구간은 대략 아래 4가지입니다.
- U-Net의 어텐션(Attention) 연산
- 해상도가 커질수록 토큰 수가 늘고, 어텐션의 중간 텐서가 폭증합니다.
- VAE 디코딩(라티언트
4채널-> RGB 이미지)- 최종 단계에서 한 번 크게 메모리를 씁니다. 고해상도에서 특히 치명적입니다.
- 추가 모듈(ControlNet, IP-Adapter, 여러 LoRA, Refiner 등)
- 모델 파라미터와 중간 활성화가 증가합니다.
- 배치 크기, CFG, 샘플러 설정
- 배치가 늘면 거의 선형으로 VRAM이 증가합니다.
따라서 VRAM 최적화는 보통 두 갈래로 나뉩니다.
- 어텐션 메모리를 줄인다: xFormers / SDPA / 메모리 효율 어텐션
- VAE 디코딩 메모리를 줄인다: VAE 타일링(tiling)
xFormers: “어텐션” 메모리를 깎는 가장 큰 레버
xFormers는 메모리 효율적인 어텐션 커널을 제공해, U-Net 어텐션에서 발생하는 중간 텐서 메모리를 크게 줄여줍니다. 체감상 “해상도를 한 단계 올릴 수 있게 되는” 수준의 효과가 나오는 경우가 많습니다.
어떤 환경에서 효과가 큰가
768x768,1024x1024같은 고해상도- Hires.fix로 2-pass를 돌리는 경우
- ControlNet을 여러 개 붙이는 경우
반대로 아주 낮은 해상도에서는 속도/메모리 차이가 작을 수 있습니다.
AUTOMATIC1111에서 xFormers 켜기
가장 흔한 WebUI 기준으로는 실행 옵션에 --xformers를 넣습니다.
# webui-user.sh 또는 webui-user.bat의 COMMANDLINE_ARGS 예시
COMMANDLINE_ARGS="--xformers"
실행 후 콘솔 로그에 xFormers가 활성화되었다는 문구가 보이면 정상입니다. 만약 설치가 꼬이면, PyTorch/CUDA 버전과 xFormers 휠이 안 맞는 경우가 많습니다.
ComfyUI에서 xFormers 켜기
ComfyUI는 환경에 따라 다르지만 보통 아래 형태로 활성화합니다.
python main.py --use-xformers
또는 일부 배포판/런처는 설정 메뉴에서 토글을 제공합니다.
xFormers vs PyTorch SDPA
최근 PyTorch는 SDPA(Scaled Dot-Product Attention) 경로가 좋아져서, 환경에 따라 xFormers 없이도 메모리 효율 어텐션이 동작합니다.
- xFormers: 설치/호환성 이슈가 가끔 있음, 대신 폭넓게 검증된 케이스가 많음
- SDPA: PyTorch/드라이버 조합에 따라 자동 최적화, 설치 단순
하지만 “당장 VRAM이 터진다”면, WebUI/ComfyUI가 제공하는 방식으로 xFormers를 먼저 시도하는 게 빠른 해결책인 경우가 많습니다.
VAE 타일링: “마지막 디코딩” OOM을 잡는 비장의 카드
xFormers로도 해결이 안 되는 OOM은 의외로 VAE 디코딩 단계에서 터집니다. 특히 1024x1024 이상, 혹은 Hires.fix의 업스케일 패스에서 VAE가 한 번에 큰 텐서를 만들다가 VRAM을 넘기곤 합니다.
VAE 타일링은 VAE 디코딩을 작은 타일로 쪼개서 순차 처리하는 방식입니다.
- 장점: VRAM 사용량을 크게 낮춤
- 단점: 속도가 느려질 수 있음, 타일 경계에서 미세한 이음새가 생길 수 있음(대부분 설정으로 완화 가능)
AUTOMATIC1111에서 VAE 타일링
WebUI 확장이나 빌드에 따라 옵션 제공 방식이 다를 수 있지만, 핵심은 “VAE를 타일 단위로 처리”하도록 켜는 것입니다.
일반적으로는 Settings에서 VAE 관련 항목에 Tiling 또는 VAE tiling 토글이 존재합니다. 없다면 확장(Extension)로 제공되는 경우도 있습니다.
diffusers(Python)에서 VAE 타일링 켜기
서버/배치 작업에서 diffusers를 쓴다면 코드로 확실하게 제어할 수 있습니다.
import torch
from diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16,
).to("cuda")
# 어텐션 메모리 최적화(환경에 따라 xFormers 또는 SDPA)
pipe.enable_xformers_memory_efficient_attention()
# VAE 타일링: 디코딩 VRAM 급증 완화
pipe.enable_vae_tiling()
image = pipe(
prompt="a photo of a cat, 35mm film",
height=1024,
width=1024,
num_inference_steps=30,
).images[0]
image.save("out.png")
enable_vae_tiling()은 특히 “생성은 거의 다 됐는데 마지막에 OOM” 같은 패턴에 강합니다.
VAE 타일링의 품질 이슈(이음새) 줄이기
타일 경계 이슈가 보이면 아래를 순서대로 시도합니다.
- 타일 크기를 키워 경계 수를 줄이기(가능한 VRAM 범위 내)
- 디코딩 후 약한 후처리(예: 아주 약한 디노이즈/샤픈 최소화)
- 업스케일 파이프라인에서는 업스케일러/샘플러 조합 변경
같이 쓰면 더 강력한 저VRAM 옵션들
xFormers와 VAE 타일링만으로도 많은 케이스가 해결되지만, 여전히 빡빡한 GPU(예: 6GB 이하)에서는 추가 옵션이 필요합니다.
1) 해상도 전략: 한 번에 크게 말고, 2-pass로
512또는640정도로 1차 생성- Hires.fix 또는 업스케일 + 낮은 denoise로 2차
다만 Hires.fix는 2차 패스에서 VRAM이 더 터질 수 있으니, 그때 VAE 타일링이 특히 유효합니다.
2) 배치 크기와 배치 카운트 구분
- Batch size는 VRAM에 직접 타격
- Batch count는 반복 횟수라 VRAM 영향이 훨씬 적음
즉 “여러 장”이 필요하면 Batch size를 올리기보다 Batch count로 해결하는 편이 안전합니다.
3) FP16 / BF16 사용
- NVIDIA 대부분 환경에서
fp16은 필수 최적화에 가깝습니다. - BF16은 GPU 지원 여부에 따라 선택.
4) ControlNet/LoRA 동시 사용 줄이기
ControlNet을 2개, 3개 붙이면 VRAM이 빠르게 올라갑니다. VRAM이 부족하면
- ControlNet 개수 축소
- 해상도 낮추고 후처리 업스케일
- 필요한 LoRA만 남기기
같은 전략이 필요합니다.
OOM이 계속 날 때: 재현 가능한 점검 순서
VRAM 부족은 “진짜 VRAM 부족” 외에도 파편화, 설정 꼬임, 드라이버/라이브러리 조합 문제로 악화될 수 있습니다. 아래 순서로 점검하면 원인 분리가 빠릅니다.
1) OOM이 나는 정확한 시점을 로그로 확인
- 시작하자마자 OOM: 모델 로딩/추가 모듈 과다
- 샘플링 중 OOM: 어텐션 메모리(= xFormers 타겟)
- 마지막 저장 직전 OOM: VAE 디코딩(= VAE 타일링 타겟)
2) 동일 프롬프트로 최소 설정부터 올리기
- ControlNet/LoRA 끄고
512x512, batch size1- 스텝
20
여기서 안정적이면 하나씩 옵션을 올리며 “어느 옵션이 VRAM을 폭발시키는지” 찾습니다.
3) GPU 메모리 사용량을 수치로 확인
리눅스라면 다음처럼 확인할 수 있습니다.
watch -n 0.5 nvidia-smi
프로세스가 갑자기 죽거나 시스템 메모리까지 압박이 번지면, 커널 OOM 관점의 분석도 도움이 됩니다: 리눅스 OOM Killer 로그로 메모리 누수 추적하기
4) xFormers가 실제로 적용됐는지 확인
실행 옵션을 넣었더라도, 환경에 따라 fallback이 걸려 적용이 안 되는 경우가 있습니다.
- 콘솔 로그에 xFormers 활성화 메시지 확인
- PyTorch/CUDA 버전 호환성 확인
5) VAE 타일링을 켰는데도 마지막에 죽으면
- 저장 포맷(예: PNG) 자체는 VRAM을 크게 쓰지 않지만, 후처리나 업스케일러가 붙어 있을 수 있습니다.
- 업스케일러를 바꾸거나, 2차 패스 해상도를 조금 낮춰 “임계점” 아래로 내립니다.
실전 추천 조합(8GB 기준)
아래는 “품질과 속도”를 어느 정도 유지하면서 VRAM을 안정화하는 조합입니다.
- xFormers 활성화
fp16사용- batch size
1 768x768또는832x832정도에서 1차 생성- 필요 시 Hires.fix를 쓰되, 2차에서 VAE 타일링 활성화
- ControlNet은 1개부터 시작
6GB 이하라면 VAE 타일링은 사실상 상시 켜는 편이 마음 편한 경우가 많고, 512 기반 2-pass 전략이 더 안전합니다.
마무리: OOM은 “어텐션”과 “VAE”로 나눠서 잡자
Stable Diffusion VRAM 부족은 대개 두 부류로 정리됩니다.
- 샘플링 중 OOM: 어텐션 메모리 문제일 확률이 높고, xFormers가 1순위 해법
- 마지막 디코딩/저장 직전 OOM: VAE 디코딩 문제일 확률이 높고, VAE 타일링이 결정타
이 둘을 함께 적용하면, 같은 GPU로도 해상도/파이프라인 여유가 눈에 띄게 늘어납니다. 이후에는 배치, ControlNet, Hires.fix 같은 “VRAM 가속 페달”을 조심스럽게 밟으면서 자신만의 안정 구간을 찾는 게 가장 효율적입니다.