들어가며: 왜 DDPM인가?
2020년 NeurIPS에서 발표된 “Denoising Diffusion Probabilistic Models” (Ho et al., 2020)은 이미지 생성 분야의 판도를 완전히 뒤바꾼 논문이다. 이 논문이 등장하기 전까지 이미지 생성의 왕좌는 GAN(Generative Adversarial Networks)이 차지하고 있었다. 그러나 GAN은 학습 불안정성, 모드 붕괴(mode collapse), 하이퍼파라미터에 대한 민감성 등 고질적인 문제를 안고 있었다.
DDPM은 열역학에서 영감을 받은 확산 과정(diffusion process)을 활용하여, 순수한 가우시안 노이즈로부터 고품질 이미지를 단계적으로 복원하는 방법을 제안했다. 이 아이디어는 이후 Stable Diffusion, DALL-E 2, Midjourney 등 현재 우리가 사용하는 거의 모든 이미지 생성 모델의 이론적 토대가 되었다.
DDPM은 단순히 하나의 생성 모델이 아니라, GAN 이후 생성 모델 연구의 새로운 패러다임을 연 논문이다.
논문 기본 정보
| 항목 | 내용 |
|---|---|
| 제목 | Denoising Diffusion Probabilistic Models |
| 저자 | Jonathan Ho, Ajay Jain, Pieter Abbeel |
| 소속 | UC Berkeley |
| 학회 | NeurIPS 2020 |
| arXiv | arXiv:2006.11239 |
| 인용 수 | 15,000+ (2026년 기준) |
| 코드 | github.com/hojonathanho/diffusion |
핵심 기여 (Key Contributions)
DDPM의 핵심 기여를 정리하면 다음과 같다:
-
확산 모델의 실용화: 기존에 이론적으로만 존재하던 확산 확률 모델(Sohl-Dickstein et al., 2015)을 실제로 고품질 이미지를 생성할 수 있는 수준으로 끌어올렸다.
-
단순화된 학습 목적 함수: 복잡한 변분 하한(variational lower bound)을 단순한 노이즈 예측 MSE 손실로 대체하여 학습을 크게 안정화했다.
-
GAN에 필적하는 생성 품질: FID(Frechet Inception Distance) 기준으로 당시 GAN 기반 모델들과 경쟁할 수 있는 이미지 품질을 달성했다.
-
안정적인 학습 과정: GAN과 달리 적대적 학습이 필요 없어 학습이 매우 안정적이며, 모드 붕괴 문제가 발생하지 않는다.
배경 지식: 확산 과정이란?
확산 모델을 이해하려면 두 가지 과정을 알아야 한다.
Forward Process (확산 과정)
원본 이미지에 점진적으로 가우시안 노이즈를 추가하여 완전한 노이즈로 만드는 과정이다. 물리학에서 잉크 한 방울이 물속에서 서서히 퍼져나가는 것과 같은 원리다.
각 시간 단계 에서 노이즈가 추가되는 과정은 다음과 같다:
여기서 각 항의 의미는:
– : 시간 단계 에서의 노이즈가 추가된 이미지
– : 이전 단계의 이미지
– : 시간 단계 에서의 노이즈 스케줄 (0에 가까운 작은 값에서 시작하여 점점 커짐)
– : 이전 단계 이미지의 스케일링 계수 (노이즈가 추가될수록 원본 신호가 줄어듦)
– : 단위 행렬 (각 픽셀에 독립적으로 노이즈 추가)
Reparameterization Trick
DDPM의 중요한 기법 중 하나는 임의의 시간 단계 로 한 번에 점프할 수 있다는 것이다. , 로 정의하면:
이를 재매개변수화(reparameterization)하면:
여기서:
– : 원본 이미지 에 곱해지는 계수 (시간이 지날수록 0에 가까워짐)
– : 노이즈 에 곱해지는 계수 (시간이 지날수록 1에 가까워짐)
– : 표준 가우시안 노이즈
이 reparameterization 덕분에 학습 시 1부터 까지 순차적으로 노이즈를 추가할 필요 없이, 임의의 를 샘플링하여 바로 를 얻을 수 있다. 이것이 학습 효율의 핵심이다.
Reverse Process (역확산 과정)
완전한 노이즈에서 출발하여 단계적으로 노이즈를 제거해 원본 이미지를 복원하는 과정이다. 이것이 바로 신경망이 학습해야 하는 부분이다.
여기서:
– : 파라미터 를 가진 신경망이 모델링하는 역확산 분포
– : 신경망이 예측하는 평균값 (이전 단계 이미지의 추정치)
– : 분산 (DDPM에서는 고정값 사용)
방법론 상세 분석
아키텍처: U-Net with Attention
DDPM은 노이즈를 예측하기 위해 U-Net 구조를 사용한다. 기존 이미지 분할(segmentation)에서 사용되던 U-Net을 생성 모델에 맞게 수정했다.
| 구성 요소 | 설명 |
|---|---|
| Encoder | 이미지를 점진적으로 다운샘플링하며 특징 추출 |
| Decoder | 업샘플링하며 원래 해상도로 복원 |
| Skip Connection | 인코더-디코더 간 정보 전달로 세부 디테일 보존 |
| Self-Attention | 16×16 해상도에서 전역 의존성 포착 |
| Time Embedding | Sinusoidal 위치 인코딩으로 시간 단계 정보 주입 |
| Group Normalization | Batch Norm 대신 사용하여 소규모 배치에서도 안정적 학습 |
| ResNet Block | 잔차 연결로 깊은 네트워크 학습 안정화 |
시간 정보 는 Transformer의 위치 인코딩(sinusoidal embedding)과 같은 방식으로 인코딩되어 네트워크의 각 레이어에 주입된다:
이 임베딩은 MLP를 거친 후 각 ResNet 블록에 더해져, 네트워크가 현재 어느 노이즈 수준에서 복원해야 하는지 인식할 수 있게 한다.
손실 함수 (Loss Function)
DDPM의 가장 큰 기여 중 하나는 손실 함수의 단순화이다.
이론적 손실: 변분 하한 (VLB)
원래 확산 모델의 학습 목표는 데이터 로그 우도의 변분 하한(Variational Lower Bound)을 최대화하는 것이다:
각 항의 의미:
– : Forward process의 마지막 분포와 사전 분포(prior) 간의 KL 발산. 가 고정이면 상수이므로 학습에 영향 없음
– : 각 역확산 단계에서 실제 사후 분포와 모델 예측 간의 KL 발산
– : 최종 복원 이미지의 로그 우도
실용적 손실: 단순 MSE
DDPM의 핵심 통찰은 위의 복잡한 VLB를 단순한 노이즈 예측 MSE로 대체할 수 있다는 것이다:
여기서:
– : 실제로 추가된 가우시안 노이즈 (ground truth)
– : 신경망이 예측한 노이즈
– : 에서 균일하게 샘플링된 시간 단계
– : 학습 데이터에서 샘플링된 원본 이미지
직관적으로 말하면, 네트워크는 “노이즈가 섞인 이미지를 보고 어떤 노이즈가 추가되었는지 맞추는” 문제를 푸는 것이다. 이것이 denoising score matching과 동일한 목적이라는 것이 논문의 핵심 연결고리다.
노이즈 스케줄
DDPM은 를 에서 까지 선형적으로 증가하는 스케줄을 사용한다:
총 시간 단계 을 사용하여, 충분히 작은 단계로 점진적으로 노이즈를 추가하고 제거한다.
학습 알고리즘
import torch
import torch.nn as nn
def train_step(model, x_0, T=1000, betas=None):
"""
DDPM 학습의 한 스텝
Args:
model: 노이즈 예측 U-Net
x_0: 원본 이미지 배치 [B, C, H, W]
T: 총 확산 단계 수
betas: 노이즈 스케줄 [T]
"""
# 1. 랜덤 시간 단계 샘플링
t = torch.randint(0, T, (x_0.shape[0],), device=x_0.device)
# 2. alpha_bar 계산
alphas = 1.0 - betas
alpha_bar = torch.cumprod(alphas, dim=0)
alpha_bar_t = alpha_bar[t].view(-1, 1, 1, 1)
# 3. 노이즈 샘플링
epsilon = torch.randn_like(x_0)
# 4. x_t 생성 (reparameterization)
x_t = torch.sqrt(alpha_bar_t) * x_0 + torch.sqrt(1 - alpha_bar_t) * epsilon
# 5. 노이즈 예측
epsilon_pred = model(x_t, t)
# 6. 단순 MSE 손실
loss = nn.functional.mse_loss(epsilon_pred, epsilon)
return loss
샘플링 알고리즘
학습이 완료된 후, 새 이미지를 생성하는 샘플링 과정은 다음과 같다:
@torch.no_grad()
def sample(model, shape, T=1000, betas=None):
"""
DDPM 샘플링 (이미지 생성)
Args:
model: 학습된 노이즈 예측 U-Net
shape: 생성할 이미지 형태 [B, C, H, W]
T: 총 확산 단계 수
betas: 노이즈 스케줄
"""
device = next(model.parameters()).device
alphas = 1.0 - betas
alpha_bar = torch.cumprod(alphas, dim=0)
# x_T ~ N(0, I) 순수 노이즈에서 시작
x = torch.randn(shape, device=device)
for t in reversed(range(T)):
t_batch = torch.full((shape[0],), t, device=device, dtype=torch.long)
# 노이즈 예측
epsilon_pred = model(x, t_batch)
# 평균 계산
alpha_t = alphas[t]
alpha_bar_t = alpha_bar[t]
mu = (1 / torch.sqrt(alpha_t)) * (
x - (betas[t] / torch.sqrt(1 - alpha_bar_t)) * epsilon_pred
)
# 분산 추가 (t > 0일 때만)
if t > 0:
sigma = torch.sqrt(betas[t])
z = torch.randn_like(x)
x = mu + sigma * z
else:
x = mu
return x
수학적 심층 분석: 왜 노이즈 예측이 작동하는가?
역확산 사후 분포의 해석
가 주어졌을 때, 역확산의 실제 사후 분포는 다음과 같이 닫힌 형태(closed form)로 구할 수 있다:
여기서 평균과 분산은:
를 대입하면, 평균이 의 함수로 표현된다. 따라서 노이즈 을 예측하는 것은 곧 역확산 평균 를 예측하는 것과 동치가 된다.
Score Matching과의 관계
DDPM의 노이즈 예측은 score function 의 추정과 직접적으로 연결된다:
이 관계는 Song & Ermon (2019)의 Score-Based Generative Model과 DDPM이 근본적으로 같은 프레임워크에 속함을 보여준다.
실험 결과 분석
정량적 결과
DDPM은 CIFAR-10과 LSUN 데이터셋에서 다음과 같은 성능을 달성했다:
CIFAR-10 (32×32) 비조건부 생성
| 모델 | FID ↓ | IS ↑ | 학습 안정성 |
|---|---|---|---|
| DDPM | 3.17 | 9.46 | 매우 안정적 |
| StyleGAN2 + ADA | 2.92 | 9.83 | 불안정 |
| NCSN (Score-based) | 25.32 | 8.87 | 안정적 |
| NVAE (VAE) | 23.50 | – | 안정적 |
| Glow (Flow) | 48.90 | 3.92 | 안정적 |
FID 3.17은 당시 비적대적(non-adversarial) 생성 모델 중 최고 성능이었으며, GAN과의 격차를 크게 줄인 결과다.
LSUN (256×256) 생성
| 데이터셋 | FID ↓ |
|---|---|
| LSUN Bedroom | 4.90 |
| LSUN Cat | 19.75 |
| LSUN Church | 7.89 |
주요 실험 관찰
-
vs : 단순화된 손실이 VLB보다 샘플 품질에서 더 우수한 결과를 보였다. FID 기준 은 3.17, 는 5.40을 기록했다.
-
고정 분산 vs 학습 분산: (상한)와 (하한) 모두 비슷한 성능을 보여, 분산을 학습할 필요가 없었다.
-
Progressive Coding 해석: 각 시간 단계별 손실을 분석하면, 작은 에서는 세밀한 디테일을, 큰 에서는 전체적인 구조를 학습하는 점진적 디코딩 특성이 나타났다.
Ablation Study
| 설정 | FID ↓ | NLL (bpd) ↓ |
|---|---|---|
| , | 3.17 | 3.75 |
| , | 3.17 | 3.70 |
| , | 5.40 | 3.99 |
| 직접 예측 | 3.58 | 3.72 |
| 예측 (최종) | 3.17 | 3.75 |
주요 관찰:
– 노이즈 예측 방식( 예측)이 평균 직접 예측 방식( 예측)보다 FID에서 우수
– 단순 손실()이 이론적 VLB 손실보다 생성 품질에서 우수
– FID와 NLL(Negative Log-Likelihood) 사이에 trade-off 존재: 좋은 FID가 반드시 좋은 NLL을 의미하지 않음
기존 방법론과의 비교
생성 모델 패러다임 비교
| 특성 | GAN | VAE | Flow | DDPM |
|---|---|---|---|---|
| 학습 안정성 | 낮음 | 높음 | 높음 | 매우 높음 |
| 생성 품질 (FID) | 최고 | 낮음 | 낮음 | GAN에 근접 |
| 다양성 (Mode Coverage) | 낮음 (mode collapse) | 높음 | 높음 | 매우 높음 |
| 로그 우도 계산 | 불가 | 하한만 가능 | 정확 | 하한 가능 |
| 샘플링 속도 | 매우 빠름 (1 pass) | 매우 빠름 (1 pass) | 빠름 | 매우 느림 (1000 steps) |
| 아키텍처 제약 | Generator + Discriminator | Encoder + Decoder | 가역 변환 | 자유로움 |
| 학습 목적 함수 | 미니맥스 게임 | ELBO | 정확한 우도 | 단순 MSE |
| 잠재 공간 구조 | 비구조적 | 구조적 | 구조적 | 비구조적 |
DDPM vs Score-Based Model (NCSN)
| 특성 | DDPM | NCSN (Song & Ermon) |
|---|---|---|
| 이론적 관점 | 확률적 확산 과정 | 점수 함수 추정 |
| 학습 목표 | 노이즈 예측 | Score 추정 |
| 샘플링 | 역확산 마르코프 체인 | Langevin 동역학 |
| CIFAR-10 FID | 3.17 | 25.32 |
| 수학적 관계 | 두 접근법은 본질적으로 동치 |
DDPM의 강점
-
학습의 단순성과 안정성: 손실 함수가 단순한 MSE이므로 하이퍼파라미터 튜닝이 간단하고, 학습이 GAN에 비해 매우 안정적이다.
-
모드 붕괴 없음: GAN의 고질적 문제인 모드 붕괴가 구조적으로 발생하지 않아 데이터의 다양성을 잘 포착한다.
-
이론적 기반의 견고함: 열역학적 확산 과정과 변분 추론에 기반한 탄탄한 수학적 프레임워크를 갖추고 있다.
-
확장성: U-Net 아키텍처를 자유롭게 수정할 수 있으며, 조건부 생성, 텍스트-이미지 변환 등으로 쉽게 확장 가능하다.
-
재현성: 학습이 안정적이므로 동일 설정에서 일관된 결과를 얻을 수 있다.
DDPM의 한계점
-
느린 샘플링 속도: 단계의 순차적 역확산이 필요하여, 이미지 하나를 생성하는 데 GAN 대비 수백~수천 배 느리다. 이는 실시간 응용에 큰 장벽이 된다.
-
FID에서 GAN 미달: 당시 최고 GAN(StyleGAN2)에 비해 FID가 다소 뒤처졌다 (3.17 vs 2.92).
-
NLL 성능 한계: 이 생성 품질은 좋지만 NLL(bits-per-dimension) 기준으로는 자기회귀 모델에 뒤처진다.
-
고해상도 직접 생성의 어려움: 256×256까지는 가능하나, 더 높은 해상도로 직접 확장하기 어렵다. (이후 Latent Diffusion으로 해결)
-
조건부 생성 미지원: 원 논문은 무조건부(unconditional) 생성만 다루며, 텍스트나 클래스 조건부 생성에 대한 논의가 없다.
-
메모리 사용량: 고해상도 이미지에서 U-Net이 상당한 메모리를 요구한다.
후속 연구와 발전 방향
DDPM 이후 확산 모델은 폭발적으로 발전했다. 주요 후속 연구를 시간순으로 정리한다:
| 논문 | 연도 | 핵심 기여 | DDPM 한계 해결 |
|---|---|---|---|
| Improved DDPM | 2021 | 코사인 스케줄, 분산 학습 | NLL 개선 |
| DDIM | 2021 | 비마르코프 샘플링 (50 steps) | 샘플링 속도 20× 개선 |
| Classifier Guidance | 2021 | 분류기로 조건부 생성 유도 | 조건부 생성 |
| Classifier-Free Guidance | 2022 | 분류기 없이 조건부 생성 | 더 실용적인 조건부 생성 |
| Latent Diffusion (LDM) | 2022 | 잠재 공간에서 확산 수행 | 고해상도 + 속도 개선 |
| DALL-E 2 | 2022 | CLIP + 확산 모델 결합 | 텍스트→이미지 생성 |
| Stable Diffusion | 2022 | LDM의 오픈소스 구현 | 대중적 접근성 |
| Consistency Models | 2023 | 1-step 생성 가능 | 샘플링 속도 극대화 |
| Flow Matching | 2023 | ODE 기반 직선 경로 학습 | 이론적 단순화 + 속도 |
| Stable Diffusion 3 | 2024 | DiT(Diffusion Transformer) + Flow Matching | 최신 아키텍처 |
현재 연구 트렌드
- 샘플링 가속화: Consistency Models, Progressive Distillation, DPM-Solver 등을 통해 1~4 step 생성 달성
- Transformer 기반 확산 모델: U-Net에서 DiT(Diffusion Transformer)로 아키텍처 패러다임 전환
- 비디오/3D 생성: Sora, SVD 등 시간/공간 차원으로 확장
- Flow Matching: SDE/ODE를 통합하는 더 일반적인 프레임워크
- Rectified Flow: 직선 경로 학습으로 샘플링 효율 극대화
PyTorch로 보는 미니 DDPM 구현
논문의 핵심을 이해하기 위한 최소한의 구현 골격을 살펴본다:
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
class SinusoidalTimeEmbedding(nn.Module):
"""시간 단계 t를 고차원 임베딩으로 변환"""
def __init__(self, dim):
super().__init__()
self.dim = dim
def forward(self, t):
half_dim = self.dim // 2
emb = torch.log(torch.tensor(10000.0)) / (half_dim - 1)
emb = torch.exp(torch.arange(half_dim, device=t.device) * -emb)
emb = t[:, None] * emb[None, :]
return torch.cat([torch.sin(emb), torch.cos(emb)], dim=-1)
class SimpleUNet(nn.Module):
"""간소화된 U-Net (개념 이해용)"""
def __init__(self, channels=3, time_dim=256):
super().__init__()
self.time_mlp = nn.Sequential(
SinusoidalTimeEmbedding(time_dim),
nn.Linear(time_dim, time_dim),
nn.GELU(),
nn.Linear(time_dim, time_dim)
)
# Encoder / Decoder 블록 (실제로는 더 복잡)
self.encoder = nn.Sequential(
nn.Conv2d(channels, 64, 3, padding=1),
nn.GroupNorm(8, 64),
nn.GELU(),
nn.Conv2d(64, 128, 3, stride=2, padding=1),
nn.GroupNorm(8, 128),
nn.GELU(),
)
self.decoder = nn.Sequential(
nn.ConvTranspose2d(128, 64, 4, stride=2, padding=1),
nn.GroupNorm(8, 64),
nn.GELU(),
nn.Conv2d(64, channels, 3, padding=1),
)
def forward(self, x, t):
t_emb = self.time_mlp(t.float())
h = self.encoder(x)
# 시간 임베딩 주입
h = h + t_emb[:, :128, None, None]
return self.decoder(h)
class DDPM:
"""DDPM 학습 및 샘플링"""
def __init__(self, model, T=1000, beta_start=1e-4, beta_end=0.02, device='cuda'):
self.model = model.to(device)
self.T = T
self.device = device
# 노이즈 스케줄
self.betas = torch.linspace(beta_start, beta_end, T).to(device)
self.alphas = 1.0 - self.betas
self.alpha_bar = torch.cumprod(self.alphas, dim=0)
def train_loss(self, x_0):
"""학습 손실 계산"""
batch_size = x_0.shape[0]
t = torch.randint(0, self.T, (batch_size,), device=self.device)
noise = torch.randn_like(x_0)
alpha_bar_t = self.alpha_bar[t].view(-1, 1, 1, 1)
# x_t 생성
x_t = torch.sqrt(alpha_bar_t) * x_0 + torch.sqrt(1 - alpha_bar_t) * noise
# 노이즈 예측 및 MSE 손실
noise_pred = self.model(x_t, t)
return F.mse_loss(noise_pred, noise)
@torch.no_grad()
def sample(self, shape):
"""이미지 생성"""
x = torch.randn(shape, device=self.device)
for t in reversed(range(self.T)):
t_batch = torch.full((shape[0],), t, device=self.device, dtype=torch.long)
noise_pred = self.model(x, t_batch)
alpha_t = self.alphas[t]
alpha_bar_t = self.alpha_bar[t]
beta_t = self.betas[t]
# 평균 계산
mu = (1 / torch.sqrt(alpha_t)) * (
x - (beta_t / torch.sqrt(1 - alpha_bar_t)) * noise_pred
)
if t > 0:
x = mu + torch.sqrt(beta_t) * torch.randn_like(x)
else:
x = mu
return x
마무리
DDPM(Denoising Diffusion Probabilistic Models)은 생성 모델 연구의 흐름을 근본적으로 바꾼 논문이다. 핵심 내용을 정리하면 다음과 같다:
- Forward Process: 원본 이미지에 점진적으로 노이즈를 추가하여 순수 가우시안 분포로 변환
- Reverse Process: 학습된 U-Net이 각 단계에서 노이즈를 예측하여 점진적으로 이미지 복원
- 단순화된 손실: 복잡한 변분 하한 대신 단순 노이즈 예측 MSE로 학습, 더 높은 생성 품질 달성
- 성과: CIFAR-10에서 FID 3.17 달성, 비적대적 모델 중 SOTA
- 한계: 1000 step 순차 샘플링으로 인한 느린 생성 속도
DDPM이 없었다면 Stable Diffusion, DALL-E, Midjourney 같은 혁신적인 이미지 생성 도구들은 존재하지 않았을 것이다. GAN 일변도였던 생성 모델 연구에 새로운 대안을 제시하고, 이후 수천 편의 후속 연구를 이끌어낸 이 논문은 딥러닝 역사에서 가장 영향력 있는 연구 중 하나로 평가받는다.
확산 모델에 입문하는 연구자라면, 이 논문을 출발점으로 DDIM → Classifier-Free Guidance → Latent Diffusion → Flow Matching 순서로 읽어나가는 것을 추천한다.
Did you find this helpful?
☕ Buy me a coffee
Leave a Reply