25  Ders 22 — Cosine Schedule, Noise Prediction ve Karras (Cosine Schedule, Noise Prediction and Karras)

ETAP 6’nın (Sıfırdan Diffusion A) finali ve diffusion’ın en rafine hâli — Howard, Johno ve Tanishq’le. Üç iyileştirme: cosine schedule (lineer β yerine sürekli, kapalı formüllü, daha dengeli bir gürültü çizelgesi); gürültü seviyesini tahmin etme (timestep’i ağa elle vermek yerine, ağ gürültü düzeyini kendisi çıkarsar); ve Karras — diffusion’ı yeniden çerçeveleyen birleştirici bir tasarım: sürekli sigma, preconditioning (scalings ile her gürültü seviyesinde birim varyans) ve çok daha iyi ODE örnekleyiciler (Euler, Heun, LMS). Dersin merkezî fikri şu: diffusion bir ODE çözme problemidir — gürültüyü ayrık bir timestep yerine sürekli bir σ ile parametreleyip örneklemeyi sayısal bir diferansiyel denklem olarak görünce, sayısal analizin onlarca yıllık çözücüleri (Runge-Kutta, Adams-Bashforth) miras alınır. İkinci köprü: scalings tam olarak Ders 17’nin varyans korunumu ilkesidir, diffusion’a uyarlanmış. Tek cümleyle: cosine schedule gürültü çizelgesini sürekli ve daha dengeli yapar, Karras ise diffusion’ı sürekli sigma + preconditioning + daha iyi ODE örnekleyiciler çerçevesinde yeniden kurarak az adımda DDIM’den yüksek kalite verir; ETAP 6 (sıfırdan diffusion A) burada kapanır.

NotBölüm bilgisi

25.1 Bu Derste Ne Var?

ETAP 6’nın finali ve diffusion’ın en rafine hâli. Üç iyileştirme tek dersin altında: cosine schedule (lineer β yerine sürekli, daha iyi gürültü çizelgesi), gürültü seviyesini tahmin etme (timestep’i elle vermek yerine ağ çıkarsar), ve Karras (“Elucidating the Design Space of Diffusion-Based Generative Models”) — diffusion’ı yeniden çerçeveleyen birleştirici bir tasarım: sürekli sigma, preconditioning (scalings) ve çok daha iyi ODE örnekleyiciler (Euler, Heun, LMS).

Üç temel fikir bu dersin omurgasını kurar:

  1. Cosine schedule — gürültü çizelgesini sürekli bir kosinüs fonksiyonuyla tanımla: ᾱ(t) = cos(t·π/2)²; lineerden daha iyi, ayrık adım yok (cosine schedule, sürekli zaman).
  2. Sürekli gürültü seviyesi (σ) — diffusion’ı ayrık timestep yerine sürekli gürültü düzeyiyle parametrele; Karras’ın çerçevesi (Karras, sürekli sigma).
  3. Preconditioning + daha iyi örnekleyiciler — ağ girdi/çıktısını ölçekle (c_skip/c_out/c_in) ki hep birim varyans görsün; Heun (2. derece) gibi ODE çözücülerle az adımda yüksek kalite (scalings, Euler, Heun).

“the seventh root of sigma, where rho is seven.” — Howard, 1:07:25

Şekil 28.1 bu üç iyileştirmeyi tek bir kavram haritasında birleştirir: solda cosine çizelge (lineer β optimal değil → ᾱ(t) = cos(t·π/2)² → dengeli gürültü dağılımı), ortada gürültü seviyesi tahmini (timestep’i elle verme → ağ gürültü düzeyini çıkarsar; Johno + Tanishq), sağda Karras çerçevesi (sürekli σ → preconditioning scalings → ρ=7 sigma çizelgesi → Euler/Heun/LMS örnekleyiciler → az adımda yüksek kalite). Karras zinciri rose ile işaretlidir: dersin ana kazanımı, diffusion’ı bir ODE çözme problemine indirgeyen bu çerçevedir.

flowchart TD
    L22["L22: Diffusion'ı<br/>Rafine Etmek"]

    L22 --> C["1 - Cosine Çizelge"]
    L22 --> N["2 - Gürültü Seviyesi<br/>Tahmini"]
    L22 --> K["3 - Karras Çerçevesi"]

    C --> C1["Lineer beta optimal değil"]
    C1 --> C2["alfa-bar(t) = cos(t*pi/2)^2<br/>sürekli t"]
    C2 --> C3["dengeli gürültü dağılımı"]

    N --> N1["timestep'i elle verme"]
    N1 --> N2["ağ gürültü düzeyini<br/>çıkarsar (Johno + Tanishq)"]

    K --> K1["sürekli sigma<br/>(çizelge kalkar)"]
    K1 --> K2["preconditioning scalings<br/>c_skip / c_out / c_in<br/>(birim varyans)"]
    K2 --> K3["sigma çizelgesi rho = 7"]
    K3 --> K4["ODE örnekleyiciler:<br/>Euler -> Heun 2. derece<br/>-> LMS çok-adımlı"]
    K4 --> K5["az adımda yüksek kalite"]

    classDef cyan fill:#cffafe,stroke:#0891b2,stroke-width:2px,color:#1e293b;
    classDef rose fill:#ffe4e6,stroke:#e11d48,stroke-width:2px,color:#1e293b;
    classDef root fill:#ecfeff,stroke:#155e75,stroke-width:3px,color:#1e293b;

    class L22 root;
    class C,C1,C2,C3,N,N1,N2,K,K1 cyan;
    class K2,K3,K4,K5 rose;
Şekil 25.1: L22 = diffusion’ın üç iyileştirmesi (ETAP 6 finali): cosine çizelge (dengeli gürültü dağılımı), gürültü seviyesi tahmini (timestep’i ağ çıkarsar) ve Karras çerçevesi (sürekli sigma + preconditioning + ODE örnekleyiciler). (şematik)
İpucuBuilder Notu — Üç İyileştirme, Tek Çatı: Çizelge, Parametreleme, Örnekleyici
  • Geriye (Ders 19-21): DDPM (L19) lineer β + ayrık adım kullandı, DDIM (L21) onu hızlandırdı; bu ders çizelgeyi (cosine), parametrelemeyi (σ) ve örnekleyiciyi (Heun/LMS) yeniden tasarlar — üç ayrı düğmeyi tek berrak çerçevede toplar.
  • Geriye (18.065): Karras örnekleyiciler diffusion’ı bir ODE çözme problemi olarak görür; Euler/Heun sayısal ODE yöntemleridir — bu, lineer cebir/sayısal analiz dersinin (18.065) diffusion’a doğrudan uygulanması.
  • İleriye (Ders 23-25): Karras çerçevesi modern diffusion’ın (super-res, latent) örnekleme standardıdır; SON ETAP onun üstüne kurulur.
  • Tek cümle: Cosine schedule gürültü çizelgesini sürekli ve daha iyi yapar; Karras ise diffusion’ı sürekli sigma + preconditioning (scalings) + ODE örnekleyiciler çerçevesinde yeniden kurarak az adımda yüksek kalite verir.

25.2 1. Cosine Schedule

Ders 19’un lineer β çizelgesi optimal değil — eğitimin çoğu zamanı “çok gürültülü” bölgede harcanır, orada öğrenilecek pek bir şey yoktur. Cosine schedule daha dengeli bir dağılım verir: birikimli ᾱ doğrudan bir kosinüs karesiyle tanımlanır, ᾱ(t) = cos(t·π/2)². Sürekli t ∈ [0,1] alır; başta yavaş, ortada hızlı, sonda yine yavaş gürültülenme. İki satır kapalı formül; ileri ve ters dönüşüm birbirinin tersidir:

def abar(t): return (t*math.pi/2).cos()**2
def inv_abar(x): return x.sqrt().acos()*2/math.pi

“improvement, fairly simple improvement to our DDPM-DDIM implementation.” — Howard, 0:35

Şekil 25.2 iki çizelgeyi gerçek hesaplamayla karşılaştırır: turuncu eğri cosine ᾱ(t) = cos(t·π/2)², kesik gri eğri Ders 19’un lineer-β cumprod çizelgesi. Orta noktada (t = 0.5) fark çarpıcı: cosine ᾱ = 0.499 (sinyalin yarısı korunmuş, dengeli), lineer ise ᾱ = 0.078 — sinyalin %92’si çoktan yok olmuş, “lineer çok erken gürültüye boğar”. Ayrıca kapalı formül kanıtı: inv_abar(abar(t)) = t round-trip hatası makine hassasiyetinde — ayrık çizelge tablosu yok, her t için doğrudan hesaplanır. İşte cosine’in iki erdemi yan yana: daha dengeli dağılım + daha az hiperparametre.

Kod
d = E.cosine_schedule_demo()
t, abar_cos, abar_lin = d["t"], d["abar_cos"], d["abar_lin"]
rt_err = d["roundtrip_err"]

# Orta nokta (t=0.5) değerleri — vurgu için
i_mid = int(np.argmin(np.abs(t - 0.5)))
cos_mid, lin_mid = abar_cos[i_mid], abar_lin[i_mid]

fig, ax = plt.subplots(figsize=(10.5, 5))

ax.plot(t, abar_cos, color=COL_PRIMARY, linewidth=3.0, zorder=4,
        label=r"cosine: $\bar\alpha(t)=\cos(t\cdot\pi/2)^2$")
