Stable Diffusion을 이해하려면 “노이즈를 지우는 법을 배운다"는 직관에서 시작하는 것이 빠르다. 깨끗한 이미지에 노이즈를 단계적으로 추가하는 과정은 간단하다. Stable Diffusion은 그 반대 방향, 즉 완전한 노이즈에서 깨끗한 이미지로 복원하는 과정을 신경망으로 학습한다.
확산 모델의 원리
순방향 확산 (Forward Diffusion)
학습 데이터(깨끗한 이미지)에 가우시안 노이즈를 T 스텝에 걸쳐 조금씩 추가한다. T = 1000이면 1000번에 걸쳐 점점 더 많은 노이즈를 입힌다. 마지막 스텝에서는 원본 이미지 정보가 완전히 사라지고 순수한 노이즈만 남는다.
x₀ (깨끗한 이미지) → x₁ → x₂ → ... → xₜ (순수 노이즈)
각 스텝의 노이즈 강도는 β 스케줄(noise schedule)로 제어한다. β가 작으면 천천히, 크면 빠르게 노이즈가 쌓인다.
수식으로는 q(xₜ | xₜ₋₁) = N(xₜ; √(1-βₜ)xₜ₋₁, βₜI) 다. xₜ는 이전 스텝 xₜ₋₁에 약간의 노이즈를 더한 것이다. 중요한 특성은 임의의 스텝 t에서의 noisy 이미지를 x₀에서 직접 샘플링할 수 있다는 것이다. 매 스텝을 순서대로 계산할 필요가 없어 학습이 효율적이다.
역방향 확산 (Reverse Diffusion)
모델이 학습하는 것은 역방향 프로세스다. p_θ(xₜ₋₁ | xₜ), 즉 노이즈가 있는 이미지 xₜ에서 조금 덜 노이즈가 있는 xₜ₋₁을 예측한다.
직접 xₜ₋₁을 예측하는 것보다 xₜ에 추가된 노이즈 자체를 예측하도록 학습하는 것이 수렴이 안정적이라는 것이 DDPM(Denoising Diffusion Probabilistic Models) 논문의 핵심 기여다. 실제로 추가된 노이즈 ε와 모델이 예측한 노이즈 ε_θ 사이의 MSE(평균 제곱 오차)를 줄이는 방향으로 학습한다.
L = E[||ε - ε_θ(xₜ, t)||²]
추론 시에는 순수 노이즈 xₜ에서 시작해 모델이 예측한 노이즈를 빼는 과정을 T번 반복하면 깨끗한 이미지 x₀가 나온다.
잠재 확산 모델 (Latent Diffusion Model)
DDPM을 픽셀 공간에서 직접 실행하면 512×512 이미지에서 3×512×512 = 786,432차원의 데이터를 다뤄야 한다. 연산량이 막대하고 T번 반복하므로 실용적이지 않다.
Stable Diffusion이 채택한 **LDM(Latent Diffusion Model)**은 픽셀 대신 잠재 공간(latent space)에서 확산을 수행한다. 잠재 공간은 픽셀 공간의 압축된 표현이다. 512×512 이미지가 64×64 잠재 벡터로 압축되면 연산량이 64분의 1로 줄어든다.
이 압축을 담당하는 것이 VAE(Variational Autoencoder)다.
아키텍처 구성요소
VAE (Variational Autoencoder)
인코더와 디코더로 구성된다. 인코더는 픽셀 이미지를 잠재 벡터로 압축하고, 디코더는 잠재 벡터를 다시 픽셀 이미지로 복원한다.
인코더: 512×512×3 → 64×64×4
디코더: 64×64×4 → 512×512×3
확산 과정은 64×64×4 잠재 공간에서 진행된다. 최종 결과물은 VAE 디코더가 잠재 벡터를 픽셀 이미지로 변환해 출력한다. VAE는 학습 전에 미리 학습되어 있고, 확산 과정 중에는 고정(frozen)된다.
U-Net (노이즈 예측 네트워크)
잠재 공간에서 노이즈를 예측하는 핵심 네트워크다. 이름 그대로 U자 형태의 인코더-디코더 구조를 가지며, 스킵 커넥션(skip connection)으로 인코더의 특징을 디코더에 전달한다.
U-Net이 받는 입력은 세 가지다.
- noisy 잠재 벡터 xₜ — 현재 노이즈가 섞인 상태
- 타임스텝 t — 현재 몇 번째 스텝인지 (sinusoidal embedding으로 인코딩)
- 조건 벡터 — 텍스트 프롬프트 등의 조건
U-Net 내부에는 어텐션 레이어가 있다. 셀프 어텐션(self-attention)은 이미지 내부의 관계를, 크로스 어텐션(cross-attention)은 이미지와 텍스트 조건의 관계를 학습한다. “빨간 사과"라는 프롬프트가 이미지의 특정 영역에 반영되는 것이 크로스 어텐션의 역할이다.
텍스트 인코더 (CLIP)
텍스트 프롬프트를 U-Net이 이해할 수 있는 벡터로 변환한다. SD 1.x/2.x는 OpenAI의 CLIP(Contrastive Language-Image Pre-Training) 텍스트 인코더를 사용한다.
CLIP은 텍스트와 이미지를 같은 임베딩 공간에 정렬하도록 학습된 모델이다. “개"라는 텍스트와 개 이미지의 임베딩이 가까워지도록 학습했기 때문에, CLIP 텍스트 인코더가 만든 벡터는 이미지 생성에 잘 맞는 표현을 갖는다.
프롬프트 → CLIP 인코더 → 토큰 임베딩 시퀀스 → U-Net 크로스 어텐션에 주입
전체 추론 흐름을 정리하면 다음과 같다.
텍스트 프롬프트
↓ CLIP 인코더
텍스트 임베딩
↓
순수 노이즈 (64×64×4) ──→ U-Net (T번 반복) ──→ 깨끗한 잠재 벡터
↑ 타임스텝 t ↓ VAE 디코더
최종 이미지 (512×512×3)
샘플링 방법
T = 1000 스텝을 전부 밟으면 이미지 하나를 생성하는 데 수십 초가 걸린다. 실용적인 스텝 수로 줄이는 것이 샘플러(sampler)의 역할이다.
DDIM (Denoising Diffusion Implicit Models)
DDPM의 확률적(stochastic) 샘플링 대신 결정론적(deterministic) 방식을 사용한다. 같은 시드와 프롬프트로 항상 같은 이미지가 나온다. 50 스텝으로도 DDPM 1000 스텝에 준하는 품질이 나온다.
DPM++ (2M, SDE)
수치 ODE(상미분방정식) 솔버를 활용해 2차 이상의 근사를 사용한다. 20~30 스텝으로 높은 품질이 나와 현재 가장 많이 사용된다. 2M은 2차 다단계(multi-step), SDE는 확률적 미분방정식을 추가해 다양성을 높인 변형이다.
CFG (Classifier-Free Guidance)
텍스트 조건을 얼마나 강하게 반영할지 결정하는 파라미터다. 모델은 조건 있는 예측과 조건 없는 예측 두 가지를 함께 수행하고, CFG 스케일(guidance scale)로 가중합한다.
ε_final = ε_uncond + cfg_scale × (ε_cond - ε_uncond)
CFG = 7이면 텍스트를 강하게 따른다. CFG = 1이면 텍스트 무시에 가깝다. CFG가 너무 높으면 과포화되고 디테일이 깨진다. 일반적으로 7~12 사이를 쓴다.
파인튜닝 기법
사전 학습된 Stable Diffusion을 특정 스타일, 특정 인물, 특정 도메인에 맞게 조정하는 방법들이다.
Textual Inversion
새로운 단어(토큰)를 CLIP 임베딩 공간에 추가한다. 예를 들어 <my-cat>이라는 토큰이 내 고양이 이미지를 표현하도록 학습한다. U-Net 가중치는 변경하지 않고, 텍스트 임베딩 벡터 하나만 학습한다. 파일 크기가 작고(수십 KB), 학습이 빠르다. 다만 표현력이 제한적이다.
DreamBooth
3~30장의 특정 대상 이미지로 U-Net 전체를 파인튜닝한다. “희귀 단어”(예: sks dog)를 해당 대상과 연결한다. prior preservation loss를 추가해 파인튜닝 전 일반적인 개념(개, 사람 등)이 망각되는 것을 방지한다. Textual Inversion보다 품질이 높지만 모델 전체를 저장해야 해 파일이 크다(수 GB).
LoRA (Low-Rank Adaptation)
원래 LLM 파인튜닝 기법인 LoRA를 확산 모델에 적용한다. U-Net의 어텐션 레이어 가중치 행렬을 두 개의 저랭크(low-rank) 행렬의 곱으로 근사해 학습한다.
W' = W + ΔW = W + A × B
W는 원본 가중치(고정), A와 B는 작은 랭크 r의 행렬(학습). 랭크 r = 4이면 4096×4096 행렬 대신 4096×4 + 4×4096을 학습한다. 파일 크기가 수십~수백 MB로 작고, 학습 속도가 빠르다. 현재 커뮤니티에서 가장 널리 쓰이는 파인튜닝 방식이다. 여러 LoRA를 가중치 합산으로 동시에 적용할 수 있다.
ControlNet
생성 이미지의 구도, 포즈, 깊이감, 엣지를 입력 조건으로 제어한다. U-Net의 인코더 부분을 복제해 컨트롤 신호를 받는 별도 네트워크를 만들고, 원본 U-Net에 출력을 더한다.
입력 조건 종류:
- Canny Edge: 엣지 맵 → 구도 제어
- Depth: 깊이 맵 → 원근감 제어
- OpenPose: 관절 좌표 → 인물 포즈 제어
- Scribble: 손 그림 → 대략적인 구성 제어
- Normal Map: 법선 맵 → 표면 질감 제어
ControlNet 없이 프롬프트만으로 구도나 포즈를 정확히 제어하기 어렵다는 한계를 해결한다.
IP-Adapter
이미지를 프롬프트처럼 조건으로 사용한다. 레퍼런스 이미지의 스타일이나 피사체를 다른 이미지에 적용하는 Image Prompt 개념이다. CLIP 이미지 인코더로 레퍼런스 이미지를 임베딩하고, 별도 크로스 어텐션 레이어로 U-Net에 주입한다.
발전 과정
SD 1.x (2022)
Runway와 LMU Munich의 Rombach 등이 공개했다. LAION-5B 데이터셋으로 학습. 512×512 기본 해상도. CLIP ViT-L/14 텍스트 인코더. 사람 손, 텍스트 렌더링 품질이 낮은 한계가 있었다.
SD 2.x (2022)
텍스트 인코더를 OpenCLIP ViT-H로 교체해 성능을 높였다. 768×768 기본 해상도. 그러나 SD 1.x 호환 LoRA/모델이 작동하지 않아 커뮤니티가 분리됐다.
SDXL (2023)
두 개의 텍스트 인코더(OpenCLIP ViT-G + CLIP ViT-L)를 함께 사용한다. 기본 해상도 1024×1024. Base 모델과 Refiner 모델로 분리해 1단계에서 전체 구도를 잡고 2단계에서 디테일을 보완한다. 파라미터 수가 3.5B로 이전 모델(1B)의 3배 이상이다.
SD3 (2024)
Diffusion Transformer(DiT) 아키텍처를 도입했다. U-Net 대신 Transformer 블록을 사용한다. 텍스트 렌더링 품질이 크게 향상됐다. 멀티모달 확산 트랜스포머(MMDiT)로 텍스트와 이미지 토큰을 함께 처리한다.
FLUX (2024, Black Forest Labs)
SD의 원 개발팀(Rombach 등)이 Stability AI를 나와 창업한 Black Forest Labs의 모델이다. Flow Matching 기반으로 DDPM과 다른 학습 방식을 사용한다. FLUX.1-dev와 FLUX.1-schnell(蒸留 버전)이 공개돼 있다. 텍스트 렌더링, 인물 사실성, 프롬프트 추종력이 SD3 대비 전반적으로 높다.
Flow Matching (FLUX의 기반)
DDPM은 노이즈 예측(ε-prediction)을 통해 역방향 확산을 학습한다. Flow Matching은 다른 관점에서 접근한다. 노이즈 분포에서 데이터 분포로의 **흐름(velocity field)**을 학습한다. 임의의 두 점 사이를 직선으로 잇는 경로(Rectified Flow)를 학습해 더 적은 샘플링 스텝으로 고품질 이미지를 생성한다.
DDPM: 복잡한 곡선 경로 → 많은 스텝 필요
Flow: 직선에 가까운 경로 → 적은 스텝으로 가능
트레이드오프
샘플링 스텝을 줄이면 속도가 빠르지만 품질이 떨어진다. CFG를 높이면 프롬프트 추종력이 높아지지만 다양성이 줄고 과포화 현상이 생긴다. LoRA 여러 개를 동시에 적용하면 가중치 간섭으로 품질이 떨어질 수 있다.
VAE가 병목이 되기도 한다. SD 1.x의 기본 VAE는 채도 표현이 약했고, 커뮤니티에서 finetuned VAE(EMA VAE, SDXL VAE)로 교체하는 것이 일반적이 됐다.
모델 크기와 VRAM 요구량도 트레이드오프다. SD 1.5는 4GB VRAM으로 동작하지만 SDXL은 8GB 이상, FLUX는 16GB 이상이 필요하다. vram-calculator 같은 도구로 추론 전에 메모리를 예측하는 것이 실용적이다.