Published on

Stable Diffusion 4K 생성, VRAM OOM 없이 끝내기

Authors

서로 다른 GPU에서 Stable Diffusion로 4K(3840x2160) 이미지를 만들다 보면, 프롬프트나 샘플러보다 먼저 한계에 부딪히는 건 대개 VRAM입니다. 특히 고해상도에서 latent 텐서가 커지고, UNet의 어텐션이 해상도에 따라 메모리를 폭발적으로 먹으면서 OOM이 쉽게 발생합니다.

이 글은 “4K를 한 번에 뽑기”가 아니라, VRAM OOM 없이 4K 결과물을 얻는 방법을 목표로 합니다. 핵심은 다음 3가지를 조합하는 것입니다.

  • 저해상도에서 안정적으로 생성하고
  • 업스케일을 여러 단계로 분리하며
  • 필요한 구간만 타일링해서 메모리를 분산

이미 OOM 자체를 줄이는 옵션(xFormers, SDPA, VAE 타일링 등)을 정리한 글도 있으니, 기본 최적화는 아래 글을 함께 참고하면 좋습니다.


왜 4K에서 VRAM이 터질까

1) UNet 어텐션 메모리의 비선형 증가

Stable Diffusion의 병목은 대개 UNet 내부의 Self-Attention / Cross-Attention입니다. 해상도가 올라가면 토큰 수가 증가하고, 어텐션은 토큰 간 상호작용 때문에 메모리가 급격히 늘어납니다.

  • 1024x1024도 이미 무겁지만
  • 4K는 면적 기준으로 1024 대비 약 8배 이상
  • “한 번에 4K latent”는 실무적으로 비효율적입니다

2) VAE 디코딩이 생각보다 무겁다

생성된 latent를 RGB로 복원하는 VAE 디코딩도 고해상도에서 VRAM을 많이 씁니다. 그래서 VAE 타일링이 고해상도 워크플로에서 매우 중요합니다.

3) 배치, CFG, 스텝이 겹치면 즉시 한계 도달

  • batch size를 2 이상으로 올리거나
  • CFG를 과하게 올리거나
  • step을 과도하게 늘리면

해상도 증가와 곱해지면서 OOM이 빨라집니다.


결론부터: OOM 없이 4K 만드는 권장 파이프라인

아래 파이프라인이 가장 재현성 좋습니다.

  1. 기본 생성은 768 또는 1024 정사각(또는 832x1216 같은 중간 해상도)에서 수행
  2. Hi-Res Fix는 1.5배 이하로만(과도한 2배는 위험)
  3. 업스케일은 전용 업스케일러로 분리(4x UltraSharp, ESRGAN, SwinIR 등)
  4. 최종 단계에서 tile-based upscaling 또는 tile-based diffusion 적용
  5. VAE 디코딩은 VAE 타일링으로 처리

즉, “확산 단계에서 4K를 직접 다루는 구간”을 최소화하는 게 핵심입니다.


방법 1: WebUI 기준 안정적인 4K 레시피

A) 1차 생성: 768 또는 1024에서 구도 확정

  • Width/Height: 768x1024 또는 1024x1024
  • Steps: 20~30
  • Sampler: DPM++ 2M Karras 계열 선호
  • Batch size: 1

구도와 주제(포즈, 배경, 조명)를 여기서 확정합니다.

B) Hi-Res Fix는 “살짝만”

Hi-Res Fix는 편하지만 VRAM을 크게 잡아먹습니다. 따라서 다음을 권장합니다.

  • Upscale by: 1.2~1.5
  • Hires steps: 10~15
  • Denoising strength: 0.35~0.55

여기서 1536x2048 같은 중간 결과를 얻어두면 이후 업스케일이 안정적입니다.

C) 4K는 업스케일러로 만들고, 디테일만 타일로 보강

  • 업스케일러(예: 2x, 4x)로 목표 해상도 근처까지 올림
  • 이후 타일 기반으로 디테일 복원(타일 디퓨전, 타일 업스케일 등)

이 방식은 VRAM이 8GB여도 성공 확률이 높습니다.


방법 2: Diffusers로 “4K 결과물”을 안정적으로 얻는 코드

아래 코드는 저해상도 생성 → 업스케일 → 타일 단위로 디테일 보강의 뼈대를 보여줍니다. 환경에 따라 모델/스케줄러/업스케일러는 바꿔 끼우면 됩니다.

1) 저해상도 생성(메모리 최적화 포함)

import torch
from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler

model_id = "runwayml/stable-diffusion-v1-5"

device = "cuda"
dtype = torch.float16

pipe = StableDiffusionPipeline.from_pretrained(
    model_id,
    torch_dtype=dtype,
    safety_checker=None,
    requires_safety_checker=False,
)

pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
pipe = pipe.to(device)

# 메모리 최적화 옵션들
pipe.enable_attention_slicing()          # 속도는 느려지지만 VRAM 절감
pipe.enable_vae_slicing()                # VAE 메모리 절감
pipe.enable_xformers_memory_efficient_attention()  # 설치되어 있을 때만

prompt = "cinematic portrait, soft rim light, 35mm, ultra detailed"

with torch.inference_mode():
    img = pipe(
        prompt,
        width=768,
        height=1024,
        num_inference_steps=28,
        guidance_scale=6.5,
    ).images[0]

img.save("base_768x1024.png")

여기서 중요한 건, 처음부터 4K width/height를 넣지 않는 것입니다.

2) 업스케일(확산이 아닌 SR로 1차 확대)