ax.plot(t, abar_lin, color=COL_SLATE_400, linewidth=2.4, linestyle="--",
        zorder=3, label=r"lineer-β (Ders 19, cumprod)")

# t=0.5 dikey kılavuz + orta nokta işaretçileri
ax.axvline(0.5, color=COL_SLATE_300, linewidth=1.2, linestyle=":", zorder=1)
ax.scatter([0.5], [cos_mid], s=70, color=COL_PRIMARY, zorder=6,
           edgecolor=COL_WHITE, linewidth=1.5)
ax.scatter([0.5], [lin_mid], s=70, color=COL_ACCENT, zorder=6,
           edgecolor=COL_WHITE, linewidth=1.5)

ax.annotate(f"cosine: ᾱ={cos_mid:.3f}", xy=(0.5, cos_mid),
            xytext=(0.56, cos_mid + 0.10), fontsize=10.5, weight="bold",
            color=COL_CYAN_800,
            arrowprops=dict(arrowstyle="-|>", color=COL_PRIMARY, lw=1.8))
ax.annotate(f"lineer: ᾱ={lin_mid:.3f}", xy=(0.5, lin_mid),
            xytext=(0.56, lin_mid + 0.16), fontsize=10.5, weight="bold",
            color=COL_ACCENT,
            arrowprops=dict(arrowstyle="-|>", color=COL_ACCENT, lw=1.8))

# Açıklayıcı metin: lineer çok erken gürültüye boğar
ax.text(0.16, 0.18,
        "lineer çok erken\ngürültüye boğar",
        ha="center", va="center", fontsize=9.5, color=COL_ACCENT,
        style="italic",
        bbox=dict(boxstyle="round,pad=0.4", fc=COL_BG_ROSE, ec=COL_ROSE_400, lw=1.3))
ax.text(0.80, 0.78,
        "cosine dengeli:\nbaşta yavaş · ortada hızlı · sonda yavaş",
        ha="center", va="center", fontsize=9.5, color=COL_CYAN_800,
        bbox=dict(boxstyle="round,pad=0.4", fc=COL_BG, ec=COL_PRIMARY, lw=1.3))

# Round-trip rozeti
ax.text(0.5, -0.205,
        f"kapalı formül: inv_abar(abar(t))=t · round-trip hata {rt_err:.1e} — ayrık çizelge YOK",
        transform=ax.transAxes, ha="center", va="center", fontsize=9.5,
        weight="bold", color=COL_WHITE,
        bbox=dict(boxstyle="round,pad=0.5", fc=COL_CYAN_700, ec=COL_CYAN_800, lw=1.5))

ax.set_xlabel("t  (gürültü zamanı, 0 = temiz · 1 = saf gürültü)")
ax.set_ylabel(r"$\bar\alpha$  (korunan sinyal payı)")
ax.set_title("Cosine çizelge vs Ders 19 lineer-β — sinyalin gürültüye gidiş hızı",
             fontsize=12, weight="bold")
ax.set_xlim(0, 1)
ax.set_ylim(-0.02, 1.04)
viz.apply_style(ax)
ax.legend(loc="center left", bbox_to_anchor=(0.0, 0.62), frameon=True,
          framealpha=0.95, edgecolor=COL_SLATE_300, fontsize=10)

plt.tight_layout()
plt.show()
Şekil 25.2: (gerçek hesaplama: cosine ᾱ(t)=cos(t·π/2)² vs Ders 19 lineer-β — t=0.5’te 0.499 vs 0.078; sürekli, kapalı formüllü, dengeli)
İpucuBuilder Notu — Cosine: Ders 19 Çizelgesinin Kapalı-Formüllü Hâli
  • Geriye (Ders 19): Ders 19’un ᾱ = cumprod(α) ayrık çizelgesinin yerine sürekli, kapalı formüllü bir versiyon; daha az hiperparametre, daha iyi dağılım. Tablo yerine fonksiyon.
  • Sezgi: t = 0.5’te lineer ᾱ = 0.078 (sinyal neredeyse yok), cosine ᾱ = 0.499 (yarı yarıya) — bu fark eğitimi nereye odakladığını belirler. Lineer çizelge modelin zamanını “zaten kayıp” bölgede harcar; cosine onu faydalı gürültü seviyelerine dağıtır.

25.3 2. Sürekli Zaman

Cosine schedule’ın bir güzelliği: sürekli bir zaman değişkeni (t ∈ [0,1]) kullanır, ayrık 1000 adım yerine. noisify artık torch.rand ile sürekli t örnekler. Bu, diffusion’ı ayrık bir Markov zincirinden sürekli bir sürece taşımanın ilk adımı — Karras’ın çerçevesine geçiş:

def noisify(x0):
    t = torch.rand(len(x0),).to(x0).clamp(0,0.999)   # sürekli t
    ε = torch.randn(x0.shape, device=x0.device)
    abar_t = abar(t).reshape(-1, 1, 1, 1)
    xt = abar_t.sqrt()*x0 + (1-abar_t).sqrt()*ε
    return (xt, t), ε

“a continuous time step and a continuous process… before we were having these discrete time steps.” — Johno, 5:06

İpucuBuilder Notu — Sürekli Zaman: Markov Zincirinden ODE’ye Kapı
  • Geriye (Ders 19): Ders 19’da timestep ayrık bir tamsayıydı (0..999); burada torch.rand ile [0,1] aralığından sürekli örneklenir. noisify formülünün iskeleti (√ᾱ·x0 + √(1−ᾱ)·ε) aynı, sadece t’nin kaynağı değişti.
  • İleriye (Karras): Sürekli zaman, diffusion’ı bir diferansiyel denklem (ODE/SDE) olarak görmenin kapısı; Karras bunu tam kullanır. Ayrık zincir → sürekli süreç → sayısal çözücüler.

25.4 3. Gürültü Seviyesini Tahmin Etme

Bir ara fikir (Johno + Tanishq’in araştırması): ağa timestep’i elle vermek yerine, ağın gürültülü bir görüntüye bakıp gürültü seviyesini kendisi tahmin etmesini öğretmek. “Bu görüntü ne kadar gürültülü?” sorusu, modelin gürültü hakkındaki anlayışını test eder ve timestep’siz eğitime kapı aralar.

“we can predict the thing that we were putting in manually.” — Johno, 19:03

Şekil 25.3 bu fikrin en sade kanıtını gerçek hesaplamayla verir: 120 örnek için gerçek gürültü seviyesi σ (x) ile kestirilen σ̂ (y) log-log eksende çizilir, hepsi y = x köşegenine (kusursuz kestirim) yapışır. Yöntem kapalı-form bir istatistiktir: gürültülenmiş görüntünün standart sapması ≈ √(σ² + σ_d²) olduğundan, σ̂ = √(std² − σ_d²). Medyan göreli hata yalnızca %8.2 — yani σ gerçekten görüntünün içinde saklı ve okunabilir. Önemli not: buradaki kestirim bir ağ değil, kapalı-form istatistik; “ağ bunu öğrenebilir” fikrinin matematiksel kanıtı. σ görüntüde saklıysa, bir ağ da onu çıkarsamayı öğrenebilir → timestep’siz eğitime kapı.

Kod
d = E.noise_level_pred_demo()
true = d["true"]
est = d["est"]
rel_med = d["rel_err_med"]

fig, ax = plt.subplots(figsize=(9.5, 5.5))

# y = x köşegen referans (kusursuz kestirim çizgisi)
lo = min(true.min(), est.min()) * 0.8
hi = max(true.max(), est.max()) * 1.2
diag = np.array([lo, hi])
ax.plot(diag, diag, "--", color=COL_SLATE_400, linewidth=1.6,
        zorder=2, label="y = x  (kusursuz kestirim)")

# scatter: gerçek σ (x) vs kestirilen σ̂ (y)
ax.scatter(true, est, s=42, color=COL_PRIMARY, alpha=0.78,
           edgecolors=COL_CYAN_800, linewidths=0.6, zorder=3,
           label="120 örnek (lognormal σ)")

ax.set_xscale("log")
ax.set_yscale("log")
ax.set_xlim(lo, hi)
ax.set_ylim(lo, hi)
ax.set_xlabel("gerçek gürültü seviyesi  σ", fontsize=11)
ax.set_ylabel(r"kestirilen  $\hat{\sigma}$", fontsize=11)
ax.set_title("Gürültü seviyesi görüntünün istatistiğinden okunabilir",
             fontsize=12.5, weight="bold")
apply_style(ax)
ax.legend(loc="upper left", fontsize=9, framealpha=0.92)

# Rozet — kapalı-form yöntemi
ax.text(0.97, 0.06,
        "medyan göreli hata %{:.1f}\n".format(rel_med * 100)
        + r"std(noised) $\approx \sqrt{\sigma^2 + \sigma_d^2}$"
        + "\n" + r"$\rightarrow\ \hat{\sigma} = \sqrt{\mathrm{std}^2 - \sigma_d^2}$",
        transform=ax.transAxes, ha="right", va="bottom",
        fontsize=9.5, color=COL_TEXT, weight="bold",
        bbox=dict(boxstyle="round,pad=0.45", fc=COL_BG, ec=COL_PRIMARY, lw=1.5))

