Mundarija (23)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Avtoenkoder
- 2.2. Latentdagi "teshiklar"
- 2.3. VAE: ELBO = qayta tiklash - KL
- 2.4. Reparametrizatsiya hiylasi
- 2.5. Latent fazo tuzilishi
- 2.6. beta-VAE
- 2.7. Shartli VAE (CVAE)
- 2.8. Posterior collapse
- 2.9. Tuzoqlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Avtoenkoder: siqish va latentdagi teshiklar
- Misol 2 — VAE noldan: reparametrizatsiya va ELBO
- Misol 3 — Latent xarita, beta-VAE va interpolatsiya
- Misol 4 — Shartli VAE va posterior collapse
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
26.2-dars: Avtoenkoder va VAE
26-QISM — GENERATIV AI · 2-dars
1. Kirish va motivatsiya
26.1-darsda generativ model p(x) ni o'rganishini va uni baholash uchun bitta log-likelihood yetmasligini ko'rdik. U yerda eng yaxshi natijani PCA + GMM berdi: avval 64 pikselni 20 o'lchovga siqdik, keyin siqilgan fazoda oddiy taqsimot o'rgatdik. Bu darsda xuddi shu g'oyani neyron tarmoq bilan qilamiz: siqishni ham, qayta tiklashni ham o'rganadigan tarmoq — avtoenkoder — va uning generativ versiyasi — VAE (variatsion avtoenkoder).
Avtoenkoder oddiy: encoder rasmni kichik vektorga (latent kodga) siqadi, decoder shu koddan rasmni qayta tiklaydi. U PCA ning nochiziqli umumlashmasi. Tabiiy savol tug'iladi: agar decoder koddan rasm chiza olsa, unga tasodifiy kod bersak, yangi rasm chizmaydimi? Chizadi — lekin ko'pincha bema'ni narsa. Sababi: oddiy avtoenkoder kodlarni fazoning qayeriga joylashtirishni hech kim nazorat qilmaydi, kodlar orasida esa "teshiklar" qoladi. VAE bu muammoni hal qiladi: u kodlarni oldindan belgilangan taqsimotga — standart normal N(0, I) ga — yaqin turishga majbur qiladi. Shunda namuna olish oddiy: z ~ N(0, I), keyin decoder.
Real vaziyat. Dizayn jamoasi mahsulot ikonkalari uchun avtoenkoder o'rgatdi: qayta tiklash ajoyib edi, test rasmlari deyarli aynan qaytardi. Keyin "yangi ikonkalar" yaratish uchun latent koddan tasodifiy namunalar olindi — va natijalar dog'lar va buzilgan shakllar bo'lib chiqdi. Jamoa arxitekturani kattalashtirdi, qayta tiklash yanada yaxshilandi, namunalar esa yaxshilanmadi. Muammo decoderda emas, latent fazoning tuzilishida edi. Bu darsning 1-misoli aynan shu holatni o'lchaydi, 2-misoli esa VAE qanday tuzatishini ko'rsatadi.
Bu darsda avtoenkoderni PCA bilan solishtiramiz, latentdagi "teshiklar"ni o'lchaymiz, VAE ni noldan yozamiz (ELBO va reparametrizatsiya hiylasi), latent fazo tuzilishini ko'ramiz, beta-VAE murosasini va shartli VAE ni o'lchaymiz, va posterior collapse tuzog'iga duch kelamiz.
Bu darsda:
- Avtoenkoder: siqish, qayta tiklash, latent kod
- Nega oddiy AE latentidan namuna olish yomon ishlaydi
- VAE: ELBO = qayta tiklash - KL
- Reparametrizatsiya hiylasi
- Latent fazo tuzilishi: xarita va interpolatsiya
- beta-VAE: qayta tiklash va KL murosasi
- Shartli VAE
- Posterior collapse
- Tuzoqlar
ℹ Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU).
2. Nazariya — chuqur tushuntirish
2.1. Avtoenkoder
TUZILISH:
x (64) -> encoder -> z (d) -> decoder -> x_hat (64)
"tor bo'g'iz": d < 64 -> tarmoq faqat muhim ma'lumotni saqlashga majbur
loss = qayta tiklash xatosi: MSE yoki BCE (piksellar [0, 1] da)
PCA BILAN BOG'LIQLIK:
chiziqli encoder/decoder + MSE -> PCA bilan bir xil fazoni topadi
nochiziqli (ReLU) -> egri sirtlarni ham siqadi
1-misol, test MSE (piksel [0, 1]):
d = 2: PCA 0.0530, AE 0.0365
d = 8: PCA 0.0246, AE 0.0122 (ikki barobar kam)
d = 16: PCA 0.0115, AE 0.0065
QAYERDA ISHLATILADI:
siqish, shovqinni tozalash (denoising AE), anomaliya aniqlash
(qayta tiklash xatosi katta - g'ayrioddiy), oldindan o'rgatish,
diffusion modellarda "latent fazo" (Matn-rasm modellari darsida) Avtoenkoder — o'rganiladigan, nochiziqli PCA: bir xil d da u PCA dan ancha yaxshi qayta tiklaydi, lekin bu hali generativ model emas.
2.2. Latentdagi "teshiklar"
MUAMMO:
AE loss faqat "koddan rasmni tikla" deydi
kodlar QAYERDA va QANDAY zichlikda joylashishi - nazoratsiz
kodlar orasidagi bo'shliqlarni decoder hech qachon ko'rmagan
1-MISOL (d = 8):
o'quv kodlari: o'rtacha norma 7.07, koordinata std 1.64 .. 2.51
-> N(0, I) umuman boshqa joyda (normasi ~ sqrt(8) = 2.8)
"teshik" = eng yaqin o'quv kodigacha masofa > test kodlarining 95-foizili
z manbasi ishonch>0.9 teshikda
N(0, I) 0.348 0.964
N(mu, Sigma) 0.594 0.502 (kodlarga Gauss moslab)
test kodlari 0.920 0.051 (ma'lumotnoma)
XULOSA:
hatto kodlarning o'rtacha va kovariatsiyasiga moslangan Gauss ham
namunalarning yarmini teshiklarga tashlaydi
-> kodlar taqsimoti Gauss emas; decoder u joylarda nima chizishni bilmaydiQayta tiklash yaxshi — namuna olish yaxshi degani emas: oddiy AE ning latent fazosi bo'shliqlarga to'la, chunki uni hech kim tartibga solmagan.
2.3. VAE: ELBO = qayta tiklash - KL
GENERATIV MODEL:
z ~ p(z) = N(0, I) prior
x ~ p(x | z) = Bernoulli(decoder(z)) (har piksel)
p(x) = integral p(x | z) p(z) dz <- hisoblab bo'lmaydi
ENCODER = TAXMINIY POSTERIOR:
q(z | x) = N(mu(x), diag(sigma(x)^2))
encoder bitta nuqta emas, TAQSIMOT beradi
ELBO (evidence lower bound):
log p(x) >= E_q[log p(x | z)] - KL(q(z | x) || p(z)) = ELBO
^ qayta tiklash ^ kod priorga yaqin bo'lsin
loss = -ELBO = qayta_tiklash + KL
KL NING YOPIQ FORMULASI (ikkita Gauss):
KL = 0.5 * sum_j (mu_j^2 + sigma_j^2 - 1 - log sigma_j^2)
mu = 0, sigma = 1 bo'lsa - nol
NEGA TESHIKLAR YO'QOLADI:
KL har kodni N(0, I) ga tortadi -> kodlar prior atrofida zich
sigma > 0 -> decoder har kod ATROFIDAGI butun sohani ko'radi
2-misol: VAE, z ~ N(0, I) -> teshikda 0.094 (AE N(mu, Sigma): 0.581)
2-MISOL TEST QIYMATLARI (nat/rasm, d = 8):
qayta tiklash 21.07 + KL 3.40 = -ELBO 24.47
AE qayta tiklashi 16.54 - KL jarimasi yo'q, shuning uchun yaxshiroqVAE ikki kuchni muvozanatlaydi: qayta tiklash kodni ma'lumotga, KL esa priorga tortadi; shu tufayli priordan olingan kod decoder tanigan joyga tushadi.
2.4. Reparametrizatsiya hiylasi
MUAMMO:
loss = E_{z ~ q(z|x)}[f(z)]; z - TASODIFIY namuna
z = torch.normal(mu, sigma) -> z.requires_grad = False
gradient mu va sigma ga (demak encoderga) yetib bormaydi
YECHIM:
eps ~ N(0, I) (parametrga bog'liq emas)
z = mu + sigma * eps (mu va sigma ning differensiallanuvchi funksiyasi)
tasodif "chetga" chiqarildi; gradient mu va sigma orqali oqadi
2-MISOL TEKSHIRUVI: f(z) = (z - 3)^2, mu = 1, sigma = 1
aniq: E[f] = (mu - 3)^2 + sigma^2 -> d/dmu = -4, d/dlogvar = sigma^2 = 1
reparam (10000 eps): -4.021 va 1.025
MUQOBIL - REINFORCE (score function):
grad = E[f(z) * d log q(z) / d mu] - har qanday f uchun ishlaydi
lekin dispersiyasi katta: bitta namunali baho std
reparam 2.00, REINFORCE 9.44 (4.7 barobar shovqinliroq)
diskret latentlar (reparam imkonsiz) uchun ishlatiladi z = mu + sigma * eps — tasodifni parametrdan ajratadi va gradientni encoderga o'tkazadi; bu VAE ni oddiy backprop bilan o'rgatish imkonini beradi.
2.5. Latent fazo tuzilishi
2D LATENT XARITASI (3-misol):
z to'ri [-2, 2]^2 -> decoder -> hakam sinfi
qo'shni nuqtalar - o'xshash raqamlar; sinflar yaxlit "orollar"
orollar orasidagi chegaralarda - noaniq rasmlar ('.' ulushi 0.140)
test kodlarining 0.940 qismi [-2, 2]^2 ichida - prior sohasi to'la ishlatilgan
INTERPOLATSIYA:
z(t) = (1 - t) * z_0 + t * z_1, t = 0 .. 1
latentda: shakl asta-sekin o'zgaradi (0 -> ... -> 1)
pikselda: ikki rasm ustma-ust tushadi (shaffof "arvoh")
3-misol: 200 juftning o'rta nuqtasi, ishonch > 0.9:
latentda 0.555, pikselda 0.515 - o'rta nuqta ko'pincha noaniq raqam
LATENT ARIFMETIKA (umumiy ma'lum g'oya):
"tabassumli yuz" - "neytral yuz" + "boshqa odam" -> boshqa odam tabassumi
bu faqat latent fazo silliq va tuzilgan bo'lsa ishlaydiVAE latent fazosi silliq: yaqin kodlar yaqin rasmlar beradi, shuning uchun unda yurish, interpolatsiya va xarita qilish mumkin.
2.6. beta-VAE
loss = qayta_tiklash + beta * KL
beta < 1: kodlar ko'proq ma'lumot saqlaydi -> qayta tiklash yaxshi,
lekin prior bilan moslik yomonlashadi
beta > 1: kod priorga kuchliroq tortiladi -> "ajralgan" (disentangled)
omillar, lekin qayta tiklash yomon; juda katta beta - collapse
3-MISOL (3 urug', d = 8, test):
beta qayta tiklash KL ishonch>0.9 sinf entropiyasi faol o'lchov
0.5 19.85 5.60 0.607 0.994 8.0
1.0 21.90 2.95 0.586 0.994 7.7
4.0 27.29 0.00 0.995 0.000 0.0
beta 0.5: qayta tiklash sezilarli yaxshi (-2.049, SE 0.115),
namuna ishonchi farqi sezilarli emas (+0.021, SE 0.023)
beta 4: KL = 0 - latent butunlay o'chdi; 1000 namunaning hammasi bir xil
"o'rtacha raqam", hakam uni 8 deb 0.995 ishonch bilan taniydi beta — qayta tiklash va prior orasidagi tugma; uni bitta o'lchov bilan tanlamang: beta = 4 da "ishonch" eng yuqori, chunki hamma namuna bitta raqam.
2.7. Shartli VAE (CVAE)
p(x | z, y), q(z | x, y); y - sinf (one-hot), encoder va decoderga qo'shiladi
generatsiya: y ni o'zimiz beramiz, z ~ N(0, I)
"menga 7 chiz" -> decoder(z, y = 7)
MA'NO BO'LINISHI:
y - QAYSI raqam; z - QANDAY yozilgan (qalinlik, qiyalik, uslub)
bitta z + turli y -> bir xil uslubda turli raqamlar (ideal holda)
4-MISOL:
so'ralgan sinf to'g'ri: 1.000 (hamma 10 sinfda)
lekin sinf ichidagi xilma-xillik: CVAE 0.803, haqiqiy test 2.284
z juda kam ma'lumot tashiydi (KL 0.91 nat) - "uslub" deyarli yo'q Shartli VAE sinfni qat'iy boshqaradi, lekin uslubni z tashiydi — va z bo'sh qolishi mumkin; to'g'ri sinf ulushi bilan birga xilma-xillikni ham o'lchang.
2.8. Posterior collapse
HODISA:
KL(q(z | x) || p(z)) -> 0: encoder x ga qaramay N(0, I) ni qaytaradi
decoder z ni e'tiborsiz qoldirib, "o'rtacha" rasmni chizadi
"faol o'lchov": test ustida Var(mu_j(x)) > 0.01
NEGA YUZ BERADI:
KL jarimasi har nat axborot uchun "narx" oladi
agar decoder z siz ham yetarli yaxshi bo'lsa (kuchli decoder, katta beta,
yoki shart y allaqachon asosiy ma'lumotni bersa) - z ishlatilmaydi
4-MISOL (o'lchovlar bo'yicha KL, nat):
VAE beta=1: jami 3.17, faol 7
CVAE beta=1: jami 0.91, faol 3 <- sinf y da, z ga kam ish qoldi
VAE beta=4: jami 0.00, faol 0 -> bitta sinf, hamma namuna bir xil
CVAE beta=4: jami 0.00, faol 0 -> 10 sinf to'g'ri, lekin xilma-xillik 0.205
YECHIMLAR:
KL annealing: beta ni 0 dan 1 ga asta-sekin oshirish
free bits: har o'lchov KL i ma'lum chegaradan past bo'lsa jarima yo'q
kuchsizroq decoder yoki kichikroq beta
diagnostika: har doim KL ni o'lchov bo'yicha va faol o'lchovlar sonini chop etingKL nolga yaqin bo'lsa — bu "zo'r moslik" emas, latentning o'limi; faol o'lchovlar sonini va namunalar xilma-xilligini doim tekshiring.
2.9. Tuzoqlar
Asosiy tuzoqlar: avtoenkoder qayta tiklashi yaxshi bo'lsa, undan namuna olish ham yaxshi deb o'ylash; AE latentidan N(0, I) bilan namuna olish (kodlar u yerda emas); torch.normal(mu, sigma) bilan namuna olib, encoder o'rganmayotganini sezmaslik; sigma o'rniga logvar ni to'g'ridan-to'g'ri ishlatish (manfiy "dispersiya") — to'g'risi sigma = exp(0.5 * logvar); KL ni o'lchovlar bo'yicha yig'ish o'rniga o'rtachalash (piksellar yig'indisi bilan nomutanosib — beta ni amalda o'zgartiradi); qayta tiklashni piksellar bo'yicha o'rtacha, KL ni esa yig'indi qilish; test ELBO ni hisoblashda urug'siz shovqin; VAE ni faqat qayta tiklash bilan AE dan "yomon" deb baholash; beta ni namuna "ishonchi" bo'yicha tanlash (collapse eng yuqori ishonch beradi); KL ≈ 0 ni muvaffaqiyat deb qabul qilish; shartli modelni faqat to'g'ri sinf ulushi bilan baholash.
3. Tez ma'lumotnoma
import torch
import torch.nn as nn
import torch.nn.functional as F
class VAE(nn.Module):
def __init__(self, d):
super().__init__()
self.enc = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, 2 * d))
self.dec = nn.Sequential(nn.Linear(d, 128), nn.ReLU(), nn.Linear(128, 64))
def forward(self, x, g=None):
mu, logvar = self.enc(x).chunk(2, dim=1)
z = mu + torch.exp(0.5 * logvar) * torch.randn(mu.shape, generator=g) # reparam
return self.dec(z), mu, logvar
logit, mu, logvar = model(x, g)
qayta = F.binary_cross_entropy_with_logits(logit, x, reduction="none").sum(1)
kl = 0.5 * (mu ** 2 + logvar.exp() - 1 - logvar).sum(1)
loss = (qayta + beta * kl).mean() # -ELBO (beta = 1)
# namuna olish
z = torch.randn(n, d, generator=torch.Generator().manual_seed(0))
x_new = torch.sigmoid(model.dec(z))
# diagnostika
faol = (mu_test.var(0) > 0.01).sum() # faol latent o'lchovlar
kl_olchov = kl_har_olchov.mean(0) # posterior collapse ni ko'rish
# shartli: decoder(cat([z, one_hot(y)]))Avtoenkoder va VAE xulosasi
AE: encoder -> tor latent -> decoder; nochiziqli PCA; namuna olishga yaroqsiz
VAE: q(z|x) = N(mu, sigma^2), p(z) = N(0, I); loss = qayta tiklash + KL
reparametrizatsiya: z = mu + sigma * eps
beta: qayta tiklash <-> prior; katta beta -> posterior collapse
CVAE: y - nima, z - qanday; xilma-xillikni alohida o'lchang4. Batafsil misollar
Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU).
Misol 1 — Avtoenkoder: siqish va latentdagi teshiklar
"""Avtoenkoder: siqish, qayta tiklash, PCA bilan taqqoslash va latent fazodagi "teshiklar"."""
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
BELGI = " .:-=+*#%@"
def ascii_qator(rasmlar, izohlar):
"""[0, 1] oralig'idagi 8x8 rasmlarni yonma-yon chizadi."""
satrlar = [" ".join(f"{s:<8}" for s in izohlar)]
for r in range(8):
satrlar.append(" ".join("".join(BELGI[min(9, int(v * 10))] for v in im.reshape(8, 8)[r])
for im in np.clip(rasmlar, 0, 1)))
return satrlar
def malumot():
d = load_digits()
x_o, x_t, y_o, y_t = train_test_split(d.data / 16, d.target, test_size=0.25,
stratify=d.target, random_state=0)
f = lambda a: torch.tensor(a, dtype=torch.float32)
return f(x_o), f(x_t), torch.tensor(y_o), torch.tensor(y_t)
class Klassifikator(nn.Module):
"""Hakam: [0, 1] oralig'idagi 64 piksel -> 10 sinf; h - xususiyatlar (128)."""
def __init__(self):
super().__init__()
self.h = nn.Linear(64, 128)
self.chiq = nn.Linear(128, 10)
def forward(self, x):
return self.chiq(F.relu(self.h(x)))
def hakam_orgat(x, y, seed=0):
torch.manual_seed(seed)
m = Klassifikator()
opt = torch.optim.Adam(m.parameters(), lr=1e-2, weight_decay=1e-4)
g = torch.Generator().manual_seed(seed)
for _ in range(60):
for idx in torch.randperm(len(x), generator=g).split(64):
loss = F.cross_entropy(m(x[idx]), y[idx])
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
@torch.no_grad()
def tanish(hakam, x):
"""Hakam ishonchi > 0.9 bo'lgan namunalar ulushi va sinflar soni."""
p = torch.softmax(hakam(x), -1)
return (p.max(1).values > 0.9).float().mean().item(), np.bincount(p.argmax(1).numpy(), minlength=10)
class AE(nn.Module):
def __init__(self, d):
super().__init__()
self.enc = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, d))
self.dec = nn.Sequential(nn.Linear(d, 128), nn.ReLU(), nn.Linear(128, 64))
def forward(self, x):
return torch.sigmoid(self.dec(self.enc(x)))
def ae_orgat(x, d, seed=0, davr=100):
torch.manual_seed(seed)
m = AE(d)
opt = torch.optim.Adam(m.parameters(), lr=3e-3)
g = torch.Generator().manual_seed(seed)
for _ in range(davr):
for idx in torch.randperm(len(x), generator=g).split(64):
loss = F.mse_loss(m(x[idx]), x[idx])
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
def main() -> None:
torch.set_num_threads(1)
x_o, x_t, y_o, y_t = malumot()
hakam = hakam_orgat(x_o, y_o)
print("=== 1. Siqish: 64 piksel -> d o'lchovli latent -> 64 piksel (test MSE) ===")
print(" d PCA (chiziqli) AE (nochiziqli) AE / PCA")
modellar = {}
for d in (2, 8, 16):
pca = PCA(d, random_state=0).fit(x_o.numpy())
mse_pca = np.mean((pca.inverse_transform(pca.transform(x_t.numpy())) - x_t.numpy()) ** 2)
ae = ae_orgat(x_o, d)
modellar[d] = ae
with torch.no_grad():
mse_ae = F.mse_loss(ae(x_t), x_t).item()
print(f" {d:<4} {mse_pca:>14.4f} {mse_ae:>17.4f} {mse_ae / mse_pca:>10.2f}")
print("\n=== 2. Qayta tiklash (d = 8): asl | tiklangan ===")
ae = modellar[8]
with torch.no_grad():
qayta = ae(x_t[:5])
juft = torch.stack([x_t[:5], qayta], 1).reshape(10, 64).numpy()
for s in ascii_qator(juft, ["asl", "AE"] * 5):
print(" " + s)
ish_q, _ = tanish(hakam, ae(x_t).detach())
ish_t, _ = tanish(hakam, x_t)
print(f" hakam: haqiqiy test ishonch > 0.9 ulushi {ish_t:.3f}, tiklanganlar {ish_q:.3f}")
print("\n=== 3. AE latentidan namuna olish (d = 8) ===")
with torch.no_grad():
z_o, z_t = ae.enc(x_o), ae.enc(x_t)
mu, cov = z_o.mean(0), torch.cov(z_o.T)
print(f" o'quv kodlari: o'rtacha norma {z_o.norm(dim=1).mean():.2f}, "
f"koordinata std {z_o.std(0).min():.2f} .. {z_o.std(0).max():.2f}")
g = torch.Generator().manual_seed(1)
L = torch.linalg.cholesky(cov)
usullar = {
"N(0, I)": torch.randn(1000, 8, generator=g),
"N(mu, Sigma)": mu + torch.randn(1000, 8, generator=g) @ L.T,
"test kodlari": z_t,
}
d_test = torch.cdist(z_t, z_o).min(1).values
chegara = torch.quantile(d_test, 0.95)
print(f" 'teshik' = eng yaqin o'quv kodigacha masofa > {chegara:.2f} (test kodlarining 95-foizili)")
print(" z manbasi ishonch>0.9 teshikda sinflar (0..9)")
for nom, z in usullar.items():
with torch.no_grad():
x = torch.sigmoid(ae.dec(z))
ish, soni = tanish(hakam, x)
teshik = (torch.cdist(z, z_o).min(1).values > chegara).float().mean().item()
print(f" {nom:<16} {ish:>10.3f} {teshik:>10.3f} {' '.join(map(str, soni))}")
if nom == "N(mu, Sigma)":
namuna = x[:6].numpy()
for s in ascii_qator(namuna, ["N(mu,S)"] * 6):
print(" " + s)
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Siqish: 64 piksel -> d o'lchovli latent -> 64 piksel (test MSE) ===
d PCA (chiziqli) AE (nochiziqli) AE / PCA
2 0.0530 0.0365 0.69
8 0.0246 0.0122 0.50
16 0.0115 0.0065 0.56
=== 2. Qayta tiklash (d = 8): asl | tiklangan ===
asl AE asl AE asl AE asl AE asl AE
=@%. :@#= .%%. .%*. *+ +% +@*. .%+ *@. +%:
+%*@ =##% %%+* *%** -@ +- :@: -: #%%* %@@+ =@=.- -@.#-
- @- @. @= # .%: #: %* =@: %= .%. *%+@. %%+@ .@=.@* .@: @*
@- :@: .@- *- :%. -- -@=-@- =@::@% :@@@+ -*@@: +% *%. +@.*@-
.@: +@ -@ +- -# :- *@@@% =@%@%. .+*% @= *@@@* -@%@+
#% =#. .@ *- .% +- .:*@+ --@: -@: .% .:+@. -#%
-#@@% :*%*+ @+-%. %*=@. =@. :@ ..=@- .:.:@ +% ##
+@%*%. -#*%#. :@@+ .%@= ## %% .%@@* .#@@% #+ #*
hakam: haqiqiy test ishonch > 0.9 ulushi 0.947, tiklanganlar 0.920
=== 3. AE latentidan namuna olish (d = 8) ===
o'quv kodlari: o'rtacha norma 7.07, koordinata std 1.64 .. 2.51
'teshik' = eng yaqin o'quv kodigacha masofa > 2.85 (test kodlarining 95-foizili)
z manbasi ishonch>0.9 teshikda sinflar (0..9)
N(0, I) 0.348 0.964 39 30 32 37 154 87 43 58 260 260
N(mu, Sigma) 0.594 0.502 63 112 116 102 102 64 74 86 194 87
test kodlari 0.920 0.051 43 51 46 44 42 46 44 47 42 45
N(mu,S) N(mu,S) N(mu,S) N(mu,S) N(mu,S) N(mu,S)
:== %* .#%%= #@@@# :*: .#=.
:###. %@+. *%-%#: -%@@- *%+ =%-+.
+- @- #% -- = #% .%@@ :#@= %-=#
+.:@: =@-.%. . @= .@@. :%%@- %=@-
*#*@. -@@@@. .=+=@. :@@+ .#%@= =%+#=.
..@ .*- .-:+% .#%: =@: +@+%+
.*% +#: .-# +%- :% :*-+
:+# %%: .#- @% :#: :#:Nima ko'rsatdi: 1-bo'limda avtoenkoder va PCA bir xil latent o'lchovda solishtirildi: hamma d da AE test MSE si PCA nikidan ancha kam — d = 8 da 0.0122 va 0.0246, ya'ni nochiziqlilik xatoni ikki barobar kamaytirdi. 2-bo'limdagi ASCII juftlar tiklanish sifatini ko'rsatadi, hakam esa tiklangan rasmlarning 0.920 qismini ishonch bilan taniydi (haqiqiy rasmlarda 0.947) — ya'ni kod raqam haqida deyarli hamma narsani saqlaydi. 3-bo'lim esa muammoni ochdi. O'quv kodlarining o'rtacha normasi 7.07, koordinatalar std si 1.64 .. 2.51 — N(0, I) bilan hech qanday aloqasi yo'q. Shuning uchun N(0, I) dan olingan kodlarning 0.964 qismi teshikda, namunalarning atigi 0.348 qismi taniladi, sinflar esa keskin nomutanosib (8 va 9 — 260 tadan, 1 — 30 ta). Kodlarga Gauss moslash (N(mu, Sigma)) yordam beradi (0.594), lekin baribir namunalarning 0.502 qismi teshikda — test kodlari uchun bu qiymat ta'rifga ko'ra 0.051. Xulosa: AE ning latent fazosi Gauss shaklida emas va bo'shliqlarga to'la. Bog'liq bo'limlar: 2.1, 2.2.
Misol 2 — VAE noldan: reparametrizatsiya va ELBO
"""VAE noldan: reparametrizatsiya, ELBO = qayta tiklash - KL va prior dan namuna olish."""
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
BELGI = " .:-=+*#%@"
def ascii_qator(rasmlar, izohlar):
"""[0, 1] oralig'idagi 8x8 rasmlarni yonma-yon chizadi."""
satrlar = [" ".join(f"{s:<8}" for s in izohlar)]
for r in range(8):
satrlar.append(" ".join("".join(BELGI[min(9, int(v * 10))] for v in im.reshape(8, 8)[r])
for im in np.clip(rasmlar, 0, 1)))
return satrlar
def malumot():
d = load_digits()
x_o, x_t, y_o, y_t = train_test_split(d.data / 16, d.target, test_size=0.25,
stratify=d.target, random_state=0)
f = lambda a: torch.tensor(a, dtype=torch.float32)
return f(x_o), f(x_t), torch.tensor(y_o), torch.tensor(y_t)
class Klassifikator(nn.Module):
"""Hakam: [0, 1] oralig'idagi 64 piksel -> 10 sinf; h - xususiyatlar (128)."""
def __init__(self):
super().__init__()
self.h = nn.Linear(64, 128)
self.chiq = nn.Linear(128, 10)
def forward(self, x):
return self.chiq(F.relu(self.h(x)))
def hakam_orgat(x, y, seed=0):
torch.manual_seed(seed)
m = Klassifikator()
opt = torch.optim.Adam(m.parameters(), lr=1e-2, weight_decay=1e-4)
g = torch.Generator().manual_seed(seed)
for _ in range(60):
for idx in torch.randperm(len(x), generator=g).split(64):
loss = F.cross_entropy(m(x[idx]), y[idx])
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
@torch.no_grad()
def tanish(hakam, x):
"""Hakam ishonchi > 0.9 bo'lgan namunalar ulushi va sinflar soni."""
p = torch.softmax(hakam(x), -1)
return (p.max(1).values > 0.9).float().mean().item(), np.bincount(p.argmax(1).numpy(), minlength=10)
class AE(nn.Module):
def __init__(self, d):
super().__init__()
self.enc = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, d))
self.dec = nn.Sequential(nn.Linear(d, 128), nn.ReLU(), nn.Linear(128, 64))
class VAE(nn.Module):
"""Encoder q(z|x) = N(mu, sigma^2), decoder p(x|z) - piksel bo'yicha Bernoulli (logit)."""
def __init__(self, d):
super().__init__()
self.enc = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, 2 * d))
self.dec = nn.Sequential(nn.Linear(d, 128), nn.ReLU(), nn.Linear(128, 64))
def kodla(self, x):
mu, logvar = self.enc(x).chunk(2, dim=1)
return mu, logvar
def forward(self, x, g=None):
mu, logvar = self.kodla(x)
eps = torch.randn(mu.shape, generator=g)
z = mu + torch.exp(0.5 * logvar) * eps # reparametrizatsiya
return self.dec(z), mu, logvar
def elbo_qismlari(model, x, g=None):
"""Bir rasm uchun o'rtacha: qayta tiklash (-log p(x|z), nat) va KL(q(z|x) || N(0, I))."""
logit, mu, logvar = model(x, g)
qayta = F.binary_cross_entropy_with_logits(logit, x, reduction="none").sum(1)
kl = 0.5 * (mu ** 2 + logvar.exp() - 1 - logvar).sum(1)
return qayta, kl
def orgat(tur, x, d=8, beta=1.0, seed=0, davr=100):
torch.manual_seed(seed)
m = AE(d) if tur == "AE" else VAE(d)
opt = torch.optim.Adam(m.parameters(), lr=3e-3)
g = torch.Generator().manual_seed(seed)
for _ in range(davr):
for idx in torch.randperm(len(x), generator=g).split(64):
if tur == "AE":
loss = F.binary_cross_entropy_with_logits(m.dec(m.enc(x[idx])), x[idx],
reduction="none").sum(1).mean()
else:
qayta, kl = elbo_qismlari(m, x[idx], g)
loss = (qayta + beta * kl).mean()
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
def main() -> None:
torch.set_num_threads(1)
x_o, x_t, y_o, y_t = malumot()
hakam = hakam_orgat(x_o, y_o)
print("=== 1. Reparametrizatsiya: gradient z orqali o'tadimi? ===")
mu = torch.tensor([1.0], requires_grad=True)
logvar = torch.tensor([0.0], requires_grad=True)
z_yomon = torch.normal(mu.detach().expand(10000), torch.exp(0.5 * logvar.detach()).expand(10000),
generator=torch.Generator().manual_seed(0))
print(f" z = torch.normal(mu, sigma): z.requires_grad = {z_yomon.requires_grad}"
f" -> mu va sigma gradient olmaydi")
eps = torch.randn(10000, generator=torch.Generator().manual_seed(0))
z = mu + torch.exp(0.5 * logvar) * eps
((z - 3) ** 2).mean().backward()
print(f" z = mu + sigma * eps: z.requires_grad = {z.requires_grad}")
print(f" maqsad E[(z - 3)^2] = (mu - 3)^2 + sigma^2; aniq gradient: d/dmu = -4.000, d/dlogvar = 1.000")
print(f" reparametrizatsiya bahosi (10000 eps): d/dmu = {mu.grad.item():.3f}, "
f"d/dlogvar = {logvar.grad.item():.3f}")
with torch.no_grad():
f = (z - 3) ** 2
rep = 2 * (z - 3) # har eps uchun d/dmu
skor = f * (z - mu) # REINFORCE: f(z) * d log q / d mu
print(f" d/dmu ning bitta-namunali bahosi: reparam std {rep.std():.2f}, "
f"REINFORCE std {skor.std():.2f} (o'rtacha {skor.mean():.3f})")
print("\n=== 2. VAE (d = 8) va AE: test ELBO qismlari (nat/rasm) ===")
vae = orgat("VAE", x_o)
ae = orgat("AE", x_o)
with torch.no_grad():
qayta, kl = elbo_qismlari(vae, x_t, torch.Generator().manual_seed(1))
mu_t, _ = vae.kodla(x_t)
qayta_mu = F.binary_cross_entropy_with_logits(vae.dec(mu_t), x_t, reduction="none").sum(1)
qayta_ae = F.binary_cross_entropy_with_logits(ae.dec(ae.enc(x_t)), x_t, reduction="none").sum(1)
print(f" VAE: qayta tiklash {qayta.mean():.2f}, KL {kl.mean():.2f}, "
f"-ELBO = {qayta.mean() + kl.mean():.2f}")
print(f" VAE qayta tiklash z = mu bilan (shovqinsiz): {qayta_mu.mean():.2f}")
print(f" AE qayta tiklash: {qayta_ae.mean():.2f} (KL jarimasi yo'q)")
print(f" bit ga: -ELBO = {(qayta.mean() + kl.mean()) / np.log(2):.1f} bit/rasm "
f"(uzluksiz piksellar - 26.1 dagi binar bitlar bilan solishtirib bo'lmaydi)")
print("\n=== 3. Prior dan namuna: z ~ N(0, I) -> decoder ===")
g = torch.Generator().manual_seed(2)
z0 = torch.randn(1000, 8, generator=g)
with torch.no_grad():
z_o_ae, z_t_ae = ae.enc(x_o), ae.enc(x_t)
mu_o, lv_o = vae.kodla(x_o)
_, lv_t = vae.kodla(x_t)
g2 = torch.Generator().manual_seed(3)
q_o = mu_o + torch.exp(0.5 * lv_o) * torch.randn(mu_o.shape, generator=g2) # z ~ q(z|x)
q_t = mu_t + torch.exp(0.5 * lv_t) * torch.randn(mu_t.shape, generator=g2)
L = torch.linalg.cholesky(torch.cov(z_o_ae.T))
manbalar = {
"AE, N(0, I)": (torch.sigmoid(ae.dec(z0)), z0, z_o_ae, z_t_ae),
"AE, N(mu, Sigma)": (torch.sigmoid(ae.dec(z_o_ae.mean(0) + z0 @ L.T)),
z_o_ae.mean(0) + z0 @ L.T, z_o_ae, z_t_ae),
"VAE, N(0, I)": (torch.sigmoid(vae.dec(z0)), z0, q_o, q_t),
}
print(" manba ishonch>0.9 teshikda sinflar (0..9)")
for nom, (x, z, baza, test) in manbalar.items():
ish, soni = tanish(hakam, x)
chegara = torch.quantile(torch.cdist(test, baza).min(1).values, 0.95)
teshik = (torch.cdist(z, baza).min(1).values > chegara).float().mean().item()
print(f" {nom:<18} {ish:>10.3f} {teshik:>10.3f} {' '.join(map(str, soni))}")
ish_t, _ = tanish(hakam, x_t)
print(f" {'haqiqiy test':<18} {ish_t:>10.3f}")
print(f" VAE o'quv kodlari z ~ q(z|x): o'rtacha {q_o.mean():+.2f}, "
f"koordinata std {q_o.std(0).min():.2f} .. {q_o.std(0).max():.2f} (prior: 0 va 1)")
for s in ascii_qator(manbalar["VAE, N(0, I)"][0][:6].numpy(), ["VAE"] * 6):
print(" " + s)
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Reparametrizatsiya: gradient z orqali o'tadimi? ===
z = torch.normal(mu, sigma): z.requires_grad = False -> mu va sigma gradient olmaydi
z = mu + sigma * eps: z.requires_grad = True
maqsad E[(z - 3)^2] = (mu - 3)^2 + sigma^2; aniq gradient: d/dmu = -4.000, d/dlogvar = 1.000
reparametrizatsiya bahosi (10000 eps): d/dmu = -4.021, d/dlogvar = 1.025
d/dmu ning bitta-namunali bahosi: reparam std 2.00, REINFORCE std 9.44 (o'rtacha -4.046)
=== 2. VAE (d = 8) va AE: test ELBO qismlari (nat/rasm) ===
VAE: qayta tiklash 21.07, KL 3.40, -ELBO = 24.47
VAE qayta tiklash z = mu bilan (shovqinsiz): 19.29
AE qayta tiklash: 16.54 (KL jarimasi yo'q)
bit ga: -ELBO = 35.3 bit/rasm (uzluksiz piksellar - 26.1 dagi binar bitlar bilan solishtirib bo'lmaydi)
=== 3. Prior dan namuna: z ~ N(0, I) -> decoder ===
manba ishonch>0.9 teshikda sinflar (0..9)
AE, N(0, I) 0.329 0.982 214 67 98 18 204 132 82 104 65 16
AE, N(mu, Sigma) 0.601 0.581 55 113 96 114 98 77 89 104 172 82
VAE, N(0, I) 0.661 0.094 88 82 76 119 113 85 112 108 129 88
haqiqiy test 0.947
VAE o'quv kodlari z ~ q(z|x): o'rtacha -0.03, koordinata std 0.96 .. 1.03 (prior: 0 va 1)
VAE VAE VAE VAE VAE VAE
-@%= .#*. +%#*. *@@* +%#- .**.
*##* *%+= :%+++ :%=*% :%##* :%%:
..#* .%:.+. :#::: :.%# .+-#+ -@%:
:+@%- -%..=. :#**: +@= -#%: -%%.
:%@@*: -%:-+: .+**= *%. +@*. -%%
=@+ .@:.*= :.-#. .%= *%= *%#-
:%. %*=#- +-+# ::+%- ##-. *@%+.
+* .#@+ +@#: #@%= *#=. .#%#-Nima ko'rsatdi: 1-bo'lim reparametrizatsiyani tekshirdi. torch.normal(mu, sigma) natijasi requires_grad = False — gradient encoderga yetib bormaydi. z = mu + sigma * eps esa differensiallanuvchi: E[(z - 3)^2] ning gradienti 10 000 ta eps bo'yicha -4.021 va 1.025 — aniq qiymatlar (-4 va 1) ga juda yaqin. Bitta namunali bahoda reparametrizatsiya std si 2.00, REINFORCE niki 9.44 — ikkalasi ham to'g'ri o'rtachaga intiladi, lekin REINFORCE ancha shovqinli. 2-bo'lim ELBO qismlari: VAE test da qayta tiklash 21.07 va KL 3.40 nat — jami -ELBO = 24.47; shovqinsiz (z = mu) qayta tiklash 19.29, AE niki 16.54 — AE yaxshiroq qayta tiklaydi, chunki unga KL jarimasi yo'q. Bu bitlarni 26.1 dagi binar raqamlar bilan solishtirib bo'lmaydi — piksellar bu yerda uzluksiz. 3-bo'lim asosiy natija: VAE da z ~ N(0, I) kodlarining atigi 0.094 qismi teshikda (AE da N(0, I) — 0.982, moslangan Gauss — 0.581). VAE o'quv kodlari z ~ q(z|x) haqiqatan ham priorga o'xshaydi: o'rtacha -0.03, koordinata std si 0.96 .. 1.03. Namunalar tanib olinishi 0.661 — moslangan Gaussli AE dan (0.601) biroz yuqori (bitta urug'da), sinflar esa tekis taqsimlangan (76 dan 129 gacha). Muhimi: VAE da prior qo'lda moslanmagan — u o'rgatishning o'zidan kelib chiqdi. Bog'liq bo'limlar: 2.3, 2.4.
Misol 3 — Latent xarita, beta-VAE va interpolatsiya
"""VAE latent fazosi: 2D xarita, beta-VAE murosasi va interpolatsiya."""
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
BELGI = " .:-=+*#%@"
def ascii_qator(rasmlar, izohlar):
"""[0, 1] oralig'idagi 8x8 rasmlarni yonma-yon chizadi."""
satrlar = [" ".join(f"{s:<8}" for s in izohlar)]
for r in range(8):
satrlar.append(" ".join("".join(BELGI[min(9, int(v * 10))] for v in im.reshape(8, 8)[r])
for im in np.clip(rasmlar, 0, 1)))
return satrlar
def malumot():
d = load_digits()
x_o, x_t, y_o, y_t = train_test_split(d.data / 16, d.target, test_size=0.25,
stratify=d.target, random_state=0)
f = lambda a: torch.tensor(a, dtype=torch.float32)
return f(x_o), f(x_t), torch.tensor(y_o), torch.tensor(y_t)
class Klassifikator(nn.Module):
"""Hakam: [0, 1] oralig'idagi 64 piksel -> 10 sinf; h - xususiyatlar (128)."""
def __init__(self):
super().__init__()
self.h = nn.Linear(64, 128)
self.chiq = nn.Linear(128, 10)
def forward(self, x):
return self.chiq(F.relu(self.h(x)))
def hakam_orgat(x, y, seed=0):
torch.manual_seed(seed)
m = Klassifikator()
opt = torch.optim.Adam(m.parameters(), lr=1e-2, weight_decay=1e-4)
g = torch.Generator().manual_seed(seed)
for _ in range(60):
for idx in torch.randperm(len(x), generator=g).split(64):
loss = F.cross_entropy(m(x[idx]), y[idx])
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
@torch.no_grad()
def tanish(hakam, x):
"""Hakam ishonchi > 0.9 bo'lgan namunalar ulushi va sinflar soni."""
p = torch.softmax(hakam(x), -1)
return (p.max(1).values > 0.9).float().mean().item(), np.bincount(p.argmax(1).numpy(), minlength=10)
class VAE(nn.Module):
def __init__(self, d):
super().__init__()
self.enc = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, 2 * d))
self.dec = nn.Sequential(nn.Linear(d, 128), nn.ReLU(), nn.Linear(128, 64))
def kodla(self, x):
return self.enc(x).chunk(2, dim=1)
def forward(self, x, g=None):
mu, logvar = self.kodla(x)
z = mu + torch.exp(0.5 * logvar) * torch.randn(mu.shape, generator=g)
return self.dec(z), mu, logvar
def elbo_qismlari(model, x, g=None):
logit, mu, logvar = model(x, g)
qayta = F.binary_cross_entropy_with_logits(logit, x, reduction="none").sum(1)
kl = 0.5 * (mu ** 2 + logvar.exp() - 1 - logvar).sum(1)
return qayta, kl
def orgat(x, d=8, beta=1.0, seed=0, davr=40, B=128):
torch.manual_seed(seed)
m = VAE(d)
opt = torch.optim.Adam(m.parameters(), lr=3e-3)
g = torch.Generator().manual_seed(seed)
for _ in range(davr):
for idx in torch.randperm(len(x), generator=g).split(B):
qayta, kl = elbo_qismlari(m, x[idx], g)
loss = (qayta + beta * kl).mean()
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
@torch.no_grad()
def olchovlar(m, hakam, x_t, d=8):
qayta, kl = elbo_qismlari(m, x_t, torch.Generator().manual_seed(1))
mu, _ = m.kodla(x_t)
faol = int((mu.var(0) > 0.01).sum()) # faol latent o'lchovlar
x = torch.sigmoid(m.dec(torch.randn(1000, d, generator=torch.Generator().manual_seed(2))))
ish, soni = tanish(hakam, x)
u = soni[soni > 0] / soni.sum()
entropiya = float(-(u * np.log(u)).sum() / np.log(10)) # 1 - hamma sinf teng, 0 - bitta sinf
return qayta.mean().item(), kl.mean().item(), ish, faol, entropiya, soni
def main() -> None:
torch.set_num_threads(1)
x_o, x_t, y_o, y_t = malumot()
hakam = hakam_orgat(x_o, y_o)
print("=== 1. 2D latent xaritasi: z to'rini decoder dan o'tkazib, hakam bilan o'qiymiz ===")
m2 = orgat(x_o, d=2)
to_r = torch.linspace(-2, 2, 11)
zz = torch.stack(torch.meshgrid(to_r, to_r.flip(0), indexing="xy"), -1).reshape(-1, 2)
with torch.no_grad():
p = torch.softmax(hakam(torch.sigmoid(m2.dec(zz))), -1)
belgi = [str(s) if q > 0.7 else "." for s, q in zip(p.argmax(1).tolist(), p.max(1).values.tolist())]
print(" z2 ^ (raqam - hakam sinfi, '.' - ishonch < 0.7)")
for r in range(11):
print(f" {to_r.flip(0)[r].item():+4.1f} " + " ".join(belgi[r * 11:(r + 1) * 11]))
print(" -2" + " " * 16 + "+2 -> z1")
with torch.no_grad():
mu2, _ = m2.kodla(x_t)
print(f" test kodlarining {((mu2.abs() < 2).all(1)).float().mean():.3f} qismi [-2, 2]^2 kvadrat ichida; "
f"xaritada '.' ulushi {belgi.count('.') / len(belgi):.3f}")
print("\n=== 2. beta-VAE (d = 8): 3 urug', test ustida (nat/rasm) ===")
betalar = (0.5, 1.0, 4.0)
nat = {b: [olchovlar(orgat(x_o, beta=b, seed=s), hakam, x_t) for s in range(3)] for b in betalar}
print(" beta qayta tiklash KL ishonch>0.9 sinf entropiyasi faol o'lchov")
for b in betalar:
v = np.array([r[:5] for r in nat[b]])
print(f" {b:<5} {v[:, 0].mean():>11.2f} {v[:, 1].mean():>9.2f} {v[:, 2].mean():>10.3f}"
f" {v[:, 4].mean():>15.3f} {v[:, 3].mean():>14.1f}")
for b in (0.5, 4.0):
for i, nom in ((0, "qayta tiklash"), (2, "ishonch>0.9")):
f = np.array([r[i] for r in nat[b]]) - np.array([r[i] for r in nat[1.0]])
se = f.std(ddof=1) / np.sqrt(3)
print(f" beta {b} - beta 1, {nom:<13}: {f.mean():+7.3f}, SE {se:.3f} -> "
f"{'sezilarli' if abs(f.mean()) > 2 * se else 'sezilarli emas'}")
soni = nat[4.0][0][5]
print(f" beta 4 (urug' 0) prior namunalari sinflari: {' '.join(map(str, soni))}")
print("\n=== 3. Interpolatsiya (beta = 1, d = 8): 0 -> 1 raqami, latent chiziq bo'yicha ===")
m = orgat(x_o, beta=1.0, seed=0)
i0, i1 = int((y_t == 0).nonzero()[0]), int((y_t == 1).nonzero()[0])
with torch.no_grad():
mu, _ = m.kodla(x_t[[i0, i1]])
t = torch.linspace(0, 1, 7)[:, None]
x = torch.sigmoid(m.dec((1 - t) * mu[0] + t * mu[1]))
p = torch.softmax(hakam(x), -1)
izoh = [f"{a}:{q:.2f}" for a, q in zip(p.argmax(1).tolist(), p.max(1).values.tolist())]
for s in ascii_qator(x.numpy(), izoh):
print(" " + s)
g = torch.Generator().manual_seed(4)
juft = torch.randint(0, len(x_t), (200, 2), generator=g)
with torch.no_grad():
mu, _ = m.kodla(x_t)
orta = torch.sigmoid(m.dec(0.5 * (mu[juft[:, 0]] + mu[juft[:, 1]])))
piksel = 0.5 * (x_t[juft[:, 0]] + x_t[juft[:, 1]])
print(f" 200 tasodifiy juftning o'rta nuqtasi, ishonch>0.9: latentda {tanish(hakam, orta)[0]:.3f}, "
f"pikselda (ikki rasm ustma-ust) {tanish(hakam, piksel)[0]:.3f}")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. 2D latent xaritasi: z to'rini decoder dan o'tkazib, hakam bilan o'qiymiz ===
z2 ^ (raqam - hakam sinfi, '.' - ishonch < 0.7)
+2.0 9 9 9 9 9 . 7 7 7 7 7
+1.6 9 9 9 9 9 . 7 7 7 7 7
+1.2 9 9 9 9 9 . 7 7 7 7 7
+0.8 9 9 9 3 . 8 . 7 7 7 7
+0.4 9 9 . 3 3 8 8 . . 4 4
+0.0 9 9 . 3 . . 8 1 . 4 4
-0.4 9 9 9 . 2 2 8 1 4 4 4
-0.8 0 0 0 0 . . 6 6 4 4 4
-1.2 0 0 0 0 6 6 6 6 . 4 4
-1.6 0 0 0 0 6 6 6 6 6 4 4
-2.0 0 0 0 0 6 6 6 6 6 . 4
-2 +2 -> z1
test kodlarining 0.940 qismi [-2, 2]^2 kvadrat ichida; xaritada '.' ulushi 0.140
=== 2. beta-VAE (d = 8): 3 urug', test ustida (nat/rasm) ===
beta qayta tiklash KL ishonch>0.9 sinf entropiyasi faol o'lchov
0.5 19.85 5.60 0.607 0.994 8.0
1.0 21.90 2.95 0.586 0.994 7.7
4.0 27.29 0.00 0.995 0.000 0.0
beta 0.5 - beta 1, qayta tiklash: -2.049, SE 0.115 -> sezilarli
beta 0.5 - beta 1, ishonch>0.9 : +0.021, SE 0.023 -> sezilarli emas
beta 4.0 - beta 1, qayta tiklash: +5.388, SE 0.137 -> sezilarli
beta 4.0 - beta 1, ishonch>0.9 : +0.409, SE 0.011 -> sezilarli
beta 4 (urug' 0) prior namunalari sinflari: 0 0 0 0 0 0 0 0 1000 0
=== 3. Interpolatsiya (beta = 1, d = 8): 0 -> 1 raqami, latent chiziq bo'yicha ===
0:1.00 0:1.00 0:0.99 0:0.60 4:0.93 1:0.65 1:0.98
:%*. .#*. .**: =#- -#= :#+ .#*.
%%*+ #%*+ +#*+ =##+ :*#+. .*%*. .+%*.
:@: *. :%-.*. .%+:*: .#*-*: +#=*: =%**: -%%#.
-%. += -%:.+= :%-.*- :%=-*- :#*+*: .####. .*%%#.
=%. *+ =%:.*= -#::*= -#--#- -#+*#: :**##. .*#%*.
:@. *+ :%. *= :%::#- :#--#: :*=*#. .++##. .=+%*
%*=%: #*+#: *++#: +=*#. --##. :-#* .-%*
:%%= :#%= .*%= =%+ -#+ :#+ .#+
200 tasodifiy juftning o'rta nuqtasi, ishonch>0.9: latentda 0.555, pikselda (ikki rasm ustma-ust) 0.515Nima ko'rsatdi: 1-bo'limda 2 o'lchovli latentli VAE ning [-2, 2]^2 to'ri decoder va hakam orqali "o'qildi". Xarita sinflarning yaxlit orollarini ko'rsatadi: chap pastda 0, o'ng pastda 6 va 4, yuqorida 9 va 7; orollar orasidagi chegaralarda noaniq rasmlar ('.' ulushi 0.140). Test kodlarining 0.940 qismi shu kvadrat ichida — prior sohasi to'la ishlatilgan. 2-bo'limda beta uch urug'da solishtirildi. beta = 0.5 qayta tiklashni sezilarli yaxshiladi (-2.049, SE 0.115), KL esa 5.60 ga o'sdi; namuna ishonchi farqi sezilarli emas (+0.021, SE 0.023). beta = 4 da kutilmagan, lekin juda ibratli natija: KL 0.00, faol o'lchovlar 0 — posterior collapse. Decoder z ni e'tiborsiz qoldirib, bitta "o'rtacha raqam" chizadi, 1000 namunaning hammasi hakamga 8 (sinf entropiyasi 0.000). Shu bilan birga "ishonch > 0.9" ko'rsatkichi 0.995 — jadvaldagi eng yuqori qiymat! Faqat bitta o'lchovga qaragan kishi eng yomon modelni tanlagan bo'lar edi. 3-bo'lim: 0 dan 1 ga latent interpolatsiya shaklni asta-sekin o'zgartiradi, oraliq kadrlar hakamga noaniq (0:0.60, 4:0.93, 1:0.65). 200 tasodifiy juftning o'rta nuqtasida latent bo'yicha 0.555, pikselda 0.515 — kichik farq; o'rta nuqta ko'pincha ikki raqam orasidagi noaniq shakl bo'ladi, bu esa kutilgan hol. Bog'liq bo'limlar: 2.5, 2.6, 2.8.
Misol 4 — Shartli VAE va posterior collapse
"""Shartli VAE va posterior collapse: sinf berib generatsiya, uslub va latent o'lchovlar KL i."""
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
BELGI = " .:-=+*#%@"
def ascii_qator(rasmlar, izohlar):
"""[0, 1] oralig'idagi 8x8 rasmlarni yonma-yon chizadi."""
satrlar = [" ".join(f"{s:<8}" for s in izohlar)]
for r in range(8):
satrlar.append(" ".join("".join(BELGI[min(9, int(v * 10))] for v in im.reshape(8, 8)[r])
for im in np.clip(rasmlar, 0, 1)))
return satrlar
def malumot():
d = load_digits()
x_o, x_t, y_o, y_t = train_test_split(d.data / 16, d.target, test_size=0.25,
stratify=d.target, random_state=0)
f = lambda a: torch.tensor(a, dtype=torch.float32)
return f(x_o), f(x_t), torch.tensor(y_o), torch.tensor(y_t)
class Klassifikator(nn.Module):
"""Hakam: [0, 1] oralig'idagi 64 piksel -> 10 sinf; h - xususiyatlar (128)."""
def __init__(self):
super().__init__()
self.h = nn.Linear(64, 128)
self.chiq = nn.Linear(128, 10)
def forward(self, x):
return self.chiq(F.relu(self.h(x)))
def hakam_orgat(x, y, seed=0):
torch.manual_seed(seed)
m = Klassifikator()
opt = torch.optim.Adam(m.parameters(), lr=1e-2, weight_decay=1e-4)
g = torch.Generator().manual_seed(seed)
for _ in range(60):
for idx in torch.randperm(len(x), generator=g).split(64):
loss = F.cross_entropy(m(x[idx]), y[idx])
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
@torch.no_grad()
def tanish(hakam, x):
"""Hakam ishonchi > 0.9 bo'lgan namunalar ulushi va sinflar soni."""
p = torch.softmax(hakam(x), -1)
return (p.max(1).values > 0.9).float().mean().item(), np.bincount(p.argmax(1).numpy(), minlength=10)
class CVAE(nn.Module):
"""Shartli VAE: encoder q(z|x, y), decoder p(x|z, y); y - raqam sinfi (one-hot)."""
def __init__(self, d, k=10):
super().__init__()
self.k = k
self.enc = nn.Sequential(nn.Linear(64 + k, 128), nn.ReLU(), nn.Linear(128, 2 * d))
self.dec = nn.Sequential(nn.Linear(d + k, 128), nn.ReLU(), nn.Linear(128, 64))
def kodla(self, x, y):
return self.enc(torch.cat([x, F.one_hot(y, self.k).float()], 1)).chunk(2, dim=1)
def dekodla(self, z, y):
return self.dec(torch.cat([z, F.one_hot(y, self.k).float()], 1))
def forward(self, x, y, g=None):
mu, logvar = self.kodla(x, y)
z = mu + torch.exp(0.5 * logvar) * torch.randn(mu.shape, generator=g)
return self.dekodla(z, y), mu, logvar
def qismlar(m, x, y, g=None):
logit, mu, logvar = m(x, y, g)
qayta = F.binary_cross_entropy_with_logits(logit, x, reduction="none").sum(1)
kl_olchov = 0.5 * (mu ** 2 + logvar.exp() - 1 - logvar) # har latent o'lchov uchun
return qayta, kl_olchov
def orgat(x, y, beta=1.0, seed=0, d=8, davr=40, B=128):
torch.manual_seed(seed)
m = CVAE(d)
opt = torch.optim.Adam(m.parameters(), lr=3e-3)
g = torch.Generator().manual_seed(seed)
for _ in range(davr):
for idx in torch.randperm(len(x), generator=g).split(B):
qayta, kl = qismlar(m, x[idx], y[idx], g)
loss = (qayta + beta * kl.sum(1)).mean()
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
class VAE(nn.Module):
def __init__(self, d=8):
super().__init__()
self.enc = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, 2 * d))
self.dec = nn.Sequential(nn.Linear(d, 128), nn.ReLU(), nn.Linear(128, 64))
def qismlar_vae(m, x, g=None):
mu, logvar = m.enc(x).chunk(2, dim=1)
z = mu + torch.exp(0.5 * logvar) * torch.randn(mu.shape, generator=g)
qayta = F.binary_cross_entropy_with_logits(m.dec(z), x, reduction="none").sum(1)
return qayta, 0.5 * (mu ** 2 + logvar.exp() - 1 - logvar)
def orgat_vae(x, beta, seed=0, davr=40, B=128):
torch.manual_seed(seed)
m = VAE()
opt = torch.optim.Adam(m.parameters(), lr=3e-3)
g = torch.Generator().manual_seed(seed)
for _ in range(davr):
for idx in torch.randperm(len(x), generator=g).split(B):
qayta, kl = qismlar_vae(m, x[idx], g)
loss = (qayta + beta * kl.sum(1)).mean()
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
def sinf_ichidagi_xilma(x, y):
"""Har sinf ichida rasmlar orasidagi o'rtacha Evklid masofa (sinflar bo'yicha o'rtacha)."""
return float(np.mean([torch.pdist(x[y == k]).mean().item() for k in range(10)]))
def main() -> None:
torch.set_num_threads(1)
x_o, x_t, y_o, y_t = malumot()
hakam = hakam_orgat(x_o, y_o)
y_kerak = torch.arange(10).repeat_interleave(100) # har sinfdan 100 ta
print("=== 1. Shartli generatsiya: 'menga 7 chiz' (har sinfdan 100 namuna) ===")
cvae = orgat(x_o, y_o)
with torch.no_grad():
z = torch.randn(1000, 8, generator=torch.Generator().manual_seed(2))
x = torch.sigmoid(cvae.dekodla(z, y_kerak))
p = torch.softmax(hakam(x), -1)
togri = (p.argmax(1) == y_kerak).float()
print(f" hakam so'ralgan sinfni tanidi: {togri.mean():.3f} (tasodifiy taxmin 0.100)")
print(" sinf bo'yicha: " + " ".join(f"{k}:{togri[y_kerak == k].mean():.2f}" for k in range(10)))
print(f" ishonch > 0.9 ulushi {(p.max(1).values > 0.9).float().mean():.3f}; "
f"haqiqiy test {tanish(hakam, x_t)[0]:.3f}")
print("\n=== 2. Uslubni saqlab sinfni almashtirish: bitta z, o'nta y ===")
for i in (int((y_t == 3).nonzero()[0]), int((y_t == 7).nonzero()[1])):
with torch.no_grad():
mu, _ = cvae.kodla(x_t[i:i + 1], y_t[i:i + 1])
x10 = torch.sigmoid(cvae.dekodla(mu.repeat(10, 1), torch.arange(10)))
p10 = hakam(x10).argmax(1)
izoh = [f"asl {int(y_t[i])}"] + [f"y={k}->{int(a)}" for k, a in enumerate(p10)]
for s in ascii_qator(torch.cat([x_t[i:i + 1], x10]).numpy(), izoh):
print(" " + s)
print("\n=== 3. Posterior collapse: latent o'lchovlar bo'yicha KL (test, nat) ===")
modellar = {"VAE beta=1": orgat_vae(x_o, 1.0), "CVAE beta=1": cvae,
"VAE beta=4": orgat_vae(x_o, 4.0), "CVAE beta=4": orgat(x_o, y_o, beta=4.0)}
print(" model KL (8 o'lchov, kamayish tartibida) jami faol")
xilma = {}
for nom, m in modellar.items():
with torch.no_grad():
if nom.startswith("CVAE"):
_, kl = qismlar(m, x_t, y_t, torch.Generator().manual_seed(1))
xs = torch.sigmoid(m.dekodla(z, y_kerak))
else:
_, kl = qismlar_vae(m, x_t, torch.Generator().manual_seed(1))
xs = torch.sigmoid(m.dec(z))
k = kl.mean(0).sort(descending=True).values
print(f" {nom:<14} {' '.join(f'{v:5.2f}' for v in k.tolist())} {k.sum():5.2f} {int((k > 0.05).sum())}")
xilma[nom] = xs
print("\n sinf ichidagi xilma-xillik (hakam sinfi bo'yicha guruhlab, o'rtacha juft masofa):")
print(f" haqiqiy test: {sinf_ichidagi_xilma(x_t, y_t):.3f}")
for nom, xs in xilma.items():
with torch.no_grad():
ys = hakam(xs).argmax(1)
bor = [k for k in range(10) if (ys == k).sum() >= 2]
xm = float(np.mean([torch.pdist(xs[ys == k]).mean().item() for k in bor]))
print(f" {nom:<14} {xm:.3f} (sinflar soni: {len(bor)})")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Shartli generatsiya: 'menga 7 chiz' (har sinfdan 100 namuna) ===
hakam so'ralgan sinfni tanidi: 1.000 (tasodifiy taxmin 0.100)
sinf bo'yicha: 0:1.00 1:1.00 2:1.00 3:1.00 4:1.00 5:1.00 6:1.00 7:1.00 8:1.00 9:1.00
ishonch > 0.9 ulushi 0.998; haqiqiy test 0.947
=== 2. Uslubni saqlab sinfni almashtirish: bitta z, o'nta y ===
asl 3 y=0->0 y=1->1 y=2->2 y=3->3 y=4->4 y=5->5 y=6->6 y=7->7 y=8->8 y=9->9
+@* :%*. .*+. #@= *@%- =* *%%#. #+ =%%*. -##: =%*:
+.@: #### .%%- =@##. -%+#* .%+ -@#+: -@= .#*##. .#*** :%+*#
-%. :%-.%: :@@: -=-%: .::%= +%-:. -%-. ## ..** .*+*# :#-*%.
.@@= -#. *= =@%: -%. *@- :@==+- -%%*: .%+:. :+%#- =%%- .+%%@:
.@. =# ++ -%%: ** :*#. *@+%%= .===+. :@%##: .*@@*- -@#: ::#=
:- %= :%. *= -*#- -%- .%+ +%%@*. .-+: .@*:** =%+. #+=+. *+
-% -@. %**%. =#%+. .%@##+ +-=%= :+%: ==*+ *%-## -%: .%==#. +::#=
*@@- :%%- .*%#-. #@%#*. *@@*. -#. #@*. *@%- +* -#%+ =%%#.
asl 7 y=0->0 y=1->1 y=2->2 y=3->3 y=4->4 y=5->5 y=6->6 y=7->7 y=8->8 y=9->9
.%@+ :%*. .+*: #@+ *%%- -# *%%#: ** -%@#- -##- =%#-
:#@* #%## .%@+ =@#%: -#+## .%+ -@#+- -@= .*##%: .#**#. :%+*#.
@# :%-.%- :@@= -=:%- ..:%+ +#--: -%-. #* ..+#. .*+*%. :#-*@:
.@+ -#. *= =@@- :%. +@- :@-=*= -%#*: .%+: :=%%- =%%= .+#%@:
.-*@#. =# ++ =%%: ** :##. *@+%%= .=++=. :@%#*: .*@@*- -@%: .::#-
@@@@%. :%. #- -#%- -%= .%= +%%@*. .=+. .@#-** -%*. .#+++ *=
::%# %**%. -#%= .%@#*= .+-+%= .+%: =+*= #%-## :%: .%==*. =:-#-
.@= :%%- .+%*. #%##+. *@@* =# #@+ *@%- +* -#%= =%%*.
=== 3. Posterior collapse: latent o'lchovlar bo'yicha KL (test, nat) ===
model KL (8 o'lchov, kamayish tartibida) jami faol
VAE beta=1 0.88 0.81 0.74 0.43 0.15 0.07 0.06 0.02 3.17 7
CVAE beta=1 0.40 0.40 0.08 0.01 0.01 0.01 0.01 0.00 0.91 3
VAE beta=4 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0
CVAE beta=4 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0
sinf ichidagi xilma-xillik (hakam sinfi bo'yicha guruhlab, o'rtacha juft masofa):
haqiqiy test: 2.284
VAE beta=1 1.232 (sinflar soni: 10)
CVAE beta=1 0.803 (sinflar soni: 10)
VAE beta=4 0.220 (sinflar soni: 1)
CVAE beta=4 0.205 (sinflar soni: 10)Nima ko'rsatdi: 1-bo'lim: shartli VAE ga har sinfdan 100 ta so'rov berildi va hakam hammasida so'ralgan sinfni tanidi (1.000, hamma 10 sinfda 1.00), ishonch > 0.9 ulushi 0.998. Bu ajoyib ko'rinadi — lekin 2-bo'lim boshqa narsani ko'rsatadi. Qalin 3 va 7 rasmlarining kodlari bilan o'nta raqam chizilganda, ikki qator deyarli bir xil chiqdi: uslub saqlanmadi. 3-bo'lim sababini o'lchadi: CVAE da latentning jami KL i atigi 0.91 nat, faol o'lchovlar 3 ta (oddiy VAE da 3.17 va 7). Sinf y orqali berilgani uchun decoderga z dan kam narsa kerak — latent qisman "o'lgan". Sinf ichidagi xilma-xillik buni tasdiqlaydi: haqiqiy test 2.284, VAE 1.232, CVAE 0.803. beta = 4 da ikkala model ham to'liq collapse ga uchradi (KL 0.00, faol 0): VAE hamma namunani bitta sinfga chizdi, CVAE esa 10 sinfni to'g'ri chizdi, lekin har sinfda deyarli bitta rasm (xilma-xillik 0.205). Xulosa: to'g'ri sinf ulushi shartli modelning faqat yarmi; ikkinchi yarmi — xilma-xillik va faol latent. Bog'liq bo'limlar: 2.7, 2.8.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Avtoenkoder — generativ model" | Qayta tiklaydi, lekin latentidan namuna olish yomon: N(0, I) da 0.964 teshikda |
| "Kodlarga Gauss moslasam, AE ham VAE bo'ladi" | Moslangan Gaussda ham 0.502 teshikda; VAE da 0.094 |
| "VAE AE dan yaxshi qayta tiklaydi" | Yo'q: AE 16.54, VAE 21.07 nat — KL jarimasi narxi |
"torch.normal bilan namuna — reparametrizatsiya" |
requires_grad = False; kerakli shakl mu + sigma * eps |
| "REINFORCE va reparametrizatsiya bir xil" | Ikkalasi to'g'ri o'rtacha beradi, lekin std 9.44 va 2.00 |
| "KL = 0 — encoder priorga ideal mos" | Bu posterior collapse: beta = 4 da 1000 namuna bir xil |
| "Katta beta — yaxshiroq namunalar" | Ishonch 0.995, lekin sinf entropiyasi 0.000 |
| "CVAE sinfni to'g'ri chizsa — ish bitdi" | To'g'ri sinf 1.000, lekin xilma-xillik 0.803 (haqiqiy 2.284) |
| "Latent interpolatsiya har doim aniq raqamlar beradi" | O'rta nuqtada ishonch > 0.9 atigi 0.555 |
6. Keng tarqalgan xatolar va yechimlari
1. Gradient o'tmaydigan namuna
z = torch.normal(mu, torch.exp(0.5 * logvar)) # ⚠️
z = mu + torch.exp(0.5 * logvar) * torch.randn(mu.shape, generator=g) # ✅2. logvar ni sigma deb ishlatish
z = mu + logvar * eps # ⚠️
z = mu + torch.exp(0.5 * logvar) * eps # ✅3. Qayta tiklash va KL masshtabi mos emas
loss = F.binary_cross_entropy_with_logits(logit, x) + kl.sum(1).mean() # o'rtacha vs yig'indi # ⚠️
qayta = F.binary_cross_entropy_with_logits(logit, x, reduction="none").sum(1)
loss = (qayta + beta * kl.sum(1)).mean() # ✅4. AE latentidan standart normal bilan namuna
x_new = ae.dec(torch.randn(n, d)) # ⚠️
# VAE o'rgating yoki kamida kodlar taqsimotiga mos model (GMM) qo'ying # ✅5. Collapse ni sezmaslik
print("KL:", kl.mean()) # 0.00 - "zo'r!" # ⚠️
print("faol:", (mu.var(0) > 0.01).sum(), "KL o'lchov:", kl.mean(0)) # ✅6. beta ni bitta o'lchov bilan tanlash
eng_beta = max(betalar, key=lambda b: ishonch[b]) # ⚠️
# qayta tiklash, KL, ishonch, sinf entropiyasi, faol o'lchov - birga # ✅7. Shartli modelni faqat sinf bo'yicha baholash
print((hakam(x).argmax(1) == y_kerak).float().mean()) # ⚠️
print(togri_sinf, sinf_ichidagi_xilma(x, y_kerak), faol_olchov) # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 16-qism (o'tilgan): PCA — chiziqli avtoenkoder; GMM — latent o'zgaruvchili model (diskret latent)
- 20-21-qismlar (o'tilgan): MLP, backprop,
torch.autograd— reparametrizatsiya aynan autograd uchun - 26.1-dars (o'tilgan):
p(x), held-out LL, hakam-klassifikator, yodlash tekshiruvi - Keyingi darslar: 26.3 — GAN: namunalar VAE nikidan o'tkirroq, lekin likelihood yo'q; 26.5-26.6 — diffusion ham ELBO dan kelib chiqadi; 26.7 — Frechet masofa bilan VAE va GAN ni solishtirish; Matn-rasm modellari darsida — rasmni siqadigan avtoenkoder latentida ishlaydigan diffusion
8. Eng yaxshi amaliyotlar
Avtoenkoderni doim bir xil
ddagi PCA bilan solishtiring.Namuna olish sifatini qayta tiklash sifatidan alohida o'lchang.
Reparametrizatsiyani
mu + exp(0.5 * logvar) * epsshaklida yozing vaz.requires_gradni tekshiring.ELBO ni qismlarga ajratib chop eting: qayta tiklash, KL, jami.
KL ni latent o'lchovlar bo'yicha va faol o'lchovlar sonini kuzating — collapse ni erta ushlang.
beta ni bir necha urug'da, bir nechta o'lchov bilan tanlang; juftlashgan farq va SE bilan.
Shartli modelda to'g'ri sinf ulushi bilan birga sinf ichidagi xilma-xillikni o'lchang.
Sampling va test ELBO uchun
torch.Generatorbering — natija takrorlansin.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # chiziqli AE + MSE qaysi klassik usulga teng?
2. # nega AE latentidan N(0, I) bilan namuna olish yomon?
3. # ELBO ning ikki qismi?
4. # mu = 0, sigma = 1 da KL(q || N(0, 1)) = ?
5. # z = torch.normal(mu, sigma) dan keyin z.requires_grad?
6. # E[(z - 3)^2] ning mu bo'yicha gradienti (mu = 1)?
7. # beta oshsa qayta tiklash va KL qanday o'zgaradi?
8. # "faol o'lchov" qanday aniqlanadi?
9. # KL = 0 va hamma namuna bir xil - bu nima?
10. # CVAE da y va z nimani kodlaydi?
11. # posterior collapse ga qarshi ikki usul?
12. # nega beta ni faqat "ishonch > 0.9" bo'yicha tanlab bo'lmaydi?Javoblar
- PCA (bir xil qism-fazo)
- Kodlar
N(0, I)atrofida emas va orasida teshiklar bor (1-misol:0.964teshikda) - Qayta tiklash
E_q[log p(x|z)]va-KL(q(z|x) || p(z)) - 0
False2 * (mu - 3) = -4- Qayta tiklash yomonlashadi, KL kamayadi
- Test ustida
Var(mu_j(x)) > 0.01 - Posterior collapse — latent ishlatilmayapti
y— qaysi raqam,z— uslub (qalinlik, qiyalik)- KL annealing (beta ni 0 dan oshirish), free bits (yoki kuchsizroq decoder, kichik beta)
- Collapse bo'lgan model bitta aniq raqamni chizadi va eng yuqori ishonch oladi (
0.995) — sinf entropiyasi0.000
Vazifa 2: Xatolarni tuzating
1. mu, logvar = model.enc(x).chunk(2, dim=1)
z = torch.normal(mu, logvar)
2. qayta = F.mse_loss(torch.sigmoid(logit), x)
kl = 0.5 * (mu ** 2 + logvar.exp() - 1 - logvar).sum()
loss = qayta + kl
3. x_new = torch.sigmoid(ae.dec(torch.randn(100, 8)))
4. kl = 0.5 * (mu ** 2 + logvar.exp() - 1 - logvar).sum(1).mean()
print("KL juda kichik - model zo'r!" if kl < 0.01 else "")
5. togri = (hakam(cvae_namuna).argmax(1) == y_kerak).float().mean()
print("CVAE tayyor" if togri > 0.99 else "yana o'rgat")Javoblar
1. mu, logvar = model.enc(x).chunk(2, dim=1)
z = mu + torch.exp(0.5 * logvar) * torch.randn(mu.shape, generator=g) # reparam, sigma
2. qayta = F.binary_cross_entropy_with_logits(logit, x, reduction="none").sum(1)
kl = 0.5 * (mu ** 2 + logvar.exp() - 1 - logvar).sum(1)
loss = (qayta + kl).mean() # ikkalasi ham rasm bo'yicha yig'indi
3. # AE latenti N(0, I) emas: VAE o'rgating yoki kodlarga GMM qo'ying
x_new = torch.sigmoid(vae.dec(torch.randn(100, 8, generator=g)))
4. kl_olchov = 0.5 * (mu ** 2 + logvar.exp() - 1 - logvar).mean(0)
faol = (mu.var(0) > 0.01).sum()
if faol == 0:
print("posterior collapse: latent ishlatilmayapti")
5. togri = (hakam(cvae_namuna).argmax(1) == y_kerak).float().mean()
xilma = sinf_ichidagi_xilma(cvae_namuna, y_kerak)
print(togri, xilma, sinf_ichidagi_xilma(x_test, y_test), faol) # xilma-xillik hamVazifa 3: AE va PCA
Modellang:
d = 2, 4, 8, 16, 32da AE va PCA test MSE- Qaysi
dda farq eng katta? - Denoising AE: kirishga shovqin qo'shib, toza rasmni tiklash
Vazifa 4: Teshiklar
Modellang:
- AE kodlariga GMM (
K = 10) moslab namuna oling - Teshik ulushi va tanib olinishni
N(mu, Sigma)va VAE bilan solishtiring
Vazifa 5: beta va collapse
Modellang:
beta = 0.25, 0.5, 1, 2, 3, 4— qayta tiklash, KL, faol o'lchov, sinf entropiyasi- Qaysi beta da collapse boshlanadi?
- KL annealing: beta ni birinchi 20 davrda 0 dan 4 gacha oshiring — collapse saqlanib qoladimi?
Vazifa 6: Shartli VAE
Modellang:
- CVAE uchun
beta = 0.25va0.5— faol o'lchov va xilma-xillik - Bitta
z+ o'ntayqatori uslubni saqlay boshladimi? - To'g'ri sinf ulushi o'zgardimi?
Vazifa 7: O'ylash
Hamkasbingiz yozdi: "Men VAE ni sozladim: beta ni 4 ga ko'targanimda generatsiya qilingan raqamlarni klassifikator 99.5% ishonch bilan taniydi, beta = 1 da esa atigi 59%. KL ham nolga tushdi — ya'ni latent priorga ideal mos. beta = 4 ni ishlab chiqarishga qo'yamiz." Siz nima deysiz?
Javob
Qisqa javob: bu model ishlamayapti — u posterior collapse ga uchragan. Yuqori ishonch va nol KL — muvaffaqiyat emas, balki latentning o'limi belgisi.
1. Nima bo'lgan. 3-misolda xuddi shu holat: beta = 4 da KL 0.00, faol o'lchovlar 0, 1000 namunaning hammasi hakamga 8 (sinf entropiyasi 0.000). Decoder z ga qaramaydi va bitta "o'rtacha" rasm chizadi. Hakam uni ishonch bilan taniydi — chunki bu bitta aniq rasm, ming marta takrorlangan.
2. Nega ko'rsatkich aldadi. "Ishonch > 0.9" faqat har namunaning o'zini baholaydi; xilma-xillik va sinf qamrovini umuman ko'rmaydi. KL = 0 esa "q(z|x) = p(z) har bir x uchun" degani, ya'ni kod x haqida hech narsa bilmaydi.
3. Nima o'lchash kerak. Sinf taqsimoti yoki entropiyasi (collapse da 0), faol o'lchovlar soni, sinf ichidagi xilma-xillik, qayta tiklash (beta = 4 da 27.29, beta = 1 da 21.90 nat — sezilarli yomon).
4. Nima qilish kerak. beta = 1 atrofida qolish (yoki 0.5 — qayta tiklash sezilarli yaxshi, namuna ishonchi farqi sezilarli emas); namuna sifatini oshirish uchun kattaroq decoder, ko'proq ma'lumot yoki boshqa model oilasi (GAN, diffusion).
Tavsiya:
# 1. har beta uchun: qayta tiklash, KL, faol o'lchov, sinf entropiyasi, ishonch
# 2. bir necha urug' va juftlashgan farq + SE
# 3. collapse sharti: faol == 0 yoki entropiya < 0.5 -> nomzoddan chiqarish
# 4. qolganlar ichida - eng yaxshisidan sezilarli yomon bo'lmagan eng soddaHamkasbga javob: "99.5% ishonch — ogohlantirish belgisi: beta = 4 da model hamma namunaga bir xil raqamni chizyapti, KL nol esa latent o'lganini bildiradi. Sinf entropiyasini qarang — u nol. beta = 1 (yoki 0.5) da qolamiz va sifatni boshqa yo'l bilan oshiramiz."
Nimani mustahkamlaydi: 2.3, 2.6, 2.8-bo'limlar.
Xulosa
Bu darsda avtoenkoderdan VAE gacha yurdik: siqish va qayta tiklash, latentdagi teshiklar, ELBO va reparametrizatsiya, latent fazo tuzilishi, beta murosasi, shartli generatsiya va posterior collapse.
Eng muhim uch fikr:
Yaxshi qayta tiklash — yaxshi generatsiya emas. 1-misolda AE test MSE si PCA nikidan ikki barobar kam (
d = 8:0.0122va0.0246), tiklangan rasmlarning0.920qismi taniladi. Lekin uning latentidanN(0, I)bilan olingan kodlarning0.964qismi teshikda, kodlarga moslangan Gaussda ham0.502— test kodlarida esa0.051.VAE latentni priorga bog'laydi — reparametrizatsiya orqali o'rgatiladi. 2-misolda
z = mu + sigma * epsgradienti aniq qiymatlarga mos keldi (-4.021va-4),torch.normalesa gradient bermadi; REINFORCE bahosi 4.7 barobar shovqinliroq. VAE qayta tiklashda AE dan yomonroq (21.07va16.54nat — KL narxi), lekin priordan olingan kodlarning atigi0.094qismi teshikda va o'quv kodlari haqiqatanN(0, I)ga o'xshaydi (std0.96 .. 1.03).Posterior collapse — ko'rsatkichlarni aldaydigan tuzoq. 3-misolda
beta = 4da KL0.00, faol o'lchov0va 1000 namuna bitta raqam — "ishonch" esa eng yuqori (0.995). 4-misolda shartli VAE so'ralgan sinfni1.000to'g'ri chizdi, lekin latentning KL i0.91nat, faol o'lchov 3 ta va xilma-xillik0.803(haqiqiy2.284) — uslub deyarli yo'qolgan.
Keyingi darsda GAN: likelihood ni umuman tashlab, generator va diskriminator o'yini orqali o'rganadigan modelni noldan quramiz — avval 2D da 8 ta Gauss aralashmasida, keyin 8x8 raqamlarda — va namunalarini VAE bilan bir xil o'lchovlarda solishtiramiz.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!