실전에서는 Real-ESRGAN, SwinIR, 4x-UltraSharp 같은 업스케일러를 많이 씁니다. 아래는 예시용으로 PIL 리사이즈만 보여주되, 파이프라인 상 “확산 단계와 분리”하는 게 포인트입니다.

from PIL import Image

img = Image.open("base_768x1024.png")

# 예시: 2배 업스케일(실전은 ESRGAN 계열 권장)
up = img.resize((img.width * 2, img.height * 2), resample=Image.LANCZOS)
up.save("up_1536x2048.png")

이제 1536x2048 같은 중간 결과를 얻었습니다. 목표가 3840x2160이라면 종횡비가 다르므로, 다음 중 하나를 선택합니다.

  • 크롭을 염두에 두고 16:9로 생성 단계부터 설계
  • 업스케일 후 캔버스 확장(outpainting)로 16:9 맞추기

방법 3: 16:9 4K를 위한 실전 설계(처음부터 비율 맞추기)

4K는 보통 16:9입니다. 인물 사진을 1024x1024로 만들고 4K로 늘리면, 결국 크롭에서 손해가 납니다. 따라서 아래처럼 초기부터 16:9 근처 해상도로 설계하는 게 유리합니다.

권장 시작 해상도 예시

  • 832x468 (가벼움)
  • 1152x648 (균형)
  • 1344x768 (VRAM 여유 있을 때)

이후 Hi-Res Fix 1.3~1.5배, 업스케일러 2배, 마지막 타일 보강으로 4K에 도달합니다.


타일링을 어디에 적용해야 OOM이 줄어드나

타일링은 크게 두 영역에서 효과가 있습니다.

1) VAE 타일링(디코딩 단계)

고해상도에서 latent를 RGB로 바꾸는 순간 VRAM이 튀는 케이스가 많습니다. 이때 VAE 타일링을 켜면 “디코딩을 조각내서” 처리합니다.

  • 장점: 품질 손실이 거의 없고 OOM 방지에 직결
  • 단점: 속도 저하

2) 타일 디퓨전(디테일 보강 단계)

업스케일 후 디테일이 뭉개졌다면, 전체 4K에 확산을 다시 돌리는 대신 타일 단위로만 부분 확산을 적용합니다.

  • 장점: 4K 전체 UNet 메모리를 피할 수 있음
  • 단점: 타일 경계(seam) 관리가 필요

타일 경계는 overlap(겹침)과 블렌딩으로 해결합니다.


OOM을 피하는 체크리스트(우선순위 순)

1) 해상도 전략부터 바꿔라

  • 4K를 “생성 해상도”로 두지 말고 “결과 해상도”로 두기
  • 생성은 768~1344 폭에서 시작

2) batch size는 1로 고정

고해상도에서 batch는 VRAM을 직선적으로 잡아먹습니다.

3) xFormers 또는 SDPA 사용

환경에 따라 효과가 크며, 특히 어텐션 메모리에서 차이가 납니다. 관련 옵션과 함정은 아래 글을 참고하세요.

4) VAE를 가볍게(또는 타일링)

  • vae slicing 또는 vae tiling
  • 필요하면 더 가벼운 VAE로 교체

5) FP16 또는 BF16 사용

  • NVIDIA consumer GPU는 FP16이 일반적
  • Ampere 이상에서 BF16이 안정적인 경우도 있음

6) ControlNet, IP-Adapter를 “필요한 것만”

ControlNet을 여러 개 동시에 쓰면 고해상도에서 급격히 무거워집니다. 4K 파이프라인에서는

  • 1차 구도 확정 단계에서만 사용
  • 업스케일 단계에서는 최소화

같은 방식이 안전합니다.


흔한 실패 패턴과 처방

패턴 A: 1024에서 잘 되는데 2048부터 OOM

  • Hi-Res Fix 배율을 낮추고
  • 업스케일러로 확대한 뒤
  • 타일 디퓨전으로 디테일만 보강

패턴 B: 생성은 되는데 저장(디코딩)에서 OOM

  • VAE 타일링 또는 VAE slicing이 정답인 경우가 많습니다.

패턴 C: 타일링 후 경계가 보임

  • 타일 overlap을 늘리고
  • 블렌딩 마스크를 부드럽게
  • 디노이즈 강도를 낮춰 경계 변형을 줄이기

추천 운영 팁: VRAM 여유를 “품질”에 쓰는 법

OOM을 피하는 목적이 단지 생존이 아니라면, 확보한 VRAM 여유를 다음에 투자하는 게 체감이 큽니다.

  • 업스케일 후 타일 디퓨전에서 step을 조금 늘리기
  • 디테일 전용 LoRA를 “마지막 보강 단계”에만 적용
  • 얼굴/손 같은 취약 부위는 inpaint로 국소 개선

마무리

Stable Diffusion에서 4K를 OOM 없이 만드는 가장 현실적인 해법은, 4K를 확산 모델의 입력 해상도로 고집하지 않는 것입니다. 저해상도에서 구도와 의미를 확정하고, 업스케일을 분리한 뒤, 필요한 구간만 타일 기반으로 디테일을 복원하면 8GB~12GB급 GPU에서도 4K 결과물을 충분히 안정적으로 얻을 수 있습니다.

만약 지금도 OOM이 잦다면, 먼저 xFormers 또는 SDPA, VAE 타일링 같은 “기본 최적화”부터 정리한 뒤 파이프라인을 위 방식으로 재구성해 보세요.