# Annotate — fikrin kanıtı (Johno+Tanishq)
ax.text(0.04, 0.97,
        "Johno+Tanishq fikrinin en sade kanıtı: σ görüntüde saklı;\n"
        "ağ bunu öğrenebilir → timestep'siz eğitime kapı.\n"
        "(Burada AĞ DEĞİL kapalı-form istatistik kestirimi — fikrin kanıtı.)",
        transform=ax.transAxes, ha="left", va="top",
        fontsize=8.6, color=COL_CYAN_800, style="italic",
        bbox=dict(boxstyle="round,pad=0.4", fc=COL_WHITE,
                  ec=COL_SLATE_300, lw=1.0, alpha=0.95))

plt.tight_layout()
plt.show()
Şekil 25.3: (gerçek hesaplama: gürültü seviyesi kestirimi — std’den kapalı-form σ̂, medyan hata %8.2; ‘ağ gürültü düzeyini çıkarsayabilir’ fikrinin istatistik kanıtı, ağ değil)
İpucuBuilder Notu — Gürültü Tahmini: Modelin Gerçek Anlayışının Testi
  • Geriye (Ders 19): Ders 19’da timestep’i before_batch’te elle veriyorduk; burada ağ onu çıkarsayabilir mi diye soruyoruz — modelin gürültüyü gerçekten “anlayıp anlamadığının” testi.
  • Sezgi: Bir görüntünün gürültü seviyesi, std gibi basit bir istatistiğe gömülüdür (figürde kapalı-formla %8.2 hata). Ağın bunu öğrenmesi zor değil; asıl değer, modelin gürültü hakkında zengin bir içsel temsil kurması — bu temsil bir sonraki adımın (Karras preconditioning) zeminini hazırlar.

25.5 4. Neden Gürültü Seviyesi Tahmini Önemli?

Bu sadece bir merak değil: gürültü seviyesini tahmin edebilen bir model, gürültü hakkında zengin bir içsel temsil öğrenmiştir. Bu, koşulsuz örneklemeyi ve gürültü-uyumlu işlemleri mümkün kılar. Ayrıca Karras’ın “ağ her gürültü seviyesinde iyi çalışmalı” ilkesinin temelini oluşturur — bir sonraki bölümün scalings fikrine doğrudan köprü.

İpucuBuilder Notu — Gürültü Farkındalığı: Preconditioning’e Köprü
  • İleriye: Gürültü seviyesi farkındalığı, gürültüye göre uyarlanan örnekleme ve preconditioning fikrine (Karras scalings) doğal köprü. “Ağ her σ’da iyi çalışmalı” demek için önce ağın σ’yı anlaması gerekir.
  • Sezgi: σ’yı tahmin edebilmek ile σ’ya göre girdiyi ölçeklemek aynı madalyonun iki yüzü: ikisi de “ağ gürültü düzeyinin farkında olmalı” der. Bu farkındalık, modeli her gürültü seviyesinde istikrarlı kılan ön-koşullamanın (scalings) felsefi temelidir.

25.6 5. Karras: Elucidating the Design Space

Karras ve ark. (2022), “Elucidating the Design Space of Diffusion-Based Generative Models” makalesi, diffusion’ın dağınık seçeneklerini (çizelge, parametreleme, örnekleyici) tek bir berrak çerçevede birleştirir. Howard’ın notebook’u büyük ölçüde bu makaleye dayanır. Ana yenilik: ayrık timestep yerine sürekli gürültü seviyesi σ ile çalışmak.

“Elucidating the Design Space of Diffusion-Based Generative Models.” — Howard, 38:48

Şekil 25.4 çerçevenin üç sütununu şematik olarak birleştirir: solda EĞİTİM zinciri (x₀ + σ·noise örnekle → scalings ile birim varyans → ağ → target = (x₀ − c_skip·noised)/c_out), ortada birleştirici denoise(model, x, σ) tanımı (eğitim ve örneklemeyi tek noktada buluşturur, ε değil temiz görüntü tahmini), sağda ÖRNEKLEME döngüsü (sigmas_karras ρ=7 → türev d = (x − denoised)/σ → Euler/Heun/LMS adımı → σ → 0 temiz görüntü). Mesaj: çizelge + parametreleme + örnekleyici, üç ayrı tasarım kararı, tek berrak çerçevede toplanır.

Kod
fig, ax = plt.subplots(figsize=(12.5, 5.5))
ax.set_xlim(0, 12.5)
ax.set_ylim(0, 5.5)
ax.axis("off")

# Üç sütun başlığı
ax.text(2.0, 5.2, "EĞİTİM", ha="center", va="center", fontsize=12.5,
        weight="bold", color=COL_CYAN_800)
ax.text(6.25, 5.2, "denoise(model, x, σ)", ha="center", va="center",
        fontsize=12.5, weight="bold", color=COL_ACCENT)
ax.text(10.5, 5.2, "ÖRNEKLEME", ha="center", va="center", fontsize=12.5,
        weight="bold", color=COL_CYAN_800)

# ----------------------------------------------------------------------------
# SOL — eğitim zinciri (yukarıdan aşağıya)
# ----------------------------------------------------------------------------
boxed_node(ax, 2.0, 4.45, 3.3, 0.66,
           "x₀ + σ·noise\n(σ ~ lognormal örnekle)",
           fc=COL_BG, ec=COL_PRIMARY, fontsize=9.5)
boxed_node(ax, 2.0, 3.45, 3.3, 0.66,
           "scalings(σ): c_in·girdi\n→ birim varyans",
           fc=COL_BG, ec=COL_PRIMARY, fontsize=9.5)
boxed_node(ax, 2.0, 2.45, 3.3, 0.58, "ağ",
           fc=COL_CYAN_50, ec=COL_CYAN_700, fontsize=10.5)
boxed_node(ax, 2.0, 1.35, 3.3, 0.74,
           "target =\n(x₀ − c_skip·noised) / c_out",
           fc=COL_BG, ec=COL_PRIMARY, fontsize=9.5)
arrow_between(ax, (2.0, 4.12), (2.0, 3.78), shrink=2)
arrow_between(ax, (2.0, 3.12), (2.0, 2.74), shrink=2)
arrow_between(ax, (2.0, 2.16), (2.0, 1.72), shrink=2)

# ----------------------------------------------------------------------------
# ORTA — birleştirici denoise tanımı (eğitim + örnekleme buraya bağlanır)
# ----------------------------------------------------------------------------
boxed_node(ax, 6.25, 3.55, 3.5, 1.5,
           "denoise(model, x, σ) =\nmodel(x·c_in, σ)·c_out\n+ x·c_skip\n\n→ TEMİZ görüntü tahmini",
           fc=COL_BG_ROSE, ec=COL_ACCENT, tc=COL_TEXT, fontsize=10.0, lw=2.4)
ax.text(6.25, 1.95,
        "ε değil — Ders 19'dan fark\n(matematiksel denk, ama kararlı)",
        ha="center", va="center", fontsize=8.8, style="italic",
        color=COL_CYAN_800)

# Sol ağ → orta denoise (eğitim besler), orta → sağ (örnekleme kullanır)
arrow_between(ax, (3.65, 2.55), (4.5, 3.4), color=COL_ACCENT, shrink=6,
              connectionstyle="arc3,rad=0.15")
arrow_between(ax, (8.0, 3.55), (8.85, 3.55), color=COL_ACCENT, shrink=6)

# ----------------------------------------------------------------------------
# SAĞ — örnekleme döngüsü (yukarıdan aşağıya)
# ----------------------------------------------------------------------------
boxed_node(ax, 10.5, 4.45, 3.3, 0.66,
           "sigmas_karras (ρ=7)\nσmax → … → 0",
           fc=COL_BG, ec=COL_PRIMARY, fontsize=9.5)
boxed_node(ax, 10.5, 3.45, 3.3, 0.66,
           "denoise → türev\nd = (x − denoised) / σ",
           fc=COL_BG, ec=COL_PRIMARY, fontsize=9.5)
boxed_node(ax, 10.5, 2.45, 3.3, 0.66,
           "Euler / Heun / LMS\nadımı: x += d·Δσ",
           fc=COL_BG, ec=COL_PRIMARY, fontsize=9.5)
boxed_node(ax, 10.5, 1.45, 3.3, 0.58, "σ → 0  (temiz görüntü)",
           fc=COL_CYAN_50, ec=COL_CYAN_700, fontsize=9.5)
arrow_between(ax, (10.5, 4.12), (10.5, 3.78), shrink=2)
arrow_between(ax, (10.5, 3.12), (10.5, 2.74), shrink=2)
arrow_between(ax, (10.5, 2.16), (10.5, 1.74), shrink=2)

# Annotate — çerçevenin özü
ax.text(6.25, 0.62,
        "çizelge + parametreleme + örnekleyici TEK berrak çerçevede\n"
        "'Elucidating the Design Space of Diffusion-Based Generative Models' (Karras 2022)",
        ha="center", va="center", fontsize=9.5, weight="bold", color=COL_TEXT,
        bbox=dict(boxstyle="round,pad=0.45", fc=COL_WHITE, ec=COL_SLATE_400, lw=1.4))

plt.tight_layout()
plt.show()
Şekil 25.4: (şematik: Karras çerçevesi — sürekli σ eğitimi (scalings+denoise) + ρ-çizelge + ODE örnekleyici; diffusion’ın en rafine hâli)
İpucuBuilder Notu — Design Space: Builder İçin Düşünme Tarzı
  • İleriye (research): Karras çerçevesi, modern diffusion örneklemenin (k-diffusion, Stable Diffusion’ın samplerları) temelidir; “design space” düşünme tarzı builder için değerli — dağınık seçenekleri tek eksende toplayıp her birini bağımsız ayarlamak.
  • Sezgi: Karras’ın katkısı yeni bir model değil, var olan parçaları (çizelge, parametreleme, örnekleyici) ayrıştırıp her birinin en iyi seçimini ayrı ayrı bulmaktır. Bu, mühendislik disiplini: bir sistemi bileşenlerine ayır, her bileşeni ayrı optimize et.

