🎨 GAN Lab - Od Autoencoderu ke Generátoru

OpenTechLab Jablonec nad Nisou · Science Micro Elementary School

Naučili jsme se, že Decoder z autoencoderu umí vytvořit obrázek z malého vektoru. Co kdybychom ho naučili generovat nové obrázky bez originálu?

🔗 Jak GAN navazuje na Autoencoder?

🔺 Decoder z Autoencoderu

Latentní vektor → Obrázek
Umí rekonstruovat, co viděl

🎨 Generator v GAN

Náhodný šum → Nový obrázek
Učí se tvořit od nuly!

🧠 Klasifikátor (CNN)

Obrázek → Třída (0-9)
Rozpoznává co vidí

🔍 Discriminator v GAN

Obrázek → Real/Fake
Rozpoznává padělky!

⚙️ Ovládání


🎨 Generátor

🔍 Diskriminátor

D silnější G silnější
⚖️ Vyrovnaný trénink
Krok: 0
G Loss:
D Loss:
📈 Historie Loss
🎨
Generátor
0%
VS
🌱
Připraven
🔍
Diskriminátor
100%

🧠 Architektura sítí:

Real vs Fake porovnání:

✨ Generované obrázky

💡 Co sleduješ:

  • Na začátku G generuje šum
  • D snadno rozpozná fake (100% přesnost)
  • G se učí klamat, D se učí odhalovat
  • Ideální stav: oba na ~50%

🧠 Od Autoencoderu ke GAN (Návaznost)

GAN využívá Decoder z autoencoderu jako svůj Generátor. Ale je tu klíčový rozdíl:

1️⃣
Autoencoder Decoder
Vstup = latent z encoderu (naučený)
2️⃣
GAN Generátor
Vstup = náhodný šum (z normálního rozdělení)

Klíčová změna: Místo rekonstrukce existujícího obrázku se G učí tvořit od nuly - přeměnit náhodný šum na realistický obrázek!

Porovnání architektury:
Autoencoder
784 → Encoder → 2 → Decoder → 784
Cíl: zrekonstruovat vstup
GAN
šum(4) → G → 64 → D → real/fake
Cíl: oklamat diskriminátor
G = Decoder bez Encoderu
+ nový "učitel" = Diskriminátor

💡 Klíčový insight: V autoencoderu decoder věděl, co má generovat (rekonstruovat vstup). V GAN nemá decoder (G) žádný cíl - učí se ho od D! D říká "tohle vypadá fake" a G se přizpůsobuje.

🔢 Proč má G 4 vstupy a D 1 výstup?

🎨 Generátor: 4 vstupní neurony

z = [0.3, -0.7, 1.2, 0.1] → G → 64 pixelů

4 náhodná čísla = "souřadnice v latentním prostoru". Každá kombinace 4 čísel vytvoří jiný obrázek!

Proč právě 4?
  • Málo → omezená variabilita (všechny obrázky podobné)
  • Moc → těžší trénování, více parametrů
  • 4 → dobrý kompromis pro 8×8 obrázky

🔍 Diskriminátor: 1 výstupní neuron

64 pixelů → D → P(real) ∈ [0,1]

1 číslo = pravděpodobnost, že obrázek je skutečný. Sigmoid aktivace → výstup vždy mezi 0 a 1.

Interpretace výstupu:
0.0
100% fake
0.5
nejistý
1.0
100% real

💡 Klíčový insight: G transformuje 4D prostor → 64D prostor (rozbaluje šum na obrázek). D transformuje 64D prostor → 1D (komprimuje obrázek na jedno rozhodnutí). Jsou to opačné operace - proto má GAN tu zajímavou symetrii!

⚔️ Adversarial Training - Soupeření dvou sítí

🎨 Generátor (Padělatel)

Vstup: Náhodný šum z
Výstup: Falešný obrázek
Cíl: Oklamat D (D(G(z)) → 1)

⚔️ Souboj

G se snaží oklamat
D se snaží odhalit
Min-Max hra

🔍 Diskriminátor (Detektiv)

Vstup: Real nebo Fake obrázek
Výstup: P(real) ∈ [0,1]
Cíl: Správně klasifikovat (real→1, fake→0)

💡 Analogie: Padělatel (G) se učí kreslit bankovky. Detektiv (D) se učí rozpoznávat padělky. Čím lepší je detektiv, tím lepší musí být padělatel - a naopak. Když oba dosáhnou 50% úspěšnosti, padělky jsou k nerozeznání od originálu!

📐 Matematický přehled

🔍 Diskriminátor Loss

LD = -[log D(x) + log(1 - D(G(z)))]

x = real obrázek, z = náhodný šum
D chce: D(x)→1 (real) a D(G(z))→0 (fake)

🎨 Generátor Loss

LG = -log D(G(z))

G chce: D(G(z))→1
(D si myslí, že fake je real)

🎯 Min-Max Hra (Hodnota hry)

minG maxD V(D,G) = E[log D(x)] + E[log(1 - D(G(z)))]

D maximalizuje V (správně klasifikuje), G minimalizuje V (oklame D). V rovnováze: D(G(z)) = 0.5 pro všechny vzorky.

⚠️ Nash Equilibrium

G: 50%
oklame D
= Rovnováha
ideální stav
D: 50%
odhalí fake

Nash equilibrium: Ani G ani D nemůže jednostranně zlepšit svou pozici. D jen hádá (50/50), protože fake jsou k nerozeznání od real!

