Stable Diffusion with Python 파이썬으로 배우는 확산 모델
Chapter 03 목차
제1부 · 빠른 소개 — 4장

노이즈를 더하고, 다시 걷어내고

DDPM의 심장부로 내려간다. 이미지를 가우시안 노이즈로 망가뜨리는 순방향 확산, 그 과정을 신경망이 되감는 역방향 확산 — 그리고 그 사이를 잇는 수학.

DDPM Forward Diffusion Reverse Process Reparameterization UNet

Section 01이미지에서 노이즈로

하나의 이미지를 물 한 컵으로 생각하자. 충분한 노이즈(잉크)를 떨어뜨리면 결국 이미지(물)는 완전한 노이즈 이미지(잉크물)로 변한다. 이미지 x₀는 거의 가우시안 노이즈 이미지 xₜ로 체계적으로 변환될 수 있다.

이미지가 순수 노이즈가 될 때까지 가우시안 노이즈를 도입하는, 사전 정의된 순방향 확산 과정 q를 사용한다. 이 과정은 q(xₜ | xₜ₋₁)로 표시되며, 역방향 과정 pθ(xₜ₋₁ | xₜ)는 아직 알려지지 않았다.

Forward Diffusion — single step
q(xₜ | xₜ₋₁) := N( xₜ ; √(1−βₜ)·xₜ₋₁ , βₜ·I )
q(xₜ|xₜ₋₁) 이전 이미지가 주어졌을 때 노이즈 이미지 xₜ를 관찰할 조건부 확률 · := 확산 순방향 과정은 결정론적이므로 ~ 대신 정의 기호 사용 · βₜ 단계 t의 노이즈 분산 · √(1−βₜ)·xₜ₋₁ 새 분포의 평균 · I 항등 행렬 — RGB 채널마다 노이즈 분산을 독립 적용
순방향 확산 — 이미지가 노이즈로 STEP 01 / 6
space 재생 · → 다음 · R 리셋
Intuition — 무한할 필요는 없다 이미지는 단계를 무한대로 보낼 때만 완전한 등방성 가우시안 분포가 된다. 하지만 그것은 불필요하다. 원래 DDPM 논문은 단계 수를 1,000으로 두었고, 이후 Stable Diffusion에서는 20~50단계로 줄었다. 단 16단계만으로도 이미지는 거의 등방성 노이즈로 변한다.

Section 02재매개변수화 트릭

연쇄 과정으로 단계 t의 노이즈 이미지를 계산하려면 1부터 t−1까지 전부 거쳐야 한다 — 비효율적이다. 재매개변수화(reparameterization) 트릭은 이 연쇄를 한 단계 계산으로 압축한다.

평균 μ, 분산 σ²인 가우시안 z ~ N(μ, σ²)ε ~ N(0,1)을 써서 z = μ + σε로 다시 쓸 수 있다. 이 발상을 확산 과정에 적용한다.

One-shot noisy image at step t
αₜ = 1 − βₜ · ᾱₜ = ∏ αᵢ ( i = 1 … t )
xₜ = √ᾱₜ · x₀ + √(1−ᾱₜ) · ε
αₜ 편의를 위해 정의한 값 (1 − βₜ) · ᾱₜ α들의 누적곱 · x₀ 노이즈 없는 원본 이미지 · ε N(0,1) 가우시안 노이즈 · 이제 어떤 단계 t의 이미지든 한 번의 계산으로 x₀에서 직접 생성 — 훈련 성능이 크게 향상된다
재매개변수화 — 임의 단계의 노이즈 이미지 생성
import numpy as np
from itertools import accumulate

def get_product_accumulate(numbers):
    return list(accumulate(numbers, lambda x, y: x * y))

image = plt.imread("dog.png")
image = image * 2 - 1          # [0,1] -> [-1,1]

num_iterations, beta = 16, 0.05
betas       = [beta] * num_iterations
alpha_list  = [1 - b for b in betas]
alpha_bar   = get_product_accumulate(alpha_list)

target_index = 5
x_target = (
    np.sqrt(alpha_bar[target_index]) * image +
    np.sqrt(1 - alpha_bar[target_index]) * np.random.normal(0, 1, image.shape)
)

Section 03노이즈에서 이미지로: 훈련

이미지에 노이즈를 더하는 솔루션 — 순방향 확산 — 은 손에 넣었다. 반대로 노이즈에서 이미지를 복구하려면 역방향 단계 pθ(xₜ₋₁ | xₜ)를 구현할 방법이 필요하다. 그런데 이 단계는 추가적인 도움 없이는 다루기 어렵거나 계산 불가능하다.