25.7 6. Sürekli Sigma (Gürültü Seviyesi)

Karras, gürültüyü bir timestep yerine doğrudan standart sapma σ ile parametreler: gürültülü görüntü = temiz + σ·gürültü. σ küçükse az gürültü, büyükse çok. Bu, çizelgeyi (β, ᾱ) ortadan kaldırır — yalnızca “şu an gürültü seviyesi ne kadar” sorusu kalır. Daha sade, daha esnek:

def noisify(x0):
    sig = (torch.randn([len(x0)])*1.2-1.2).exp().to(x0).reshape(-1,1,1,1)   # lognormal σ
    noise = torch.randn_like(x0)
    c_skip,c_out,c_in = scalings(sig)
    noised_input = x0 + noise*sig
    target = (x0 - c_skip*noised_input)/c_out
    return (noised_input*c_in, sig.squeeze()), target
İpucuBuilder Notu — Sürekli σ: Çizelgesiz Parametreleme
  • Geriye (Ders 19): Ders 19’un xt = √ᾱ·x0 + √(1−ᾱ)·ε formülünün σ-parametreli, daha sade hâli: noised = x0 + σ·noise. Çizelge tablosu yerine tek bir σ değeri.
  • Sezgi: σ doğrudan “ne kadar gürültü” demek; β/ᾱ ise dolaylı (bir çizelge üzerinden). σ ile herhangi bir gürültü seviyesi serbestçe seçilebilir, üstelik diffusion sürekli bir matematiksel nesneye (ODE) dönüşür — bu da sayısal çözücülerin kapısını açar.

25.8 7. Preconditioning: scalings

Karras’ın anahtar içgörüsü: ağ her gürültü seviyesinde birim varyanslı girdi/çıktı görmeli (Ders 17’nin varyans korunumu, diffusion’a uyarlanmış). Bunu üç ölçek sağlar: c_in girdiyi normalize eder, c_out çıktıyı ölçekler, c_skip girdinin ne kadarının doğrudan geçeceğini belirler. σ ve veri varyansına (sig_data) göre hesaplanır:

def scalings(sig):
    totvar = sig**2 + sig_data**2
    return sig_data**2/totvar, sig*sig_data/totvar.sqrt(), 1/totvar.sqrt()

“the input scalings and the cosine schedule… and some of the other schedulers we look at.” — Johno, 30:30

Şekil 25.5 bu fikri gerçek hesaplamayla kanıtlar — bu dersin Ders 17 köprüsü. Solda üç ölçek katsayısı σ boyunca (log eksen): σ küçükken c_skip ≈ 1 (girdi neredeyse temiz, doğrudan geçir), σ büyükken c_skip ≈ 0 (girdi çöp, ağ çıktısına güven); c_in girdiyi normalize eder, c_out çıktıyı ölçekler. σ = σ_data = 0.66 geçiş noktasıdır. Sağda asıl kanıt: farklı σ değerleri (0.01’den 80’e) için c_in · noised girdisinin standart sapması ölçülür — hepsi ≈ 1.0 (aralık 0.993–1.006). σ dört büyüklük mertebesi değişse de ağın gördüğü girdi sabit birim varyansta kalır. İşte Ders 17’nin varyans korunumu, diffusion’a uyarlanmış.

Kod
d = E.scalings_demo()
sig = d["sig"]
test_sigmas = d["test_sigmas"]
in_stds = d["in_stds"]
sig_data = d["sig_data"]

fig, (axL, axR) = plt.subplots(1, 2, figsize=(12, 5))

# --- SOL: c_skip / c_out / c_in eğrileri (log-x) ---
axL.semilogx(sig, d["c_skip"], color=COL_PRIMARY, lw=2.6,
             label=r"$c_\mathrm{skip}$  (σ küçükken girdiyi geçir)")
axL.semilogx(sig, d["c_out"], color=COL_ACCENT, lw=2.6,
             label=r"$c_\mathrm{out}$  (ağ çıktısının ölçeği)")
axL.semilogx(sig, d["c_in"], color=COL_SLATE_400, lw=2.6, ls="--",
             label=r"$c_\mathrm{in}$  (girdiyi normalize et)")
apply_style(axL)
axL.set_xlabel("σ  (gürültü seviyesi, log eksen)")
axL.set_ylabel("ölçek katsayısı")
axL.set_title("Karras preconditioning: scalings(σ)", color=COL_CYAN_700, weight="bold")
axL.axvline(sig_data, color=COL_CYAN_800, lw=1.0, ls=":", alpha=0.7)
axL.text(sig_data * 1.12, 0.92, r"σ = σ$_\mathrm{data}$ = 0.66",
         color=COL_CYAN_800, fontsize=8.5, rotation=90, va="top")
axL.annotate("σ küçük → c_skip≈1\n(girdi neredeyse temiz, geçir)",
             xy=(0.03, 0.97), xytext=(0.03, 0.62),
             fontsize=8.5, color=COL_CYAN_800, weight="bold",
             arrowprops=dict(arrowstyle="->", color=COL_CYAN_800, lw=1.3))
axL.annotate("σ büyük → c_skip≈0\n(girdi çöp, ağ çıktısına güven)",
             xy=(60.0, 0.0001), xytext=(2.5, 0.30),
             fontsize=8.5, color=COL_ACCENT, weight="bold",
             arrowprops=dict(arrowstyle="->", color=COL_ACCENT, lw=1.3))
axL.legend(loc="center right", fontsize=8.6, framealpha=0.92)

# --- SAĞ: birim-varyans kanıtı — test_sigmas vs in_stds ---
xpos = np.arange(len(test_sigmas))
axR.bar(xpos, in_stds, width=0.58, color=COL_BG, edgecolor=COL_PRIMARY,
        linewidth=2.0, zorder=3)
axR.scatter(xpos, in_stds, color=COL_ACCENT, s=70, zorder=5)
axR.axhline(1.0, color=COL_ACCENT, lw=1.8, ls="--", zorder=4,
            label="hedef birim varyans (std = 1.0)")
apply_style(axR)
axR.set_ylim(0.0, 1.35)
axR.set_xticks(xpos)
axR.set_xticklabels([f"σ={s:g}" for s in test_sigmas], color=COL_TEXT, fontsize=9.5)
axR.set_ylabel("std(c_in · noised)")
axR.set_title("Birim-varyans kanıtı: ağ hep birim varyans görür",
              color=COL_CYAN_700, weight="bold")
for x, v in zip(xpos, in_stds):
    axR.text(x, v + 0.05, f"{v:.3f}", ha="center", va="bottom",
             fontsize=9, color=COL_TEXT, weight="bold")
axR.text(0.5, 0.20,
         "c_in·noised std ≈ 1.0  HER σ'da  (0.993–1.006)\nσ 0.01'den 80'e değişse de ağ girdisi sabit ölçekte",
         transform=axR.transAxes, ha="center", va="center", fontsize=8.8,
         color=COL_CYAN_800, weight="bold",
         bbox=dict(boxstyle="round,pad=0.4", fc=COL_BG_ROSE, ec=COL_ROSE_500, lw=1.5))
axR.legend(loc="upper right", fontsize=8.4, framealpha=0.92)

fig.text(0.5, -0.02,
         "Ders 17 varyans korunumu (Kaiming / BatchNorm ilkesi) diffusion'a uyarlandı: "
         "girdi ölçeği normalize edilince ağ tüm σ aralığında istikrarlı öğrenir.",
         ha="center", fontsize=8.6, color=COL_TEXT, style="italic")

plt.tight_layout()
plt.show()
Şekil 25.5: (gerçek hesaplama: Karras scalings — c_skip/c_out/c_in eğrileri + birim-varyans kanıtı: c_in·noised std≈1.0 her σ’da; Ders 17 köprüsü)
İpucuBuilder Notu — scalings = Ders 17 Varyans Korunumu (KÖPRÜ)
  • Geriye (Ders 17) — merkezî köprü: Bu tam olarak Ders 17’nin varyans korunumu ilkesidir; ağ hep birim varyans görsün diye girdi/çıktı ölçeklenir. Kaiming init’in (√(2/n)) diffusion’a taşınmış hâli — orada katmanlar arası varyansı korumuştuk, burada gürültü seviyeleri arası.
  • Sezgi: σ 0.01’den 80’e değişirken (figürde dört mertebe) ağ aynı görevle karşı karşıya kalamaz; c_in her σ’da girdiyi ~birim varyansa çeker (kanıt: std 0.993–1.006). Ağ böylece “hangi σ’dayım” derdine düşmeden, hep iyi-ölçeklenmiş değerlerle çalışır — foundations’ta (L17) öğrendiğimiz şeyin diffusion’daki meyvesi.

25.9 8. denoise: Temiz Görüntüyü Tahmin Etme

Karras’ta ağ gürültüyü değil, temiz görüntüyü (denoised) tahmin eder; scalings ile birleştirilir. denoise fonksiyonu modelin çıktısını c_out/c_skip ile birleştirerek temiz görüntü tahminini verir. Bu, gürültü-tahmini ve görüntü-tahmini parametrelemelerini birleştiren genel formdur:

def denoise(model, x, sig):
    c_skip,c_out,c_in = scalings(sig)
    return model((x*c_in, sig))*c_out + x*c_skip
İpucuBuilder Notu — denoise: ε Yerine Temiz Görüntü (Daha Kararlı)
  • Geriye (Ders 19): Ders 19’da ağ gürültüyü (ε) tahmin ediyordu; Karras parametrelemesi temiz görüntüyü tahmin eder — ikisi matematiksel olarak denktir, ama Karras’ınki sayısal olarak daha kararlı.
  • Sezgi: denoise = model(x·c_in, σ)·c_out + x·c_skip formülü iki uçtaki davranışı tek satırda birleştirir: σ küçükken c_skip ≈ 1 baskındır (görüntü zaten temiz, neredeyse aynen geçir), σ büyükken c_out·model(...) baskındır (girdi çöp, tahmine güven). Tek fonksiyon her gürültü seviyesinde doğru karışımı verir.

25.10 9. Sigma Schedule ve ρ

Örneklemede hangi σ değerlerinden geçileceği bir sigma çizelgesiyle belirlenir. Karras, σmax’tan σmin’e giderken adımları ρ (rho) parametresiyle dağıtır: σᵢ = (σmax^(1/ρ) + i/(n−1)·(σmin^(1/ρ) − σmax(1/ρ)))ρ. ρ=7 düşük gürültü bölgesine daha çok adım ayırır (orada detay önemli):

def sigmas_karras(n, sigma_min=0.01, sigma_max=80., rho=7., device='cpu'):
    ramp = torch.linspace(0, 1, n)
    min_inv_rho = sigma_min**(1/rho)
    max_inv_rho = sigma_max**(1/rho)
    sigmas = (max_inv_rho + ramp * (min_inv_rho-max_inv_rho))**rho
    return torch.cat([sigmas, tensor([0.])]).to(device)

“the rho-th root of sigma, where rho is seven.” — Howard, 1:07:25

Şekil 25.6 ρ’nun etkisini gerçek hesaplamayla gösterir (notebook sigmas_karras birebir): üç ρ değeri (1, 3, 7) için 50 σ adımı log eksende çizilir. σ = 1 “detay sınırı”dır — altı düşük gürültü, yapı ve detayın belirginleştiği bölge. ρ büyüdükçe adımlar bu bölgeye yığılır: σ < 1 oranı ρ=1’de yalnız %2, ρ=3’te %20, ρ=7’de %36. Yani ρ=7 ile örnekleme adımlarının üçte birinden fazlası detay bölgesine ayrılır; kaba gürültü hızla geçilir, ince detay için bütçe ayrılır. ρ bu kalite-hız dengesinin ince ayar düğmesidir.

Kod
d = E.karras_sigma_demo()
rhos = d["rhos"]
frac_low = d["frac_low"]

# Her eğri 51 nokta (50 ramp + sona eklenen 0.0). Son 0.0 noktasını
# log-y ekseninde çizemeyiz; ilk 50 anlamlı adımı (σ>0) gösteriyoruz.
sig1 = rhos[1.0][:-1]
sig3 = rhos[3.0][:-1]
sig7 = rhos[7.0][:-1]
steps = np.arange(len(sig1))

fig, ax = plt.subplots(figsize=(10.5, 5.2))

ax.plot(steps, sig1, color=COL_SLATE_400, lw=2.0, marker="o", ms=3.5,
        label=f"ρ=1  (σ<1: %{frac_low[1.0]*100:.0f})")
ax.plot(steps, sig3, color=COL_CYAN_400, lw=2.4, marker="s", ms=3.5,
        label=f"ρ=3  (σ<1: %{frac_low[3.0]*100:.0f})")
ax.plot(steps, sig7, color=COL_ACCENT, lw=3.2, marker="^", ms=4.5,
        label=f"ρ=7  (σ<1: %{frac_low[7.0]*100:.0f})")

# σ=1 yatay referans çizgisi — detay/yapı bölgesi sınırı
ax.axhline(1.0, color=COL_CYAN_800, lw=1.4, ls="--", alpha=0.8, zorder=1)
ax.text(len(steps) - 1, 1.15, "σ=1 (detay sınırı)", ha="right", va="bottom",
        fontsize=9.5, color=COL_CYAN_800, weight="bold")

ax.set_yscale("log")
ax.set_xlabel("adım indeksi  (0 → 50)", fontsize=11)
ax.set_ylabel("σ  (gürültü düzeyi, log ölçek)", fontsize=11)
ax.set_title("Karras gürültü çizelgesi: σ neden ρ-üssü ile düşürülür?",
             fontsize=12.5, weight="bold")

annot = ("σᵢ = (σmax^(1/ρ) + ramp·(σmin^(1/ρ) − σmax^(1/ρ)))^ρ\n"
         "ρ=7 → adımların %36'sı σ<1 bölgesinde (ρ=1'de yalnız %2)\n"
         "detay düşük gürültüde; Karras adımları oraya yığar")
ax.text(0.97, 0.93, annot, transform=ax.transAxes, ha="right", va="top",
        fontsize=9.5, color=COL_TEXT,
        bbox=dict(boxstyle="round,pad=0.5", fc=COL_BG_ROSE,
                  ec=COL_ACCENT, lw=1.4, alpha=0.95))

ax.legend(loc="lower left", frameon=True, fontsize=10, edgecolor=COL_SLATE_400)
apply_style(ax)
plt.tight_layout()
plt.show()
Şekil 25.6: (gerçek hesaplama: Karras sigma çizelgesi ρ=1/3/7 — ρ büyüdükçe düşük-σ (detay) bölgesine çok adım: σ<1 oranı %2→%20→%36; notebook sigmas_karras birebir)
İpucuBuilder Notu — ρ: Adım Bütçesini Nereye Harcamak
  • İleriye: ρ, adımların gürültü seviyeleri arasında nasıl dağıldığını ayarlar — örnekleme kalitesi-hız dengesinin ince ayarı. ρ=7 yaygın varsayılan; daha yüksek ρ detaya daha çok adım.
  • Sezgi: Adım bütçesi sınırlıyken (örn. 50 adım), nereye harcanacağı kritik. Kaba gürültü kabaca giderilebilir (büyük sıçramalar), ama ince detay küçük adımlar ister. ρ=7 ile adımların %36’sı σ<1 bölgesine yığılır (figür) — Karras’ın “detay düşük gürültüde gizli” içgörüsünün sayısal karşılığı.

25.11 10. Daha İyi Örnekleyiciler: Euler

Karras, diffusion örneklemesini bir ODE çözme problemi olarak görür: her adımda görüntünün σ boyunca nasıl değiştiğini (türevi) tahmin et, bir adım ilerle. En basit ODE çözücü Euler yöntemi: türevi ((x − denoised)/σ) hesapla, σ adımı kadar ilerle:

@torch.no_grad()
def sample_euler(x, sigs, i, model):
    sig,sig2 = sigs[i], sigs[i+1]
    denoised = denoise(model, x, sig)
    return x + (x-denoised)/sig*(sig2-sig)
İpucuBuilder Notu — Euler: DDIM’in ODE Karşılığı
  • Geriye (18.065/calculus): Euler yöntemi sayısal ODE çözmenin en temel adımı; diffusion örnekleme = bir ODE’yi adım adım çözmek. DDIM aslında bu ODE’nin bir Euler çözücüsüdür — Ders 21’de hızlandırma diye gördüğümüz şey, meğer bir sayısal ODE yöntemiymiş.
  • Sezgi: Türev (x − denoised)/σ, görüntünün “temiz hâle doğru” yönünü gösterir; σ adımı kadar o yönde ilerlemek bir Euler adımıdır. Tek türev/adım kullandığı için kabadır — büyük adımlarda hata birikir.

25.12 11. Heun’s Method (2. Derece)

Euler kabadır (her adımda tek türev). Heun yöntemi daha akıllıdır: bir Euler adımı atar, varış noktasında türevi tekrar hesaplar, iki türevin ortalamasıyla düzeltir (predictor-corrector). Sonuç: aynı adım sayısında belirgin daha yüksek kalite — az adımda iyi örnekleme.

“called Heun’s method. And Heun’s method does something which we can pictorially see here to decide where to go.” — Howard, 1:15

Şekil 25.7 iki yöntemin yakınsama mertebesini gerçek hesaplamayla karşılaştırır (test ODE üzerinde, dürüst etiket): adım sayısı n arttıkça hata log-log eksende düşer. Euler eğimi ≈ −1.03 (1. derece: adım yarıya inince hata ~2× azalır), Heun eğimi ≈ −2.03 (2. derece: adım yarıya inince hata ~4× azalır). n = 20 adımda fark çarpıcı: Euler 8.9e-3, Heun 1.6e-4 — aynı bütçede ~55× daha doğru. Dürüstlük notu: bu bir test ODE’si (dy/dt = −y², analitik çözüm 1/(1+t)), diffusion ODE’sinin kendisi değil; ama ilke birebir aynıdır — daha yüksek dereceli çözücü, adım başına daha doğru, dolayısıyla daha az adımda yüksek kalite.

Kod
d = E.heun_vs_euler_demo()
steps = d["steps"]
err_e = d["err_euler"]
err_h = d["err_heun"]
slope_e = d["slope_euler"]   # ≈ -1.03  (1. derece)
slope_h = d["slope_heun"]    # ≈ -2.03  (2. derece)

fig, ax = plt.subplots(figsize=(10, 5.5))

