MCP HubMCP Hub
스킬 목록으로 돌아가기

implement-diffusion-network

pjt222
업데이트됨 Yesterday
1 조회
17
2
17
GitHub에서 보기
메타aidesign

정보

이 스킬은 노이즈 스케줄링, U-Net 아키텍처, DDIM 가속이 적용된 훈련/샘플링 루프를 포함하여 생성형 확산 모델(DDPM/점수 기반)을 처음부터 완전히 구현한 것입니다. 이미지/오디오 합성을 위한 맞춤형 확산 모델을 구축하거나, 논문을 구현하거나, 사용자 정의 조건을 추가하거나, 대규모 프레임워크 사용 전에 프로토타이핑이 필요할 때 활용하세요. 모델 구성 요소와 훈련 과정을 완전히 제어해야 하는 개발자를 위해 설계되었습니다.

빠른 설치

Claude Code

추천
기본
npx skills add pjt222/agent-almanac -a claude-code
플러그인 명령대체
/plugin add https://github.com/pjt222/agent-almanac
Git 클론대체
git clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/implement-diffusion-network

Claude Code에서 이 명령을 복사하여 붙여넣어 스킬을 설치하세요

문서

建擴散網路

自零建去噪擴散概率模型(DDPM)或基於分數之生成模型,含前向加噪過程、U-Net 去噪器、訓練目標、反向採樣過程與經 DDIM 或 DPM-Solver 加速推理。

適用時機

  • 為影像、音訊或分子合成建生成模型
  • 依研究論文建 DDPM 或分數基擴散
  • 於擴散流水中加自訂加噪計畫或條件機制
  • 以擴散為基之生成器代 GAN 基生成器
  • 以 diffusers 等生產框架擴展前原型化擴散模型

輸入

  • 必要:訓練資料集(影像、頻譜圖、點雲或他連續資料)
  • 必要:目標解析度與通道數
  • 必要:計算預算(GPU 類與數、訓練時限)
  • 選擇性:加噪計畫類(預設:cosine)
  • 選擇性:擴散時步 T 數(預設:1000)
  • 選擇性:條件訊號(類標、文嵌入或他引導)
  • 選擇性:採樣加速法(預設:DDIM 五十步)

步驟

步驟一:定前向過程(加噪計畫)

配控資料如何漸加噪之變異計畫。

  1. 定 beta 計畫(線性、cosine 或學得):
import torch
import numpy as np

def cosine_beta_schedule(timesteps, s=0.008):
    """Cosine schedule from Nichol & Dhariwal (2021)."""
    steps = timesteps + 1
    t = torch.linspace(0, timesteps, steps) / timesteps
    alphas_cumprod = torch.cos((t + s) / (1 + s) * np.pi / 2) ** 2
    alphas_cumprod = alphas_cumprod / alphas_cumprod[0]
    betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1])
    return torch.clip(betas, 0.0001, 0.9999)

def linear_beta_schedule(timesteps, beta_start=1e-4, beta_end=0.02):
    """Original DDPM linear schedule."""
    return torch.linspace(beta_start, beta_end, timesteps)
  1. 預算訓練與採樣所用之衍生量:
class DiffusionSchedule:
    def __init__(self, betas):
        self.betas = betas
        self.alphas = 1.0 - betas
        self.alphas_cumprod = torch.cumprod(self.alphas, dim=0)
        self.alphas_cumprod_prev = torch.cat([torch.tensor([1.0]), self.alphas_cumprod[:-1]])
        self.sqrt_alphas_cumprod = torch.sqrt(self.alphas_cumprod)
        self.sqrt_one_minus_alphas_cumprod = torch.sqrt(1.0 - self.alphas_cumprod)
        self.posterior_variance = (
            betas * (1.0 - self.alphas_cumprod_prev) / (1.0 - self.alphas_cumprod)
        )
  1. 實前向加噪函數(q-sample):
    def q_sample(self, x_0, t, noise=None):
        """Add noise to x_0 at timestep t: q(x_t | x_0)."""
        if noise is None:
            noise = torch.randn_like(x_0)
        sqrt_alpha = self.sqrt_alphas_cumprod[t].reshape(-1, 1, 1, 1)
        sqrt_one_minus_alpha = self.sqrt_one_minus_alphas_cumprod[t].reshape(-1, 1, 1, 1)
        return sqrt_alpha * x_0 + sqrt_one_minus_alpha * noise
  1. 視覺驗計畫:
schedule = DiffusionSchedule(cosine_beta_schedule(1000))
print(f"alpha_cumprod at t=0:   {schedule.alphas_cumprod[0]:.4f}")    # ~1.0 (clean)
print(f"alpha_cumprod at t=500: {schedule.alphas_cumprod[500]:.4f}")   # ~0.5 (half noise)
print(f"alpha_cumprod at t=999: {schedule.alphas_cumprod[999]:.4f}")   # ~0.0 (pure noise)

預期: alphas_cumprod 自近 1.0 單調降至近 0.0。Cosine 計畫中間時步應較線性漸降。

失敗時:alphas_cumprod 於 t=T 時未至近零,模型不能從純噪學生成。增 T 或調計畫。若值變負,核 betas 之截斷界。

步驟二:設計去噪網路架構

建附時間條件、於噪輸入下預測噪之 U-Net。

  1. 定時間嵌入模組:
import torch.nn as nn
import math

class SinusoidalTimeEmbedding(nn.Module):
    def __init__(self, dim):
        super().__init__()
        self.dim = dim

    def forward(self, t):
        half_dim = self.dim // 2
        emb = math.log(10000) / (half_dim - 1)
        emb = torch.exp(torch.arange(half_dim, device=t.device) * -emb)
        emb = t[:, None].float() * emb[None, :]
        return torch.cat([emb.sin(), emb.cos()], dim=-1)
  1. 定帶時間條件之殘差區塊:
class ResBlock(nn.Module):
    def __init__(self, in_ch, out_ch, time_dim):
        super().__init__()
        self.conv1 = nn.Conv2d(in_ch, out_ch, 3, padding=1)
        self.conv2 = nn.Conv2d(out_ch, out_ch, 3, padding=1)
        self.time_mlp = nn.Linear(time_dim, out_ch)
        self.norm1 = nn.GroupNorm(8, out_ch)
        self.norm2 = nn.GroupNorm(8, out_ch)
        self.skip = nn.Conv2d(in_ch, out_ch, 1) if in_ch != out_ch else nn.Identity()

    def forward(self, x, t_emb):
        h = self.norm1(torch.nn.functional.silu(self.conv1(x)))
        h = h + self.time_mlp(torch.nn.functional.silu(t_emb))[:, :, None, None]
        h = self.norm2(torch.nn.functional.silu(self.conv2(h)))
        return h + self.skip(x)
  1. 以編碼、瓶頸與解碼組成 U-Net:
class UNet(nn.Module):
    def __init__(self, in_channels=3, base_channels=64, channel_mults=(1, 2, 4, 8)):
        super().__init__()
        time_dim = base_channels * 4
        self.time_embed = nn.Sequential(
            SinusoidalTimeEmbedding(base_channels),
            nn.Linear(base_channels, time_dim),
            nn.SiLU(),
            nn.Linear(time_dim, time_dim)
        )
        # Encoder, bottleneck, and decoder built from ResBlocks
        # with skip connections between encoder and decoder stages
        # (full implementation depends on resolution and channel config)
  1. 驗架構接受目標解析度之輸入:
model = UNet(in_channels=3, base_channels=64)
x_test = torch.randn(2, 3, 64, 64)
t_test = torch.randint(0, 1000, (2,))
out = model(x_test, t_test)
assert out.shape == x_test.shape, f"Output shape {out.shape} != input shape {x_test.shape}"
print(f"Model parameters: {sum(p.numel() for p in model.parameters()):,}")

預期: 模型輸出與輸入同形之張量(預測匹配維度之噪)。參數數應比於解析度:64x64 約三千萬至六千萬、256x256 約一至三億。

失敗時: 形不配常示下/上採樣比不正。驗每編碼階半空間維度、每解碼階倍之。GroupNorm 需通道數可除於組數。

步驟三:實訓練迴圈

訓去噪器以預測每時步所加之噪。

  1. 設訓練目標(簡化 DDPM 損失):