🔄 Fundamentální změna: Cíl NENÍ Loss = 0!

❌ Klasické sítě (MLP, CNN, Autoencoder)

Loss → 0
čím menší, tím lepší

Jeden jasný cíl: minimalizovat chybu.
Síť se přibližuje k "dokonalé" odpovědi.
Loss klesá → trénink úspěšný.

✅ GAN (Adversarial sítě)

Loss ≈ konstanta
"dynamický chaos"

Dva protivníci, dva cíle.
Když jeden vítězí, druhý prohrává.
Loss osciluje → rovnováha = úspěch!

📊 Jak vypadá úspěšný trénink GAN?

🚫 Špatně:
  • D Loss → 0 (D je moc silný, G se nemůže učit)
  • G Loss → 0 (G našel jeden trik - mode collapse)
  • Jedna ztráta klesá, druhá roste
✅ Správně:
  • Obě loss oscilují kolem konstanty
  • Battle Score → 50% / 50%
  • Ani jeden nedominuje dlouhodobě

💡 Klíčový insight: V GAN hledáme rovnováhu, ne minimum. Ideální stav je, když D jen hádá (50/50), protože fake jsou k nerozeznání od real. To znamená, že obě sítě jsou stejně silné — a to je přesně to, co chceme! Proto sledujeme "Battle Score" místo ztráty.

⚠️ Časté problémy při trénování GAN

💀 Mode Collapse

G se naučí generovat jen jeden typ obrázku, který oklame D. Přestane explorovat - proč riskovat, když tohle funguje?

Řešení: Větší batch size, různé z vzorky, regularizace

📉 Vanishing Gradient

D je moc silný a vždy správně identifikuje fake. Gradient pro G je pak ~0 a G se nemůže učit.

Řešení: Label smoothing, slabší D, balance slider

🎢 Nestabilní trénink

Loss osciluje, D a G se "honí" - jakmile se jeden zlepší, druhý se zhorší. Nikdy nedosáhnou rovnováhy.

Řešení: Menší learning rate, více kroků D před G

🔀 Helvetica Scenario

G produkuje vizuálně různé obrázky, ale všechny jsou ve skutečnosti podobné v latentním prostoru.

Řešení: Minibatch discrimination, feature matching

🛠️ K čemu je GAN v praxi?

🎨 Generování obrázků

StyleGAN, DALL-E, Midjourney - tvorba realistických tváří, umění, fotografií. Neexistující lidé na thispersondoesnotexist.com.

🔄 Image-to-Image

Pix2Pix, CycleGAN - přeměna skic na fotky, koně na zebry, léto na zimu.

📈 Super-Resolution

SRGAN - zvětšení rozlišení fotek a videí. Remaster starých filmů a her.

🎭 Deepfakes

Výměna tváří ve videu, voice cloning. ⚠️ Etické obavy - dezinformace, manipulace.

💻 Implementační průvodce

1. Trénovací krok Diskriminátoru
function trainDiscriminator(realSample, lr) {

    // 1. Trénuj na REAL (target = 1, s label smoothing = 0.8)

    const realOut = D.forward(realSample);

    const realError = realOut - 0.8;

    D.backward([realError], lr);

    

    // 2. Trénuj na FAKE (target = 0, s label smoothing = 0.2)

    const z = sampleLatent();

    const fake = G.forward(z);

    const fakeOut = D.forward(fake);

    const fakeError = fakeOut - 0.2;

    D.backward([fakeError], lr);

    

    return (realError**2 + fakeError**2) / 2;

}
2. Trénovací krok Generátoru
function trainGenerator(lr) {

    // G chce aby D řekl "tohle je real" (target = 1)

    const z = sampleLatent();

    const fake = G.forward(z);

    const dOut = D.forward(fake);

    

    // Chyba: jak daleko je D od 1?

    const error = dOut - 1;

    

    // Backprop přes D (bez update!) a pak přes G (s update)

    const dGrad = D.computeGradient([error]);  // jen gradient, ne update!

    G.backward(dGrad, lr);                      // update G podle gradientu z D

    

    return error ** 2;

}
3. Hlavní trénovací smyčka
function trainStep() {

    const realSample = dataset[randomIndex()];

    

    // Nejprve trénuj D (aby uměl rozlišovat)

    const dLoss = trainDiscriminator(realSample, lr);

    

    // Pak trénuj G (aby uměl klamat)

    const gLoss = trainGenerator(lr);

    

    // Sleduj skóre

    updateStats(gLoss, dLoss);

}
4. Měření Battle Score (reálná úspěšnost)
function computeBattleScore(batchSize = 32) {

    let pRealSum = 0;

    

    for (let i = 0; i < batchSize; i++) {

        const z = sampleLatent();

        const fake = G.forward(z);

        const pReal = D.forward(fake);  // Jak moc D věří, že fake je real?

        pRealSum += pReal;

    }

    

    const avgPReal = pRealSum / batchSize;

    // Normalizace z rozsahu [0.2, 0.8] (label smoothing) na [0, 100]%

    const genScore = Math.round(((avgPReal - 0.2) / 0.6) * 100);

    return { genScore, discScore: 100 - genScore };

}

🎯 Shrnutí klíčových konceptů

Generátor
šum → obrázek (klamání)
Diskriminátor
obrázek → real/fake
Adversarial
Min-Max hra, soupeření
Rovnováha
Nash equilibrium = 50/50