# Euler — 1. derece (slate, ince)
ax.loglog(steps, err_e, "-o", color=COL_SLATE_400, lw=2.0, markersize=7,
          markerfacecolor=COL_WHITE, markeredgecolor=COL_SLATE_400,
          markeredgewidth=1.6, label="Euler (1 türev/adım)", zorder=3)
# Heun — 2. derece (rose, kalın)
ax.loglog(steps, err_h, "-s", color=COL_ACCENT, lw=3.2, markersize=8,
          markerfacecolor=COL_ACCENT, markeredgecolor=COL_WHITE,
          markeredgewidth=1.4, label="Heun (2 türev/adım)", zorder=4)

# Eğim etiketleri — eğri ortasına yerleştir
ax.annotate("eğim ≈ −1.03\n(1. derece)", xy=(steps[2], err_e[2]),
            xytext=(steps[2] * 1.25, err_e[2] * 2.6),
            color=COL_SLATE_400, fontsize=10.5, weight="bold", ha="left",
            arrowprops=dict(arrowstyle="-|>", color=COL_SLATE_400, lw=1.5,
                            shrinkA=4, shrinkB=4))
ax.annotate("eğim ≈ −2.03\n(2. derece)", xy=(steps[3], err_h[3]),
            xytext=(steps[3] * 0.30, err_h[3] * 0.18),
            color=COL_ACCENT, fontsize=10.5, weight="bold", ha="left",
            arrowprops=dict(arrowstyle="-|>", color=COL_ACCENT, lw=1.5,
                            shrinkA=4, shrinkB=4))

# n=20 rozeti (steps[2] = 20)
badge = ("n=20 adımda:\nEuler 8.9e-3  vs  Heun 1.6e-4\n— aynı bütçede ~55× doğru")
ax.text(0.97, 0.97, badge, transform=ax.transAxes, ha="right", va="top",
        fontsize=10.5, color=COL_TEXT, weight="bold",
        bbox=dict(boxstyle="round,pad=0.5", fc=COL_BG_ROSE,
                  ec=COL_ACCENT, lw=1.8))

# Köprü/dürüstlük açıklaması
note = ("Heun = predictor-corrector (2 türev/adım, ortalama) = 2. derece Runge-Kutta;\n"
        "18.065 sayısal ODE köprüsü. Diffusion örnekleme de bir ODE — aynı ilke az\n"
        "adımda yüksek kaliteyi verir. (Test ODE dy/dt=−y², analitik 1/(1+t)\n"
        "— diffusion ODE'si değil, ilke aynı.)")
ax.text(0.03, 0.04, note, transform=ax.transAxes, ha="left", va="bottom",
        fontsize=8.8, color=COL_CYAN_800,
        bbox=dict(boxstyle="round,pad=0.45", fc=COL_CYAN_50,
                  ec=COL_CYAN_700, lw=1.3))

apply_style(ax)
ax.set_xlabel("adım sayısı  n  (log)", fontsize=11)
ax.set_ylabel("|hata|  =  |y_sayısal(1) − 1/2|  (log)", fontsize=11)
ax.set_title("Euler vs Heun: aynı adım bütçesinde yakınsama mertebesi",
             fontsize=12.5, weight="bold", color=COL_CYAN_800, pad=10)
ax.legend(loc="lower left", fontsize=10, framealpha=0.95,
          edgecolor=COL_SLATE_300)

plt.tight_layout()
plt.show()
Şekil 25.7: (gerçek hesaplama: Euler vs Heun yakınsama — log-log eğim −1.03 vs −2.03 (1. vs 2. derece); test ODE üzerinde, diffusion örnekleyicilere aynı ilke)
İpucuBuilder Notu — Heun = 2. Derece Runge-Kutta (18.065 KÖPRÜSÜ)
  • Geriye (18.065): Heun = 2. derece Runge-Kutta; sayısal analiz dersinin diffusion’a doğrudan uygulanması. Daha yüksek dereceli çözücü = adım başına daha doğru = daha az adım.
  • Sezgi: Euler bir kez türev alıp “düz çizgide” ilerler; Heun varış noktasında türevi yeniden hesaplayıp iki türevin ortalamasını kullanır (predictor-corrector). Bu ekstra hesap, eğimin −1.03’ten −2.03’e çıkmasını sağlar (figür) — yani hata adım sayısının karesiyle azalır, lineerle değil. Bir ekstra ağ çağrısının bedeli, çok daha hızlı yakınsamayla fazlasıyla geri ödenir.

25.13 12. LMS Sampler (Lineer Çok-Adımlı)

LMS (Linear Multistep) örnekleyici, önceki birkaç adımın türevlerini saklayıp ağırlıklı birleştirir (Adams-Bashforth gibi). Geçmiş bilgiyi kullanarak daha yüksek dereceli doğruluk sağlar — Karras çerçevesindeki güçlü örnekleyicilerden biri:

@torch.no_grad()
def sample_lms(model, steps=100, order=4, sigma_max=80.):
    x = torch.randn(sz).to(model.device)*sigma_max
    sigs = sigmas_karras(steps, sigma_max=sigma_max)
    ds = []
    for i in range(len(sigs)-1):
        denoised = denoise(model, x, sigs[i])
        d = (x-denoised)/sigs[i]
        ds.append(d)
        if len(ds) > order: ds.pop(0)
        # geçmiş türevleri ağırlıklı birleştir (Adams-Bashforth katsayıları)
    return x
İpucuBuilder Notu — LMS: Geçmiş Türevleri Bedava Kullan
  • Geriye (18.065): Çok-adımlı yöntemler sayısal ODE’nin ileri konusu; geçmiş türevleri kullanmak hesap maliyetini artırmadan doğruluğu yükseltir.
  • Sezgi: Heun bir adımda iki türev hesaplar (ekstra ağ çağrısı); LMS ise zaten hesaplanmış geçmiş türevleri saklayıp birleştirir — yeni ağ çağrısı gerektirmez. order=4 ile son dört türevin ağırlıklı toplamı (Adams-Bashforth katsayıları), yüksek dereceli doğruluğu neredeyse bedavaya getirir.

25.14 13. Sonuç: Az Adımda Yüksek Kalite

Bütün bu iyileştirmeler (cosine/sigma çizelge + preconditioning + Heun/LMS) birleşince: aynı eğitilmiş model, çok daha az adımda (örn. 100 yerine ~20-50) DDIM’den daha iyi FID verir. Karras çerçevesi, diffusion’ı pratik ve yüksek kaliteli kılan dönüm noktasıdır.

“a bit better than we had on 100 steps for our previous DDIM.” — Johno, 9:14

İpucuBuilder Notu — Az Adımda Yüksek Kalite: Üretimin Anahtarı
  • İleriye (Ders 25): Bu örnekleyiciler, latent diffusion (Stable Diffusion) ve modern üretimde standart; az adımda yüksek kalite, gerçek-zamanlı üretimin anahtarı.
  • Sezgi: Üç iyileştirme bağımsız ama birbirini güçlendirir: cosine/sigma daha iyi çizelge verir, scalings ağı her σ’da istikrarlı tutar, Heun/LMS az adımda doğru entegrasyon sağlar. Ders 21’de DDIM 100 adımda iyiydi; Karras ~20-50 adımda daha iyi FID — örnekleme maliyetini düşürmek, üretimi pratik kılar.

25.15 14. ETAP Kapanışı: Sıfırdan Diffusion A Tamamlandı

Ders 22, “sıfırdan diffusion A” bloğunu (L19-22) tamamlar. DDPM’i kurduk (L19), hızlandırdık ve eğitimi iyileştirdik (L20), ölçtük ve daha da hızlandırdık (L21 FID/DDIM), şimdi en rafine hâline getirdik (L22 cosine/Karras). Diffusion artık baştan sona bizim — matematiğinden örnekleyicisine.

Şekil 25.8 bu kapanışı dersin sentezi olarak çerçeveler: merkezde çekirdek fikir — L22: diffusion = ODE çözme problemi (sürekli σ, sayısal çözücüler; ayrık 1000 adım değil, bir yörüngeyi entegre etmek). Üstte diffusion evrim zinciri: DDPM (L19, piksel, 1000 adım, lineer β) → DDIM (L21, deterministik, ~50 adım) → Karras (L22, sürekli σ + ön-koşullama + Heun, ~20 adım) → latent diffusion (L25, ileri). Solda köprüler: scalings → Ders 17 varyans korunumu, Euler/Heun/LMS → 18.065 sayısal ODE, cosine ᾱ → Ders 19 schedule, FID ölçütü → Ders 21 “daha iyi mi?”. Sağda ileriye: modern SD samplerları (k-diffusion, DPM++, Euler a, Heun…) hepsi σ-uzayı ODE çözücüleridir — bu çerçevenin türevleri. Altta: ETAP 6 kapanışı, sıfırdan diffusion A tamam.

Kod
fig, ax = plt.subplots(figsize=(12.5, 6.5))
ax.set_xlim(0, 12.5)
ax.set_ylim(0, 6.5)
ax.axis("off")

# --- MERKEZ: çekirdek fikir (büyük vurgu) ---
cx, cy = 6.25, 3.55
boxed_node(
    ax, cx, cy, 4.85, 1.7,
    "L22: diffusion =\n"
    "ODE çözme problemi\n"
    "(sürekli σ, sayısal çözücüler;\n"
    "ayrık 1000 adım değil,\n"
    "bir yörüngeyi entegre etmek)",
    fc=COL_BG, ec=COL_PRIMARY, tc=COL_TEXT,
    fontsize=11.5, lw=2.6,
)

