拡散モデル
学習目標: 拡散モデル(Diffusion Model)の原理と実装を理解する
拡散モデルとは
拡散モデルは、データに徐々にノイズを加えていく過程(拡散過程)と、 ノイズから元のデータを復元する過程(逆拡散過程)を学習する生成モデルです。
拡散過程のイメージ
生成時は逆方向 ノイズ → 徐々にクリアな画像へ
数学的な定式化
拡散過程(Forward Process)
徐々にノイズを加える
q(xₜ|xₜ₋₁) = N(√(1-βₜ)xₜ₋₁, βₜI)
βₜ: ノイズスケジュール(小さい値から徐々に増加)
逆拡散過程(Reverse Process)
ノイズを除去(ニューラルネットで学習)
p_θ(xₜ₋₁|xₜ) = N(μ_θ(xₜ,t), Σ_θ(xₜ,t))
θ: 学習するパラメータ
PyTorch実装(DDPM)
import torch
import torch.nn as nn
import torch.nn.functional as F
class DiffusionModel:
def __init__(self, n_steps=1000, beta_start=1e-4, beta_end=0.02):
# ノイズスケジュール
self.betas = torch.linspace(beta_start, beta_end, n_steps)
self.alphas = 1 - self.betas
self.alpha_bars = torch.cumprod(self.alphas, dim=0)
def add_noise(self, x0, t, noise=None):
"""拡散過程: x0にノイズを加えてxtを生成"""
if noise is None:
noise = torch.randn_like(x0)
alpha_bar_t = self.alpha_bars[t].view(-1, 1, 1, 1)
# xt = sqrt(alpha_bar_t) * x0 + sqrt(1 - alpha_bar_t) * noise
xt = torch.sqrt(alpha_bar_t) * x0 + torch.sqrt(1 - alpha_bar_t) * noise
return xt, noise
def sample(self, model, shape, device):
"""逆拡散過程: ノイズから画像を生成"""
# 純粋なノイズから開始
x = torch.randn(shape, device=device)
for t in reversed(range(len(self.betas))):
t_tensor = torch.full((shape[0],), t, device=device, dtype=torch.long)
# ノイズを予測
predicted_noise = model(x, t_tensor)
# 1ステップ分ノイズを除去
alpha_t = self.alphas[t]
alpha_bar_t = self.alpha_bars[t]
beta_t = self.betas[t]
# 平均を計算
mean = (1 / torch.sqrt(alpha_t)) * (
x - (beta_t / torch.sqrt(1 - alpha_bar_t)) * predicted_noise
)
if t > 0:
noise = torch.randn_like(x)
x = mean + torch.sqrt(beta_t) * noise
else:
x = mean
return x
# ノイズ予測ネットワーク(U-Net構造)
class NoisePredictor(nn.Module):
def __init__(self, channels=1, time_embed_dim=256):
super().__init__()
# 時間埋め込み
self.time_mlp = nn.Sequential(
nn.Linear(1, time_embed_dim),
nn.ReLU(),
nn.Linear(time_embed_dim, time_embed_dim)
)
# 簡略化したU-Net(実際はもっと複雑)
self.down1 = nn.Conv2d(channels, 64, 3, padding=1)
self.down2 = nn.Conv2d(64, 128, 3, stride=2, padding=1)
self.mid = nn.Conv2d(128, 128, 3, padding=1)
self.up1 = nn.ConvTranspose2d(128, 64, 4, stride=2, padding=1)
self.out = nn.Conv2d(64, channels, 3, padding=1)
def forward(self, x, t):
# 時間情報を埋め込み
t_emb = self.time_mlp(t.float().unsqueeze(-1) / 1000)
# ダウンサンプリング
h1 = F.relu(self.down1(x))
h2 = F.relu(self.down2(h1))
# ミドル(時間情報を追加)
h = F.relu(self.mid(h2))
# アップサンプリング
h = F.relu(self.up1(h))
return self.out(h + h1)
学習プロセス
# 学習ループ
model = NoisePredictor()
diffusion = DiffusionModel()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
for epoch in range(epochs):
for x0 in dataloader:
# ランダムな時刻tを選択
t = torch.randint(0, 1000, (x0.size(0),))
# ノイズを加える
xt, noise = diffusion.add_noise(x0, t)
# ノイズを予測
predicted_noise = model(xt, t)
# 損失: 予測ノイズと実際のノイズの差
loss = F.mse_loss(predicted_noise, noise)
optimizer.zero_grad()
loss.backward()
optimizer.step()
学習の目標: 任意の時刻tにおいて、ノイズが加わった画像xtから、加えられたノイズを正確に予測すること
主要な拡散モデル
| モデル | 特徴 | 用途 |
|---|---|---|
| DDPM | 基本的な拡散モデル | 研究・学習用 |
| DDIM | 高速サンプリング(非マルコフ) | 効率的な生成 |
| Stable Diffusion | 潜在空間での拡散 + テキスト条件 | テキストから画像生成 |
| DALL-E 2 | CLIP + 拡散モデル | 高品質テキスト→画像 |
理解度チェック
Q. 拡散モデルの学習で、ニューラルネットワークは何を予測するように訓練されますか?