def training_loss(model, schedule, x_0):
    batch_size = x_0.shape[0]
    t = torch.randint(0, len(schedule.betas), (batch_size,), device=x_0.device)
    noise = torch.randn_like(x_0)
    x_t = schedule.q_sample(x_0, t, noise)
    predicted_noise = model(x_t, t)
    loss = torch.nn.functional.mse_loss(predicted_noise, noise)
    return loss
  1. 配優化器與學習率計畫:
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4, weight_decay=0.01)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100000)
  1. 執訓練迴圈附日誌:
from torch.utils.data import DataLoader

dataloader = DataLoader(dataset, batch_size=64, shuffle=True, num_workers=4, pin_memory=True)

for epoch in range(num_epochs):
    model.train()
    epoch_loss = 0.0
    for batch_idx, x_0 in enumerate(dataloader):
        x_0 = x_0.to(device)
        loss = training_loss(model, schedule, x_0)
        optimizer.zero_grad()
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
        optimizer.step()
        scheduler.step()
        epoch_loss += loss.item()
    avg_loss = epoch_loss / len(dataloader)
    print(f"Epoch {epoch}: loss={avg_loss:.4f}, lr={scheduler.get_last_lr()[0]:.6f}")
  1. 定期存檢查點:
    if (epoch + 1) % 10 == 0:
        torch.save({
            "epoch": epoch,
            "model_state": model.state_dict(),
            "optimizer_state": optimizer.state_dict(),
            "loss": avg_loss
        }, f"checkpoint_epoch_{epoch+1}.pt")

預期: 損失隨訓練穩降。資料歸一化於 [-1, 1],初始損失應近 1.0(預測隨機噪)。收斂後,損失應於 0.01-0.10 範圍依資料複雜度。

失敗時: 若損失早平(> 0.5),核:(a) 資料歸一化(須 [-1, 1] 或 [0, 1] 配最終激活),(b) 學習率(試 3e-4 或 5e-5),(c) 梯度截斷(1.0 為標準)。若損失為 NaN,降學習率並核計畫中除零。

步驟四:實採樣(反向過程)

自純高斯噪疊去噪以生新樣本。

  1. 實標準 DDPM 採樣迴圈:
@torch.no_grad()
def ddpm_sample(model, schedule, shape, device):
    """Sample via the full DDPM reverse process (T steps)."""
    x = torch.randn(shape, device=device)
    T = len(schedule.betas)

    for t in reversed(range(T)):
        t_batch = torch.full((shape[0],), t, device=device, dtype=torch.long)
        predicted_noise = model(x, t_batch)

        alpha = schedule.alphas[t]
        alpha_cumprod = schedule.alphas_cumprod[t]
        beta = schedule.betas[t]

        mean = (1 / torch.sqrt(alpha)) * (
            x - (beta / torch.sqrt(1 - alpha_cumprod)) * predicted_noise
        )

        if t > 0:
            noise = torch.randn_like(x)
            sigma = torch.sqrt(schedule.posterior_variance[t])
            x = mean + sigma * noise
        else:
            x = mean

    return x
  1. 生並視覺化樣本:
samples = ddpm_sample(model, schedule, shape=(16, 3, 64, 64), device=device)
samples = (samples.clamp(-1, 1) + 1) / 2  # rescale to [0, 1]

預期: 生樣本現可辨結構(非純噪或均勻色)。64x64 解析度於十萬以上訓練步後,輸出視覺應似訓練分布。

失敗時: 若樣本模糊,訓更久或增模型容量。若樣本噪雜,反向過程或有錯——驗計畫索引配訓練。若所有樣本似同,核模式崩潰(試不同隨機種)。

步驟五:加採樣加速

以 DDIM 或 DPM-Solver 減採樣步數。

  1. 實 DDIM 採樣(確定性、較少步):
@torch.no_grad()
def ddim_sample(model, schedule, shape, device, num_steps=50, eta=0.0):
    """DDIM sampling with configurable step count and stochasticity."""
    T = len(schedule.betas)
    step_indices = torch.linspace(0, T - 1, num_steps, dtype=torch.long)

    x = torch.randn(shape, device=device)

    for i in reversed(range(len(step_indices))):
        t = step_indices[i]
        t_batch = torch.full((shape[0],), t, device=device, dtype=torch.long)
        predicted_noise = model(x, t_batch)

        alpha_t = schedule.alphas_cumprod[t]
        alpha_prev = schedule.alphas_cumprod[step_indices[i - 1]] if i > 0 else torch.tensor(1.0)

        predicted_x0 = (x - torch.sqrt(1 - alpha_t) * predicted_noise) / torch.sqrt(alpha_t)
        predicted_x0 = predicted_x0.clamp(-1, 1)

        sigma = eta * torch.sqrt((1 - alpha_prev) / (1 - alpha_t) * (1 - alpha_t / alpha_prev))
        direction = torch.sqrt(1 - alpha_prev - sigma**2) * predicted_noise

        x = torch.sqrt(alpha_prev) * predicted_x0 + direction
        if i > 0 and eta > 0:
            x = x + sigma * torch.randn_like(x)

    return x
  1. 較跨步數之樣本品質:
for n_steps in [10, 25, 50, 100, 250]:
    samples = ddim_sample(model, schedule, shape=(16, 3, 64, 64), device=device, num_steps=n_steps)
    print(f"DDIM {n_steps} steps: generated {samples.shape[0]} samples")
    # Save grid for visual comparison
  1. 基準採樣速度:
import time

for method, n_steps in [("DDPM", 1000), ("DDIM-50", 50), ("DDIM-25", 25)]:
    start = time.time()
    _ = ddim_sample(model, schedule, (1, 3, 64, 64), device, num_steps=n_steps if "DDIM" in method else 1000)
    elapsed = time.time() - start
    print(f"{method}: {elapsed:.2f}s per sample")

預期: DDIM 五十步生視覺上可比於 DDPM 一千步之樣本,速二十倍改善。品質於約二十至二十五步和緩降。

失敗時: 若同步數下 DDIM 樣本劣於 DDPM,驗 alpha 索引。DDIM 直用 alphas_cumprod,非 alphas。若低步數之樣本極噪,先試 eta=0.0(全確定性)。

步驟六:評樣本品質

以標準指標量生品質。

  1. 算 FID(Frechet Inception Distance):
from torchmetrics.image.fid import FrechetInceptionDistance

fid_metric = FrechetInceptionDistance(feature=2048, normalize=True)

# Add real images
for batch in real_dataloader:
    fid_metric.update(batch.to(device), real=True)

# Add generated images
n_generated = 0
while n_generated < 10000:
    samples = ddim_sample(model, schedule, (64, 3, 64, 64), device, num_steps=50)
    samples = ((samples.clamp(-1, 1) + 1) / 2 * 255).byte()
    fid_metric.update(samples, real=False)
    n_generated += samples.shape[0]

fid_score = fid_metric.compute()
print(f"FID: {fid_score:.2f}")
  1. 評樣本多樣性(核模式崩潰):
# Compute pairwise LPIPS distances among generated samples
from torchmetrics.image.lpip import LearnedPerceptualImagePatchSimilarity

lpips = LearnedPerceptualImagePatchSimilarity(net_type="alex")
n_pairs = 50
diversity_scores = []
for i in range(n_pairs):
    s1 = ddim_sample(model, schedule, (1, 3, 64, 64), device, num_steps=50)
    s2 = ddim_sample(model, schedule, (1, 3, 64, 64), device, num_steps=50)
    score = lpips(s1.clamp(-1, 1), s2.clamp(-1, 1))
    diversity_scores.append(score.item())
print(f"Mean pairwise LPIPS: {np.mean(diversity_scores):.4f} (higher = more diverse)")
  1. 記結果:
results = {
    "fid": fid_score.item(),
    "mean_lpips_diversity": float(np.mean(diversity_scores)),
    "sampling_method": "DDIM-50",
    "training_epochs": num_epochs,
    "model_params": sum(p.numel() for p in model.parameters())
}
print("Evaluation results:", results)

預期: 標準基準(CIFAR-10、CelebA)上訓練良好之模型 FID 低於五十。LPIPS 多樣性高於 0.4 示無模式崩潰。SOTA 模型於 CIFAR-10 達 FID 2-10。

失敗時: 高 FID(>100)示訓練問題或訓不足。低多樣性(LPIPS < 0.2)示模式崩潰——增模型容量、核資料增強或訓更久。於至少一萬樣本上算 FID 以得穩定估計。

驗證

  • 前向過程於 t=T 產純噪(視覺核與數值:均值近 0、標準差近 1)
  • U-Net 輸出形於所有目標解析度下配輸入形
  • 訓練損失於首千步單調降
  • DDPM 採樣於充分訓練後產可辨輸出
  • DDIM 五十步產可比於 DDPM 一千步之品質
  • 目標資料集上 FID 分低於五十(依領域調閾)
  • 樣本多樣性(LPIPS)確無模式崩潰
  • 檢查點已存且可無錯載

