- Published on
Stable Diffusion VRAM 부족? SDXL 8GB 최적화
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서론
SDXL은 기본 모델 자체가 무겁고, 여기에 해상도와 배치, 샘플러 설정까지 더해지면 8GB VRAM에서 CUDA out of memory가 매우 쉽게 발생합니다. 특히 AUTOMATIC1111 WebUI나 ComfyUI에서 SDXL을 처음 시도하는 경우, 기본값 그대로 1024x1024로 뽑다가 바로 터지는 경험을 많이 합니다.
이 글은 “SDXL을 8GB에서 어떻게든 굴리는 법”을 목표로 합니다. 단순히 옵션을 나열하는 수준이 아니라, 어떤 설정이 VRAM을 얼마나 자극하는지, 그리고 어떤 조합이 현실적으로 가장 성공률이 높은지까지 단계적으로 정리합니다. 로컬 LLM에서 OOM을 줄이기 위해 양자화와 캐시를 조절하듯, 확산 모델도 메모리 병목 지점을 정확히 찌르면 8GB에서도 충분히 실사용 가능합니다. 참고로 OOM 자체를 체계적으로 다루는 사고방식은 이 글도 도움이 됩니다: Transformers 로컬 LLM OOM 해결 - 4bit+KV캐시
SDXL에서 VRAM이 터지는 구조(왜 8GB가 빡센가)
SDXL 파이프라인에서 VRAM을 크게 잡아먹는 덩어리는 대략 아래입니다.
- UNet 추론: 스텝마다 가장 큰 텐서를 만들고 지우는 구간
- VAE: 디코딩 시 피크 메모리 상승(특히 고해상도)
- 텍스트 인코더 2개: SDXL은 텍스트 인코더가 2개라 프롬프트 길이와 배치가 VRAM에 더 민감
- Attention 연산: 해상도에 따라 토큰 수가 늘며 메모리 폭발
- 추가 네트워크: LoRA, ControlNet, IP-Adapter 등은 “한 개만 더”가 생각보다 큼
가장 중요한 규칙은 이것입니다.
- 해상도는 VRAM을 선형이 아니라 “제곱에 가깝게” 압박합니다.
- 배치 크기(
batch size)는 VRAM을 거의 선형으로 밀어 올립니다. - SDXL은
1024x1024를 기본 타깃으로 설계했지만, 8GB에서는 “기본값”이 함정인 경우가 많습니다.
1단계: 실패 확률을 확 줄이는 기본 세팅
여기부터는 “8GB에서 성공률이 높은” 최소 세팅을 먼저 잡고, 이후 품질을 올리는 방식이 좋습니다.
해상도부터 낮춰서 시작하기
- 1차 생성은
832x832또는768x1024같은 타협 해상도로 시작 - 최종은
hires fix나 업스케일 파이프라인으로 해결
SDXL은 1024x1024가 예쁘지만, 8GB에서 ControlNet이나 LoRA를 얹는 순간 급격히 불안정해집니다. 우선 “안 터지는 해상도”를 확보하는 게 우선입니다.
배치 크기와 배치 카운트
batch size는1로 고정- 여러 장 필요하면
batch count로 돌리기(순차 생성)
batch size를 올리면 VRAM이 바로 치솟습니다. 8GB에서는 사실상 1이 정답입니다.
스텝 수와 샘플러
- 스텝은
20내외부터 시작 - 샘플러는
DPM++ 2M Karras계열이 무난
스텝 수는 시간과 약간의 메모리(캐시/버퍼)에 영향을 주지만, 8GB OOM의 1순위 원인은 대개 해상도와 부가 모듈입니다. 스텝을 줄여도 안 되면 다음 단계로 가야 합니다.
2단계: 메모리 절감 옵션(체감 큰 순서)
xFormers 또는 SDPA(Scaled Dot-Product Attention)
Attention 구현을 메모리 효율적인 것으로 바꾸면 피크 VRAM이 크게 내려갑니다.
- PyTorch 2.x 환경에서는 SDPA가 잘 먹히는 경우가 많음
- WebUI는 보통
xformers토글로 제어
설치 예시는 환경에 따라 다르지만, 일반적으로는 아래처럼 확인/설치합니다.
python -c "import torch; print(torch.__version__); print(torch.cuda.is_available())"
python -c "import xformers; print(xformers.__version__)"
xFormers 설치가 꼬이면, PyTorch/CUDA 조합 불일치가 흔한 원인입니다. 이런 류의 “옵션 하나 켰더니 에러”를 다루는 관점은 양자화 글도 유사합니다: PyTorch 2.1 int8 양자화 오류별 해결과 속도
VAE를 타일링 또는 경량 VAE로
VAE 디코딩은 마지막에 한 번이지만 피크를 크게 만들 수 있습니다.
VAE tiling(타일 디코딩)을 켜면 VRAM 피크가 내려가고 대신 속도가 약간 느려질 수 있음- SDXL용 경량 VAE를 쓰는 워크플로우도 있음(환경에 따라 품질/색감 차이 체크 필요)
FP16, BF16, 그리고 --no-half-vae 주의
- 대부분의 8GB 환경에서는 FP16이 기본
- 특정 GPU에서 VAE half 정밀도가 깨지는 경우
--no-half-vae를 쓰지만, 이 옵션은 VRAM을 늘릴 수 있음
즉 “검은 화면/깨짐” 때문에 --no-half-vae를 켜는 순간 8GB에서 OOM이 더 잘 날 수 있습니다. 가능하면 VAE 쪽은 타일링으로 해결하고, 정밀도는 유지하는 편이 안정적입니다.
CPU 오프로딩(최후의 안전망)
- 텍스트 인코더나 일부 모듈을 CPU로 내리면 VRAM은 절약
- 대신 속도는 크게 느려짐
8GB에서 “일단 결과가 나오는 것”이 목표면 유효합니다. 다만 생성 시간이 길어져 작업 효율이 떨어질 수 있습니다.
3단계: SDXL 8GB에서 잘 되는 권장 조합(실전 프리셋)
아래는 “8GB에서 SDXL을 안정적으로 돌리는” 쪽에 무게를 둔 조합입니다.
프리셋 A: 가장 안전(품질 타협)
- 해상도:
832x832 - 배치:
1 - 스텝:
20 - 샘플러:
DPM++ 2M Karras - 옵션: xFormers 또는 SDPA 활성화
- VAE: 타일링 활성화
- LoRA/ControlNet: 일단 끄고 시작
프리셋 B: SDXL 느낌 유지(현실적 타협)
- 해상도:
896x896또는768x1024 - 배치:
1 - 스텝:
25 - 옵션: xFormers 또는 SDPA 활성화
- LoRA: 1개 정도만(가중치 낮게)
- ControlNet: 가능하면 1개만
프리셋 C: 1024x1024 도전(불안정 구간)
- 해상도:
1024x1024 - 배치:
1 - 스텝:
20부터 - 옵션: xFormers 또는 SDPA 필수
- VAE: 타일링 권장
- 추가 모듈: LoRA/ControlNet/IP-Adapter는 “하나씩만” 올리며 테스트
8GB에서 1024는 “옵션을 조금만 과하게 얹어도” 바로 OOM으로 이어집니다. 특히 ControlNet 2개 이상은 대부분 위험 구간으로 봐야 합니다.
4단계: Hires fix와 업스케일을 8GB 친화적으로 쓰는 법
SDXL을 8GB에서 쓰는 핵심 전략은 이겁니다.
- 1차는 낮은 해상도에서 안정적으로 생성
- 업스케일은 타일 기반 또는 2단계로 분리
WebUI Hires fix 팁
Hires steps를 과하게 올리지 않기- 업스케일 배율은
1.5부터 시작 - 업스케일러는 메모리 사용량이 적은 쪽을 우선 선택
타일 업스케일(추천)
타일 업스케일은 VRAM 피크를 분산시켜 8GB에서 성공률이 높습니다. 워크플로우에 따라 Tiled Diffusion류 확장이나 ComfyUI의 타일 노드를 사용합니다.
5단계: OOM을 재현 가능하게 잡는 체크리스트
“어쩌다 되거나 어쩌다 터지는” 상태에서 벗어나려면, 변경을 한 번에 하나씩만 적용하고 피크 VRAM을 관찰해야 합니다.
변경 순서(권장)
- 해상도 낮추기
batch size=1고정- xFormers 또는 SDPA 켜기
- VAE 타일링 켜기
- LoRA 1개 추가
- ControlNet 1개 추가
1024로 올리기
VRAM 관찰 커맨드
리눅스/WSL 환경에서는 다음이 가장 간단합니다.
watch -n 0.5 nvidia-smi
파이썬에서 간단히 현재 메모리 사용량을 찍을 수도 있습니다.
import torch
def vram_mb():
alloc = torch.cuda.memory_allocated() / 1024**2
reserv = torch.cuda.memory_reserved() / 1024**2
return alloc, reserv
print("cuda:", torch.cuda.is_available())
if torch.cuda.is_available():
a, r = vram_mb()
print(f"allocated={a:.1f}MB reserved={r:.1f}MB")
reserved가 높게 유지되는 건 캐싱 전략 때문일 수 있어 “항상 나쁜 것”은 아닙니다. 다만 생성 직후에도 계속 증가만 한다면 설정 조합이나 확장 기능에서 누수가 있는지 의심해볼 만합니다.
6단계: 자주 하는 실수와 회피법
실수 1: SDXL + ControlNet 여러 개 + 1024를 한 번에
8GB에서는 이 조합이 가장 흔한 OOM 트리거입니다. ControlNet은 한 개만 먼저 붙이고, 해상도는 896 이하에서 안정화한 뒤 올리는 편이 낫습니다.
실수 2: 배치 크기를 올려서 “한 번에 여러 장”
batch size는 VRAM을 직격합니다. 여러 장은 순차 생성으로 처리하세요.
실수 3: 문제를 숨기는 해결책만 반복
예를 들어 무조건 CPU 오프로딩만 켜두면 “되긴 되는데 너무 느린” 상태가 됩니다. OOM은 원인을 분해해서 해결해야 합니다. 이 관점은 서버에서 OOMKilled를 잡는 방식과도 유사합니다: EKS CrashLoopBackOff? OOMKilled 진단 7단계
7단계: 8GB에서의 현실적인 목표선
정리하면 8GB에서 SDXL은 “불가능”이 아니라 “운영 방식이 달라야” 합니다.
- 기본 생성은
832또는896에서 안정화 - 최종 해상도는 타일 업스케일이나 2단계 생성으로 달성
- 추가 모듈은 1개씩만 올리며 VRAM 피크를 확인
- xFormers 또는 SDPA, VAE 타일링은 거의 필수 카드
결과적으로 8GB에서도 SDXL 특유의 질감과 프롬프트 반응성을 충분히 누릴 수 있고, 작업 흐름을 “저해상도 생성 + 업스케일”로 설계하면 OOM 스트레스가 크게 줄어듭니다.
부록: 최소 실행 예시(diffusers)
WebUI가 아니라 파이썬에서 SDXL을 직접 돌릴 때, 메모리 최적화 옵션을 포함한 예시는 아래처럼 구성할 수 있습니다. 환경에 따라 동작 옵션이 다르므로 “구조 참고용”으로 보세요.
import torch
from diffusers import StableDiffusionXLPipeline
model_id = "stabilityai/stable-diffusion-xl-base-1.0"
dtype = torch.float16
pipe = StableDiffusionXLPipeline.from_pretrained(
model_id,
torch_dtype=dtype,
variant="fp16",
use_safetensors=True,
)
pipe = pipe.to("cuda")
# 메모리 절감 옵션(지원 여부는 버전마다 다름)
pipe.enable_attention_slicing()
pipe.enable_vae_slicing()
prompt = "cinematic portrait photo, 85mm lens, soft light"
image = pipe(
prompt=prompt,
height=832,
width=832,
num_inference_steps=20,
guidance_scale=5.5,
).images[0]
image.save("sdxl_832.png")
이 코드가 안정적으로 돌아간 뒤에만 896 또는 1024로 올리고, 그 다음에 LoRA나 ControlNet을 단계적으로 추가하는 것이 8GB 최적화의 핵심입니다.