# --- ÜST: diffusion evrim zinciri (oklar, rose) ---
chain = [
    ("DDPM (L19)\npiksel, 1000 adım\nlineer β", 2.30, 5.90),
    ("DDIM (L21)\ndeterministik\n~50 adım", 5.05, 5.95),
    ("Karras (L22)\nsürekli σ + ön-koşullama\n+ Heun, ~20 adım", 8.05, 5.95),
    ("latent diffusion\n(L25)\nileri →", 10.85, 5.90),
]
for txt, mx, my in chain:
    boxed_node(ax, mx, my, 2.55, 1.05, txt,
               fc=COL_BG_ROSE, ec=COL_ROSE_500, tc=COL_TEXT,
               fontsize=8.4, lw=1.9)
# evrim okları (soldan sağa, rose)
for i in range(len(chain) - 1):
    x0 = chain[i][1] + 1.28
    x1 = chain[i + 1][1] - 1.28
    arrow_between(ax, (x0, chain[i][2]), (x1, chain[i + 1][2]),
                  color=COL_ACCENT, lw=2.3, mutation_scale=20)
# merkezden zincire bağ (Karras = merkez fikrin somut hâli)
arrow_between(ax, (8.05, 5.42), (cx + 0.9, cy + 0.9),
              color=COL_ROSE_400, lw=1.9)

# --- SOL: köprüler (cyan) — hangi önceki ders/kurs bileşeni ---
bridges = [
    ("scalings (c_in/c_out)\n→ Ders 17 varyans\nkorunumu", 1.55, 4.55),
    ("Euler / Heun / LMS\n→ 18.065 sayısal ODE", 1.55, 3.35),
    ("cosine ᾱ çizelgesi\n→ Ders 19 schedule", 1.55, 2.15),
    ("FID ölçütü\n→ Ders 21 'daha iyi mi?'", 1.55, 0.95),
]
for txt, bx, by in bridges:
    boxed_node(ax, bx, by, 2.75, 1.0, txt,
               fc=COL_BG, ec=COL_PRIMARY, tc=COL_TEXT,
               fontsize=8.4, lw=1.8)
    arrow_between(ax, (bx + 1.38, by), (cx - 2.48, cy + 0.34 * (by - cy)),
                  color=COL_CYAN_400, lw=1.9)

# --- SAĞ: ileriye / modern bağlantı (rose vurgu) ---
boxed_node(
    ax, 10.85, 3.05, 2.85, 1.85,
    "modern SD\nsamplerları\n(k-diffusion) =\nbu çerçeve\n"
    "(DPM++, Euler a, Heun…\nhepsi σ-uzayı ODE çözücü)",
    fc=COL_BG_ROSE, ec=COL_ACCENT, tc=COL_TEXT,
    fontsize=8.6, lw=2.2,
)
arrow_between(ax, (cx + 2.48, cy - 0.2), (10.85 - 1.45, 3.25),
              color=COL_ROSE_400, lw=2.0)

# --- başlık şeritleri ---
ax.text(6.25, 6.45, "diffusion evrimi: ayrık zincir → sürekli ODE",
        ha="center", va="center", fontsize=10.5, color=COL_ACCENT, weight="bold")
ax.text(1.55, 5.35, "önceki ders + 18.065 köprüleri", ha="center", va="center",
        fontsize=10.0, color=COL_CYAN_700, weight="bold")
ax.text(10.85, 4.35, "ileriye / modern", ha="center", va="center",
        fontsize=10.0, color=COL_ACCENT, weight="bold")
ax.text(6.25, 0.45, "ETAP 6 kapanışı — sıfırdan diffusion A tamam",
        ha="center", va="center", fontsize=10.0, color=COL_CYAN_800,
        weight="bold", style="italic")

plt.tight_layout()
plt.show()
Şekil 25.8: (sentez: L22 = diffusion’ın ODE olarak yeniden çerçevelenişi — DDPM→DDIM→Karras evrimi, Ders 17/19/21 + 18.065 köprüleri; ETAP 6 kapanır)
ÖnemliBuilder Notu — ETAP 6 Kapanışı: Diffusion = ODE (MERKEZÎ)
  • Çekirdek ders: Bu dersten tek bir şey alıp gideceksen: diffusion bir ODE çözme problemidir. Gürültüyü sürekli bir σ ile parametreleyip (ayrık timestep ve çizelgeyi kaldırarak), örneklemeyi bir yörüngeyi entegre etmek olarak görünce, sayısal analizin onlarca yıllık çözücüleri (Euler, Heun, LMS, Runge-Kutta, Adams-Bashforth) doğrudan miras alınır.
  • İki büyük köprü: (1) scalings = Ders 17 varyans korunumu (ağ her σ’da birim varyans görür, Kaiming’in diffusion’a taşınmış hâli); (2) örnekleyiciler = 18.065 sayısal ODE (DDIM bile aslında bir Euler çözücüsü). Bir problemi tanıdık bir çerçeveye oturtmak, o çerçevenin tüm araç kutusunu kazandırır.
  • İleriye (Ders 23-25, SON ETAP): Temel diffusion tam; ETAP 7 (super-res, attention, latent diffusion) bu temeli gerçek Stable Diffusion’a taşır. Karras örnekleyicileri elimizde, sıradaki uygulamalara hazırız.

25.16 15. Kapanış

Ders 22 diffusion’ı en rafine hâline getirdi: cosine schedule (sürekli, daha iyi çizelge), gürültü seviyesi tahmini ve Karras çerçevesi (sürekli σ + preconditioning/scalings + Euler/Heun/LMS örnekleyiciler). Diffusion’ı bir ODE çözme problemi olarak gördük; daha iyi çözücüler az adımda yüksek kalite verdi. “Sıfırdan diffusion A” tamamlandı.

İpucuBuilder Notu — Kapanış: Rafine Diffusion, SON ETAP’ın Zemini
  • İleriye (Ders 23): Karras örnekleyicileri elimizde; SON ETAP super-resolution ile başlayıp attention ve latent diffusion’la gerçek Stable Diffusion’a ulaşır.
  • Sezgi: ETAP 6 boyunca diffusion’ı kara kutudan baştan sona bizim olan bir sisteme çevirdik: matematiği (L19), eğitimi (L20), ölçümü ve hızı (L21), rafine çizelge/örnekleyiciyi (L22). Sıradaki ETAP artık “nasıl çalışır”ı değil, “ne yapabiliriz”i (super-res, koşullu üretim, latent) soracak.

25.17 Bu Dersin Özeti

  1. Cosine schedule: ᾱ(t) = cos(t·π/2)²; lineer β’dan daha iyi, sürekli gürültü dağılımı (t=0.5’te 0.499 vs lineer 0.078) (cosine).
  2. Sürekli zaman: Ayrık 1000 adım yerine t ∈ [0,1]; diffusion’ı sürekli sürece taşır (sürekli zaman).
  3. Gürültü seviyesi tahmini: Ağ timestep’i elle almak yerine gürültü düzeyini çıkarsayabilir; gürültü anlayışının testi (kapalı-form kanıt %8.2 hata) (gürültü tahmini).
  4. Karras çerçevesi: Diffusion’ı sürekli σ (gürültü seviyesi) ile parametreler; çizelgeyi kaldırır (Karras, sürekli sigma).
  5. Preconditioning (scalings): c_in/c_out/c_skip ile ağ her σ’da birim varyans görür (std 0.993–1.006); Ders 17 varyans korunumu (scalings).
  6. denoise: Ağ temiz görüntüyü tahmin eder (scalings ile); gürültü-tahminine denk ama daha kararlı (denoise).
  7. Sigma schedule + ρ: σmax→σmin adımları ρ=7 ile dağıtılır; düşük gürültüye daha çok adım (ρ=7→%36 vs ρ=1→%2) (sigma schedule).
  8. ODE örnekleyiciler: Euler (1. derece, eğim −1.03), Heun (2. derece, eğim −2.03, predictor-corrector), LMS (çok-adımlı); az adımda yüksek kalite (Euler, Heun, LMS).
ÖnemliTek Bir Cümle

Cosine schedule gürültü çizelgesini sürekli ve daha dengeli yapar (ᾱ(t) = cos(t·π/2)²); Karras ise diffusion’ı sürekli gürültü seviyesi σ + preconditioning (scalings, ağ her σ’da birim varyans görsün) + daha iyi ODE örnekleyiciler (Euler/Heun/LMS) çerçevesinde yeniden kurarak, diffusion’ı bir ODE çözme problemi olarak görüp az adımda DDIM’den yüksek kalite verir.

25.18 Kontrol Soruları

Cevap:

Lineer β çizelgesinde (Ders 19) gürültü, zaman boyunca sabit hızla artar; bu, eğitim adımlarının çoğunun “neredeyse tamamen gürültülü” bölgede harcanmasına yol açar — orada öğrenilecek pek bir şey yoktur. Cosine schedule birikimli ᾱ’yı doğrudan bir kosinüs karesiyle tanımlar: ᾱ(t) = cos(t·π/2)². Bu, gürültülenmeyi başta yavaş, ortada hızlı, sonda yine yavaş yapar — modelin zamanını faydalı gürültü seviyelerine daha dengeli dağıtır. Somut fark Şekil 25.2’de: t = 0.5’te cosine ᾱ = 0.499 (sinyalin yarısı korunmuş), lineer ᾱ = 0.078 (sinyalin %92’si çoktan yok). Ayrıca cosine sürekli bir t ∈ [0,1] alır (ayrık adım sayısına bağlı değil) ve kapalı formüllüdür (daha az hiperparametre). Sonuç: daha iyi eğitilmiş model, daha yüksek örnek kalitesi.

