Ainsteinx Logo
Ainsteinx
👤
ยินดีต้อนรับสู่ Ainsteinx
เข้าสู่ระบบ

เปลี่ยนภาษา

สกุลเงิน

หน้าแรก
บล็อก
บริการ
บทที่ 03 · 6 เทคนิคหลัก

Variational Autoencoder (VAE)

บีบภาพเป็นจุดใน latent space แล้ววาดภาพใหม่จากจุดสุ่ม

Autoencoder มี encoder บีบภาพเป็นเวกเตอร์เล็ก (latent) และ decoder สร้างภาพกลับ แต่ latent space มีช่องว่าง จึงสุ่มภาพใหม่ได้ไม่ดี

VAE แก้โดยให้ encoder ออกเป็นการแจกแจง (μ, σ) และใช้ KL divergence ดึงให้ใกล้ N(0, I) หลังฝึกแค่สุ่ม z จาก N(0, I) แล้ว decode ก็ได้ภาพใหม่ โค้ดตัวอย่างวาดตัวเลข 8×8 ออกมาเป็นตัวอักษร

z = μ + σ · ε, ε ~ N(0, I) ← reparameterization trick loss = reconstruction(x, x̂) + β · KL( N(μ, σ²) ‖ N(0, I) ) KL = −½ Σ (1 + log σ² − μ² − σ²)
Reconstruction lossให้ภาพที่สร้างกลับคล้ายภาพต้นฉบับ
KL lossให้ latent space ต่อเนื่อง ไม่มีรู จึงสุ่มได้

สิ่งที่ควรจำ

  • VAE = autoencoder + ความสุ่ม + KL
  • คำนวณเวกเตอร์ใน latent space ได้ เช่น ใบหน้า + "แว่นตา" = ใบหน้าใส่แว่น
generative-ai-ep03-vae.py
import torch, torch.nn as nn
from sklearn.datasets import load_digits

torch.manual_seed(0)
X = torch.tensor(load_digits().data / 16.0, dtype=torch.float32)   # 8x8 digits

class VAE(nn.Module):
    def __init__(self, z=2):
        super().__init__()
        self.enc = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, 2 * z))
        self.dec = nn.Sequential(nn.Linear(z, 128), nn.ReLU(), nn.Linear(128, 64), nn.Sigmoid())

    def forward(self, x):
        mu, logvar = self.enc(x).chunk(2, dim=1)
        z = mu + torch.randn_like(mu) * torch.exp(0.5 * logvar)    # reparameterization trick
        return self.dec(z), mu, logvar

vae = VAE()
opt = torch.optim.Adam(vae.parameters(), lr=1e-3)
for epoch in range(200):
    recon, mu, logvar = vae(X)
    rec = nn.functional.binary_cross_entropy(recon, X, reduction="sum") / len(X)
    kl = -0.5 * torch.sum(1 + logvar - mu ** 2 - logvar.exp()) / len(X)
    loss = rec + kl
    opt.zero_grad(); loss.backward(); opt.step()
    if epoch % 50 == 49:
        print(f"epoch {epoch + 1}  reconstruction {rec.item():.1f}  KL {kl.item():.2f}")

# Generate: decode random points from N(0, I)
with torch.no_grad():
    sample = vae.dec(torch.randn(1, 2)).view(8, 8)
for row in sample:
    print("".join(" .:-=+*#%@"[int(v * 9.99)] for v in row))

ผลลัพธ์

epoch 50  reconstruction 29.1  KL 1.31
epoch 100  reconstruction 27.7  KL 0.97
epoch 150  reconstruction 26.7  KL 1.09
epoch 200  reconstruction 25.5  KL 1.42
..=%#+..
 :%*+#:.
.:#:-#..
..+=+#: 
 .: :#:.
  .  *-.
  +-=#-.
..-%%+..
  • #GenerativeAI
  • #DeepLearning
  • #PythonສຳລັບຄົນLaos
  • #AI
  • #ບອກຕໍ່ຄວາມຮູ້