常見陷阱

  • 資料歸一化錯:DDPM 假設資料於 [-1, 1]。若影像於 [0, 255],損失將極大且訓練發散。訓前歸一化、採樣後反歸一化。
  • 計畫索引差一:前向過程用 alphas_cumprod[t] 為 t 步之噪樣本。採樣中差一錯(用 t+1 或 t-1)產視覺降級之樣本。
  • 忘梯度截斷:無 clip_grad_norm_(1.0),大模型訓練不穩。早期尤關鍵。
  • DDIM 採樣步過少:二十步以下 DDIM 品質速降。至少二十五步以得可接受結果;五十步以得近 DDPM 品質。
  • FID 於樣本過少上評:FID 估計於小樣本量有偏。用至少一萬生影像與一萬真影像以得穩定 FID 計算。
  • 忽視 EMA:模型權重之指數移動平均顯著改樣本品質。用 0.9999 之衰減率並自 EMA 模型採樣,非訓練模型。

相關技能

  • analyze-diffusion-dynamics - DDPM 離散化之擴散 SDE 之數學基
  • fit-drift-diffusion-model - 擴散過程於認知建模之不同應用
  • setup-gpu-training - 為擴散模型訓練配 GPU 環境
  • containerize-application - 於 Docker 中封裝擴散推理流水

GitHub 저장소

pjt222/agent-almanac
경로: i18n/wenyan-lite/skills/implement-diffusion-network
0
agentsagentskillsai-assisted-developmentclaude-codeskillsteams

연관 스킬

content-collections

메타

이 스킬은 콘텐츠 콜렉션(Content Collections)을 위한 프로덕션 검증된 설정을 제공합니다. 콘텐츠 콜렉션은 Markdown/MDX 파일을 Zod 검증이 포함된 타입 안전한 데이터 콜렉션으로 변환해주는 TypeScript 최우선 도구입니다. 블로그, 문서 사이트 또는 콘텐츠 중심의 Vite + React 애플리케이션을 구축할 때 타입 안전성과 자동 콘텐츠 검증을 보장하기 위해 사용하세요. Vite 플러그인 구성과 MDX 컴파일부터 배포 최적화 및 스키마 검증에 이르기까지 모든 것을 다룹니다.

스킬 보기

polymarket

메타

이 스킬은 개발자들이 Polymarket 예측 시장 플랫폼을 활용한 애플리케이션을 구축할 수 있도록 지원하며, 거래 및 시장 데이터를 위한 API 통합 기능을 포함합니다. 또한 WebSocket을 통한 실시간 데이터 스트리밍을 제공하여 실시간 거래와 시장 활동을 모니터링할 수 있습니다. 이를 통해 거래 전략을 구현하거나 실시간 시장 업데이트를 처리하는 도구를 생성하는 데 활용할 수 있습니다.

스킬 보기

creating-opencode-plugins

메타

이 스킬은 개발자들이 명령어, 파일, LSP 작업 등 25개 이상의 이벤트 유형에 연결되는 OpenCode 플러그인을 만들 수 있도록 돕습니다. JavaScript/TypeScript 모듈을 위한 플러그인 구조, 이벤트 API 명세, 구현 패턴을 제공합니다. OpenCode AI 어시스턴트의 라이프사이클을 사용자 정의 이벤트 기반 로직으로 가로채거나, 모니터링하거나, 확장해야 할 때 사용하세요.

스킬 보기

sglang

메타

SGLang은 RadixAttention 프리픽스 캐싱을 활용하여 JSON, 정규식, 에이전트 워크플로우를 위한 고속 구조화 생성에 특화된 고성능 LLM 서빙 프레임워크입니다. 특히 반복되는 프리픽스가 있는 작업에서 상당히 빠른 추론 속도를 제공하여 복잡한 구조화 출력 및 다중 턴 대화에 이상적입니다. 제약 디코딩이 필요하거나 광범위한 프리픽스 공유가 있는 애플리케이션을 구축할 때는 vLLM과 같은 대안보다 SGLang을 선택하십시오.

스킬 보기