해법은 신경망이다. 노이즈 데이터와 모든 노이즈 단계 데이터가 있으니, 이 과정을 역전시키는 신경망 — 일반적으로 UNet — 을 훈련할 수 있다.

UNet 훈련 — 노이즈를 예측하고 손실을 계산 STEP 01 / 5
space 재생 · → 다음 · R 리셋
DDPM — simplified loss
L_simple(θ) := E[ ‖ ε − εθ( xₜ , t ) ‖² ]
ε 순방향 확산에서 실제로 더한 노이즈 (실측 정답) · εθ(xₜ, t) UNet이 예측한 노이즈 · t time step — 모든 노이즈 제거 단계가 같은 가중치를 공유하므로, t를 입력해 단계를 인식하게 한다 · 예측 노이즈와 실제 노이즈의 MSE를 최소화하도록 가중치를 갱신한다
PyTorch — 노이즈 예측 손실
import torch
import torch.nn as nn

# noise 는 이미지 x_t 모양의 ε ~ N(0,1)
noise = torch.randn_like(x_t)

# x_t 는 단계 t 의 노이즈 이미지, time_step 과 함께 입력
predicted_noise = model(x_t, time_step)
loss = nn.MSELoss(noise, predicted_noise)

# 역방향 가중치 전파 ...
Key — UNet은 무엇을 예측하는가 DDPM 논문에서 원래 Diffusion 모델은 분산을 고정하고, 가우시안 분포의 평균 μ만을 신경망이 학습할 매개변수로 둔다. 실제로는 평균 대신 제거할 노이즈 ε를 직접 예측하도록 단순화하며, 이것이 위 손실식의 핵심이다.

Section 04샘플링 과정

모델에서 이미지를 샘플링한다는 것 — 역방향 확산으로 이미지를 생성하는 단계는 이렇게 진행된다. 먼저 평균 0, 분산 1의 완전한 가우시안 노이즈 xₜ ~ N(0,1)를 시작 이미지로 삼는다. 그리고 t = T에서 t = 1까지 루프한다.

Reverse sampling step
xₜ₋₁ = (1/√αₜ)·( xₜ − ((1−αₜ)/√(1−ᾱₜ))·εθ(xₜ,t) ) + √(1−αₜ)·z
αₜ, ᾱₜ βₜ에서 나온 알려진 숫자 · εθ(xₜ,t) UNet이 생성한 노이즈 — 유일하게 모델이 필요한 항 · z t>1이면 새 가우시안 노이즈, t=1이면 0 · √(1−αₜ)·z 노이즈 제거 과정에 다시 더해지는 노이즈
Intuition — 왜 노이즈를 다시 더할까 샘플링 식 끝의 √(1−αₜ)·z 항은 신비롭게 보인다. 노이즈를 제거하는 과정에 노이즈를 다시 더하다니. 원래 논문은 이를 설명하지 않지만, 연구자들은 이 추가 노이즈가 생성된 이미지의 품질을 크게 향상시킨다는 것을 발견했다. 루프가 끝나면 최종 이미지 x₀가 반환된다.

Section 05분류기 가이던스

지금까지의 생성 과정은 무작위 가우시안 노이즈만을 입력으로 받아, 훈련 데이터셋을 기반으로 무작위로 이미지를 만든다. 하지만 우리는 가이드된 생성을 원한다 — "dog"라고 입력하면 개가 든 이미지가 나와야 한다.

2021년 OpenAI의 Dhariwal과 Nichol은 논문 "Diffusion Models Beat GANs on Image Synthesis"에서 분류기 가이던스를 제안했다. 훈련 단계에서 분류 레이블 — 더 나아가 텍스트 설명 임베딩 — 을 함께 제공하여, 무엇을 그릴지 모델을 안내한다.

ConceptUNet의 세 입력

노이즈 이미지 xₜ — 현재 단계의 노이즈가 있는 이미지 데이터.

time step t — 노이즈 제거가 어느 단계에서 일어나는지 알려준다.

텍스트 임베딩 — CLIP 모델이 생성한 조건부 텍스트 임베딩. 이 추가 입력이 이미지 생성을 텍스트로 가이드한다.

Key — 다음 장으로 DDPM은 사실적 이미지를 만들 수 있지만 문제는 성능이다. 훈련도 느리고 샘플링도 느리며, 픽셀 공간 추론은 계산 비용이 크다. 다음 장 — Stable Diffusion은 천재적인 방식으로 이 속도와 계산 문제를 모두 해결한다. 그 열쇠는 latent space다.