Cevap:

DDPM (Ders 19) gürültüyü ayrık bir timestep (t = 0..999) ve buna bağlı bir β/ᾱ çizelgesiyle tanımlar — ağ “hangi adımdayız” bilgisini alır. Karras bunun yerine gürültüyü doğrudan sürekli bir standart sapma σ ile parametreler: gürültülü görüntü = temiz + σ·gürültü. Artık çizelge (β, ᾱ) yoktur; tek soru “şu anki gürültü seviyesi (σ) ne kadar”. Bu daha sadedir (bir hiperparametre kümesi kalkar), daha esnektir (herhangi bir σ kullanılabilir) ve diffusion’ı sürekli bir matematiksel nesneye — bir diferansiyel denkleme (ODE) — dönüştürür. Bu ODE bakışı, Euler/Heun gibi sayısal çözücülerle örneklemeyi mümkün kılar (Euler, Heun).

Cevap:

scalings (c_in, c_out, c_skip), ağın her gürültü seviyesinde birim varyanslı girdi ve çıktı görmesini sağlar. Sorun: σ çok değişken (0.01’den 80’e); ağ böyle farklı ölçeklerdeki girdilerle iyi çalışamaz. Çözüm: c_in girdiyi normalize eder (ağ hep ~birim varyans görür), c_out çıktıyı uygun ölçeğe taşır, c_skip girdinin ne kadarının doğrudan atlanacağını (skip) belirler — hepsi σ ve veri varyansına (sig_data = 0.66) göre hesaplanır. Şekil 25.5 bunu kanıtlar: c_in · noised standart sapması her σ’da ≈ 1.0 (aralık 0.993–1.006), σ dört mertebe değişse de. Bu doğrudan Ders 17’nin varyans korunumu ilkesidir (Kaiming init / BatchNorm): ağ hep iyi-ölçeklenmiş değerlerle çalışsın ki eğitilebilsin (scalings). Yani Karras preconditioning’i, “varyansı sabit tut” fikrinin diffusion’a uyarlanmış hâlidir — foundations’ta (L17) öğrendiğimiz şeyin meyvesi.

Cevap:

DDPM örneklemesi (Ders 19) ayrık, olasılıksal bir süreç gibi görünüyordu — 1000 küçük rastgele adım. Karras bunu sürekli bir adi diferansiyel denklem (ODE) olarak yeniden çerçeveler: görüntünün σ (gürültü seviyesi) boyunca nasıl evrildiğini bir türev tanımlar, örnekleme bu ODE’yi σmax’tan 0’a çözmektir. Bu bakış güçlüdür çünkü sayısal analizin tüm araç kutusunu açar: en basiti Euler (DDIM aslında budur), daha iyisi Heun (2. derece, predictor-corrector — bir adım atıp varışta düzeltir), daha da iyisi LMS (çok-adımlı, geçmiş türevleri kullanır). Daha yüksek dereceli çözücü = adım başına daha doğru = çok daha az adımda yüksek kalite (100 yerine ~20-50). Şekil 25.7 bunu sayısal kanıtlar: Euler yakınsama eğimi −1.03 (1. derece), Heun −2.03 (2. derece) — n=20 adımda Heun ~55× daha doğru. Builder dersi: bir problemi tanıdık bir matematiksel çerçeveye (ODE) oturtmak, o çerçevenin onlarca yıllık çözüm yöntemini (Runge-Kutta, Adams-Bashforth) miras almanı sağlar — 18.065’in diffusion’a doğrudan uygulanması.

25.19 Egzersizler

Egzersiz 1 (Direkt uygulama). abar(t) = cos(t·π/2)² cosine çizelgesini çiz; lineer ᾱ ile karşılaştır, gürültülenmenin nasıl farklı dağıldığını gör (t=0.5’te 0.499 vs 0.078) (§1).

Egzersiz 2 (İki-aşamalı). sigmas_karras’ı farklı ρ değerleriyle (1, 3, 7) çiz; ρ’nun adımları gürültü seviyeleri arasında nasıl dağıttığını gözle (σ<1 oranı %2→%20→%36) (§9).

Egzersiz 3 (Edge case). sample_euler ve sample_heun’u aynı adım sayısıyla çalıştır, FID’lerini karşılaştır; Heun’un neden daha iyi olduğunu açıkla (2. derece, predictor-corrector) (§10, §11).

Egzersiz 4 (Kavramsal). scalings (c_in/c_out/c_skip) neden gereklidir? σ çok değişkenken ağ neden birim varyanslı girdi görmeli (Ders 17 bağlantısı)? (§7)

Egzersiz 5 (Sonraki dersin habercisi — Ders 23). Diffusion’ı koşullu hâle getirmek (örn. düşük çözünürlüklü görüntüden yüksek çözünürlük) nasıl mümkün olur? Super-resolution’ın bir diffusion problemi olduğunu düşün.

25.20 Sonraki: Ders 23 İçin Hazırlık

Ders 23: Super-Resolution (SON ETAP başlangıcı)

Ders 22 diffusion’ı en rafine hâline getirdi (cosine + Karras). ETAP 7 (SON ETAP, L23-25) bu temeli gerçek uygulamalara taşır. Ders 23 super-resolution ile başlar: düşük çözünürlüklü bir görüntüden yüksek çözünürlüklü üretmek — koşullu diffusion’ın güzel bir örneği.

Ana konular (Ders 23):

  • Koşullu diffusion (düşük-çöz → yüksek-çöz)
  • U-Net’i koşullama
  • Perceptual/feature loss
  • Üretim kalitesi değerlendirme (FID ile)
UyarıDers 23 Öncesi Yapılacak
  • Bu dersin egzersizlerini çöz (özellikle 1 ve 3 — cosine + Euler/Heun).
  • Karras örnekleyicilerle (Heun) DDPM modelini ~30 adımda örnekle, FID ölç.
  • Ders 21 FID ve Ders 22 Karras örnekleyicileri tekrar gözden geçir.

25.21 Anahtar Kavramlar (Cheat Sheet)

Kavram Tanım Howard’da
Cosine schedule ᾱ(t) = cos(t·π/2)²; sürekli, dengeli çizelge 0:35
Sürekli zaman Ayrık adım yerine t ∈ [0,1] 5:06
Gürültü seviyesi tahmini Ağ timestep’i değil gürültü düzeyini çıkarsar 19:03
Karras “Elucidating the Design Space”; birleştirici çerçeve 38:48
Sürekli σ Gürültü = temiz + σ·noise; çizelgesiz parametre 38:48
scalings c_in/c_out/c_skip; ağ her σ’da birim varyans görür 30:30
denoise Ağ temiz görüntüyü tahmin eder (scalings ile)
Sigma schedule (ρ) σmax→σmin, ρ=7 ile adım dağılımı 1:07:25
Euler sampler 1. derece ODE çözücü (DDIM’e denk)
Heun’s method 2. derece ODE (predictor-corrector); az adımda iyi 1:15
LMS sampler Çok-adımlı (geçmiş türevler); yüksek derece
Diffusion = ODE Örnekleme bir ODE çözme; sayısal çözücüler uygulanır

25.22 ML Bağlantıları Özeti

İpucuBuilder Notu — 6 ML Köprüsü: Çizelge, Varyans ve Sayısal ODE

Bu ders üç iyileştirmeyi (cosine, gürültü tahmini, Karras) önceki derslerin altyapısına bağlar ve “diffusion = ODE” felsefesini ortaya koyar; köprülerin özeti:

  1. Cosine schedule → Ders 19 ᾱ çizelgesi; sürekli, kapalı formüllü iyileştirme (cosine).
  2. Karras scalings → Ders 17 varyans korunumu (Kaiming/BatchNorm); ağ her σ’da birim varyans (scalings).
  3. Diffusion = ODE → 18.065 sayısal ODE (Euler/Heun/Runge-Kutta); örnekleme = ODE çözme (Euler).
  4. Heun/LMS → 18.065 yüksek dereceli çözücüler; az adımda yüksek doğruluk (Heun, LMS).
  5. Sürekli σ → Ders 21 DDIM’in deterministik ODE bakışının genellemesi (sürekli sigma).
  6. denoise (temiz görüntü tahmini) → Ders 19 ε-tahmini ile denk; sayısal olarak daha kararlı (denoise).
ÖnemliBu dersten tek bir şey alıp gideceksen

Bu dersten tek bir şey alıp gideceksen: diffusion bir ODE çözme problemidir. Karras, gürültüyü sürekli bir σ ile parametreleyip (ayrık timestep ve çizelgeyi kaldırarak), ağa preconditioning (scalings) ile her σ’da birim varyans gösterip (Ders 17’nin varyans korunumu — figürde c_in·noised std 0.993–1.006), ve örneklemeyi bir ODE olarak görüp sayısal analizin güçlü çözücülerini (Euler, Heun, LMS — Heun yakınsama eğimi −2.03, Euler −1.03) uygulayarak diffusion’ı en rafine hâline getirdi. Sonuç: çok daha az adımda yüksek kalite. “Sıfırdan diffusion A” tamamlandı; sıradaki SON ETAP gerçek Stable Diffusion’a ulaşacak.