Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Loyiha xaritasi
- 2.2. Baholash asbobi va uni kalibrlash
- 2.3. Nomzodlar va o'rgatish
- 2.4. Taqqoslash va qaror
- 2.5. Test, paket va deterministik nazorat
- 2.6. Watermark va hisobot
- 2.7. Tuzoqlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Konfig, bo'lish, baholash asbobi va uni kalibrlash
- Misol 2 — Uch nomzod validatsiyada: guidance, metrikalar, narx va namunalar
- Misol 3 — Uch urug'da juftlashgan taqqoslash va qaror
- Misol 4 — Test, paket, deterministik nazorat, watermark va hisobot
- 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.10-dars: Amaliyot — shartli raqam generatori loyihasi
26-QISM — GENERATIV AI · 10-dars
1. Kirish va motivatsiya
26-qismda generativ modellarning butun oilasini ko'rib chiqdik: generativ model nima va u nimani o'rganadi, avtoenkoder va VAE, GAN va uning muammolari, diffusion asoslari, sampling va classifier-free guidance, generativ modellarni baholash, matn-rasm va multimodal modellar va nihoyat — etika va xavfsizlik. Endi ularni bitta tekshiriladigan loyihaga yig'amiz va loyihaning eng muhim savoliga halol javob beramiz: bizning vazifamiz uchun qaysi generativ model kerak — va "eng zamonaviy" model haqiqatan ham eng yaxshisimi?
Vazifa — shartli raqam generatori: foydalanuvchi sinfni (0-9) beradi, tizim shu raqamning yangi 8x8 rasmini qaytaradi. Uch nomzod soddalik tartibida: shartli GMM (PCA fazosida har sinfga Gauss aralashmasi — 16-qismdagi usul), shartli VAE 26.2-bob va shartli diffusion classifier-free guidance bilan (26.5-26.6). Hammasi bir xil ma'lumot, bir xil baholash to'plami va bir xil qaror qoidasi bilan solishtiriladi.
Loyiha 22.14 va 24.12-darslardagi skeletni saqlaydi: konfig, testni qulflash, tez tekshiruvlar, bir necha urug'da juftlashgan taqqoslash, "eng sodda munosib model" qoidasi, testni bir marta ochish va weights_only=True bilan yuklanadigan paket. Generativ modelga xos qo'shimchalar: baholash klassifikatori (u ham faqat o'quv qismida), yodlash darvozasi 26.9-bob, deterministik namuna nazorati va chiqishga watermark.
Real vaziyat. Ta'lim platformasi bolalar uchun "raqam yozishni o'rgan" mashqlariga har safar yangi raqam rasmlari kerak edi. Jamoa darhol "hozir hamma diffusion ishlatadi" deb diffusion modelni tanladi, GPU ijaraga oldi va bir necha hafta sozladi. Keyin kimdir oddiy bazaviyni sinab ko'rdi — PCA va Gauss aralashmasi, bir necha soniyada o'rgatiladi, bitta matritsa ko'paytmasi bilan namuna beradi. Bir xil metrikada bazaviy yaxshiroq chiqdi. Bu darsning 3-misoli aynan shu holatni raqam bilan ko'rsatadi: kichik 8x8 ma'lumotda va kichik CPU byudjetida GMM ning FD si 2.151, diffusion niki 4.584, farq sezilarli — va GMM bitta namuna uchun taxminan 4400 marta kam FLOP sarflaydi.
Bu darsda to'liq generativ loyiha quramiz: ma'lumotdan watermark qo'shilgan, tekshirilgan paketgacha.
Bu darsda:
- Baholash asbobi: o'z klassifikatorimiz, FD, k-NN precision/recall, yodlash — va ularni kalibrlash
- Asosiy metrikani OLDINDAN belgilash
- Uch nomzod: shartli GMM, shartli VAE, shartli diffusion (CFG)
- Guidance kuchini validatsiyada tanlash
- Uch urug'da juftlashgan taqqoslash, yodlash darvozasi va qaror
- Hisob narxi: parametrlar, tarmoq chaqiruvlari, FLOP
- Test bir marta;
weights_only=Truepaket va deterministik nazorat - Chiqishga watermark va uni aniqlash
- Tuzoqlar
ℹ Misollar real numpy/sklearn/torch bilan (Python 3.14, torch 2.14 CPU).
2. Nazariya — chuqur tushuntirish
2.1. Loyiha xaritasi
Konfig (frozen dataclass): pca, gmm_k, vae_*, dif_*, cfg_w, lr, bs, urug_soni, nusxa_max
|
v
Ma'lumot: digits 8x8, [0, 1]; stratifikatsiyalangan bo'lish
o'quv 1077 / val 360 / test 360 -> TEST QULFLANADI
|
v
Baholash asbobi (FAQAT o'quvda): klassifikator -> xususiyatlar
metrikalar: to'g'ri sinf, FD, precision/recall (k-NN), yodlash, nusxa
kalibrlash: nusxachi, shovqinli nusxa, sinf o'rtachasi, shovqin (1-misol)
|
v
Nomzodlar: GMM < cVAE < diffusion (soddalik tartibida)
diffusion uchun w validatsiyada tanlanadi (2-misol)
|
v
3 urug' juftlashgan FD + yodlash darvozasi -> eng sodda munosib model (3-misol)
|
v
Test BIR MARTA -> paket (weights_only) -> deterministik nazorat
-> watermark -> hisobot / model kartasi (4-misol)22.14 va 24.12-darslardagi xarita bilan solishtirsak, skelet o'sha. Farq baholashda: klassifikatsiyada "to'g'ri javob" bor edi — generatsiyada yo'q. Shuning uchun biz o'lchov asbobini o'zimiz quramiz — klassifikator va uning xususiyatlari — va bu asbob ham modelning bir qismi kabi qat'iy qoidaga bo'ysunadi: u faqat o'quv qismida o'rgatiladi, val va test uning uchun ham yopiq.
Skelet o'sha; generativ loyihaga xos qo'shimcha — o'lchov asbobini qurish va kalibrlash, yodlash darvozasi va chiqishni belgilash.
2.2. Baholash asbobi va uni kalibrlash
KLASSIFIKATOR: MLP 64-128-64-10 (17 226 parametr), faqat o'quvda
val aniqligi 0.972; xususiyatlar - 64 o'lchamli oxirgi yashirin qatlam
METRIKALAR 26.7-bob:
togri - klassifikator generatsiyani so'ralgan sinf deb taniydimi
FD - xususiyatlarda Frechet masofa (FID g'oyasi), mos yozuv: val
precision - generatsiya haqiqiy k-NN sharlariga tushadimi (sifat)
recall - haqiqiy namunalar generatsiya sharlariga tushadimi (qamrov)
yodlash - mean NN(G -> o'quv) / mean NN(val -> o'quv); ~1 yaxshi
nusxa - NN(G -> o'quv) < q05 bo'lganlar ulushi;
q05 = haqiqiy yangi rasmlarning 5-foizligi -> haqiqiyda 0.05
KALIBRLASH (1-misol, val da):
generator togri FD recall yodlash nusxa
nusxachi (o'quvdan) 1.000 1.434 0.886 0.000 1.000
nusxa + shovqin 0.1 0.994 1.625 0.906 0.595 0.817
nusxa + shovqin 0.3 0.867 10.185 0.944 1.662 0.000
sinf o'rtachasi 1.000 10.002 0.000 0.898 0.000
tasodifiy shovqin 0.094 188.548 0.011 3.274 0.000
FD NAMUNALAR SONIGA BOG'LIQ (nusxachi): n=90 -> 6.474, 180 -> 2.538, 360 -> 1.434Kalibrlash jadvali butun loyihaning kaliti. Nusxachi — o'quv rasmlarini qaytaruvchi "generator" — FD bo'yicha eng yaxshi (1.434), chunki u haqiqiy taqsimotdan olingan. Ya'ni FD mukammal generator va nusxa ko'chiruvchini ajrata olmaydi — buni faqat yodlash darvozasi ushlaydi (nusxa 1.000). Sinf o'rtachasi 100% to'g'ri taniladi, lekin recall 0.000 — "to'g'ri sinf ulushi" yolg'iz qaror uchun yaroqsiz. Shovqinli nusxa sigma 0.1 da ushlandi (0.817), sigma 0.3 da esa darvozadan o'tib ketdi — lekin FD 10.185 ga oshdi: nusxani shunchalik buzish kerakki, sifat ham buziladi.
FD ning namunalar soniga kuchli bog'liqligi (6.474 → 1.434) — FID ning ma'lum xossasi: kichik n da u yuqoriga siljigan. Shuning uchun barcha nomzodlar aynan bir xil n (360) va bir xil mos yozuv to'plami bilan solishtiriladi; FD ning mutlaq qiymati emas, farqi ma'noli.
Asosiy metrika oldindan belgilanadi: FD; darvoza — nusxa ulushi ≤ 0.10; qolganlari diagnostika. Asbobni ma'lum "generatorlar"da tekshirmasdan unga ishonmang.
2.3. Nomzodlar va o'rgatish
NOMZODLAR (soddalik tartibida):
1) GMM PCA(20) + har sinfga GaussianMixture(3, full)
namuna: komponent -> z = mu + L e -> PCA teskari
2) cVAE enkoder [x, one-hot] -> z(8); dekoder [z, one-hot] -> 64
BCE + KL; 800 qadam; namuna = dekoder o'rtachasi
3) diffusion eps-bashoratchi MLP (192), T = 50, sinf embeddingi,
10% shartsiz (null sinf) -> classifier-free guidance
1000 qadam, cosine lr, EMA 0.99; DDPM sampling
GUIDANCE (2-misol, val, seed 0):
w togri FD recall
0.0 0.811 8.886 0.828
0.3 0.928 4.452 0.797 <- FD bo'yicha tanlandi
0.5 0.969 4.857 0.786
1.0 1.000 13.950 0.653
w oshsa: to'g'ri sinf ulushi oshadi, recall tushadi 26.6-bob
HISOB NARXI:
model parametrlar chaqiruv/namuna ~FLOP/namuna
GMM 8 274 0 3 360
cVAE 22 352 1 20 992
diffusion 74 528 100 14 745 600Guidance jadvali 26.6-darsdagi murosani aniq ko'rsatadi: w = 0 da diffusion so'ralgan sinfni atigi 81.1% hollarda beradi, w = 1.0 da 100% — lekin recall 0.828 dan 0.653 ga tushadi va FD 13.950 ga oshadi: model har sinfning eng "tipik" variantini chiqaradi. FD bo'yicha eng yaxshi — w = 0.3, u Konfig.cfg_w ga yozildi. Diqqat: w validatsiyada tanlandi va keyin taqqoslash ham validatsiyada — bu diffusion foydasiga kichik tanlov siljishi; biz buni bilamiz va hisobotga yozamiz (u faqat diffusion ni yaxshiroq ko'rsatadi, ya'ni qarorni o'zgartira olmaydi).
Hisob narxi alohida ustun sifatida: diffusion bitta namuna uchun 100 marta tarmoq chaqiradi (50 qadam × 2, CFG uchun shartli va shartsiz), GMM esa birortasini ham — faqat 20x20 va 20x64 matritsa ko'paytmalari.
Har nomzodning giperparametrini (masalan, w) validatsiyada tanlang va narxni sifat yonida yozing.
2.4. Taqqoslash va qaror
3 URUG' (har urug'da: model init, o'rgatish batchlari, namuna urug'i 1000 + s)
bir xil 360 ta shart (val sinflari), bir xil mos yozuv (val), bir xil asbob
JUFTLASHGAN FARQ (asosiy metrika - FD):
d_s = FD_nomzod,s - FD_eng,s; SE = std(d) / sqrt(3); d > 2 * SE -> sezilarli yomon
3-MISOL:
model togri FD recall nusxa (max)
GMM 0.978 2.151 0.806 0.031
cVAE 1.000 6.605 0.021 0.053
diffusion 0.923 4.584 0.793 0.000
cVAE - GMM: +4.454, SE 0.121 -> sezilarli yomon
diffusion - GMM: +2.433, SE 0.146 -> sezilarli yomon
QOIDA: eng yaxshisidan SEZILARLI yomon bo'lmagan + darvozadan o'tgan ENG SODDA
-> GMMNatija aniq: GMM eng yaxshi ham, eng sodda ham. cVAE so'ralgan sinfni har doim beradi (1.000), lekin recall 0.021 — dekoder o'rtachasi xira, har sinfda deyarli bitta "o'rtacha" raqam (26.2-darsdagi VAE xiraligi). Diffusion qamrovda GMM ga teng (0.793 va 0.806), lekin uning namunalari shovqinli: yodlash nisbati 1.457 — namunalar har qanday haqiqiy rasmdan haqiqiy yangi rasmlarga qaraganda uzoqroq, to'g'ri sinf ulushi 0.923.
Bu natijani qanday tushunish kerak? Bu "diffusion yomon" degani emas. 8x8 digits — kichik, sodda taqsimot: PCA ning 20 komponenti deyarli butun dispersiyani tushuntiradi, va Gauss aralashmasi uni yaxshi ifodalaydi. Diffusion esa kichik CPU byudjetida (1000 qadam) o'rgatildi — katta byudjet va katta rasmlarda aynan u ustun (26.5-26.8). To'g'ri xulosa: "bu vazifa va bu byudjetda murakkab nomzodlar murakkabligini oqlamadi". Xuddi 23.14-darsdagi kabi — va 24.12-darsdagidan farqli o'laroq, u yerda transformer o'zini oqlagan edi.
Qarorni juftlashgan farq, darvoza va soddalik tartibi belgilaydi — model nomining mashhurligi emas. Byudjet shartini qarorning bir qismi sifatida yozing.
2.5. Test, paket va deterministik nazorat
YAKUNIY MODEL: GMM, o'quv + val (1437 rasm) da; asbob - o'sha (faqat o'quvda)
TEST BIR MARTA (360 rasm, 3 namuna urug'i):
nusxachi (pastki chegara) FD 2.176
GMM: FD 2.480, 2.237, 2.368 -> 2.362 (+- 0.122); to'g'ri sinf 0.984
nusxa max 0.039 (haqiqiyda 0.05) -> darvozadan o'tdi
PAKET:
{"format", "konfig", "tanlov", "holat": {komp, orta, w, mu, L},
"metrika", "watermark": {usul, a, kalit_id}, "versiyalar",
"nazorat": {c, seed, namuna}}
holat - FAQAT tenzorlar (sklearn obyekti yo'q) -> weights_only=True bilan yuklanadi
watermark KALITI paketga yozilmaydi (sir)
DETERMINISTIK NAZORAT:
yuklangan model namuna(c, seed=7) == saqlangan namuna -> OK (torch.equal)
bir xil urug' ikki marta -> True; boshqa urug' -> farqliTest natijasi validatsiyaga mos (2.362 va 2.151; testda mos yozuv boshqa to'plam, shuning uchun mutlaq qiymat biroz farq qiladi). Eng ma'noli taqqoslash — xuddi shu test to'plamidagi nusxachi: 2.176. GMM ning FD si "mukammal generator" chegarasiga juda yaqin, nusxa ulushi esa 0.039 — haqiqiy yangi rasmlardagi 0.05 dan ham past.
Paketning muhim dizayn qarori — sklearn obyektlarini emas, tenzorlarni saqlash. GaussianMixture ni pickle bilan saqlash mumkin edi, lekin weights_only=True uni yuklamaydi — va bu to'g'ri: pickle ixtiyoriy kodni bajarishi mumkin 22.14-bob. Namuna olish ham torch da, torch.Generator bilan qayta yozildi — shuning uchun "urug' 7 → aynan shu 20 ta rasm" nazorati torch.equal bilan o'tadi.
Generativ paket = konfig + tenzor holat + urug'li nazorat namunasi; nazorat "model o'zgarmadi" va "sampling deterministik" ni birga tekshiradi.
2.6. Watermark va hisobot
XIZMAT FORMATI: 8x8 -> 16x16 (kron + 3x3 silliqlash) + a * naqsh(kalit), a = 0.04
4-MISOL (360 ta chiqish, chegara z > 4):
belgili chiqish 100.0% z 9.98
belgili + JPEG 70 99.7% z 5.79
belgisiz chiqish 0.0% z 1.02
haqiqiy test 0.0% z 0.92
FOYDALILIK: klassifikator to'g'ri sinf ulushi 0.967 -> 0.969 (watermark bilan)
MODEL KARTASI (qisqa hisobot):
vazifa, metrika, qaror (byudjet sharti bilan), test raqamlari,
maxfiylik (nusxa ulushi), paket, cheklovlar26.9-darsdagi watermark bu yerda mahsulotning bir qismi bo'ldi. Muhim tekshiruv — foydalilik: watermark rasmni "buzmadi" — klassifikator uni o'sha darajada taniydi (0.967 va 0.969). Belgisiz chiqish va haqiqiy test rasmlarida yolg'on musbat 0.0%, lekin ularning z o'rtachasi ~1 — 26.9 dagi kabi nazariy nol emas; chegara 4 bilan zaxira yetarli.
Hisobotdagi cheklovlar qatori ham raqamlar kabi muhim: a'zolik hujumi bu loyihada tekshirilmagan (26.9 dagi usul bilan qo'shish mumkin), watermark xiralash va siljitishga chidamsiz, FD kichik n da shovqinli.
Hisobot = model kartasi: har da'vo 1-4-misollardagi raqam bilan, cheklovlar ochiq.
2.7. Tuzoqlar
Asosiy tuzoqlar: baholash klassifikatorini val yoki test bilan o'rgatish (asbob ham sizadi); asbobni kalibrlamay unga ishonish; FD ni turli n yoki turli mos yozuv to'plami bilan solishtirish; asosiy metrikani natijalarni ko'rgandan keyin tanlash; faqat "to'g'ri sinf ulushi" bilan baholash (sinf o'rtachasi 100% oladi); nusxachini FD bo'yicha "eng yaxshi" deb tanlash (yodlash darvozasisiz); guidance w ni testda tanlash; bitta urug' bilan "diffusion yomon" yoki "GMM yaxshi" deyish; byudjet shartini qarordan olib tashlab "har doim" deb yozish; testni bir necha marta ochish; sklearn obyektini pickle bilan saqlab weights_only=False bilan yuklash; namuna olishni global urug' bilan qilish (nazorat takrorlanmaydi); watermark kalitini paketga yozish; watermark foydalilikni buzmaganini tekshirmaslik; hisobotda cheklovlarni yozmaslik.
3. Tez ma'lumotnoma
k = Konfig()
X, y, tr, va, te = malumot(k) # test QULF
klf = orgat_klf(k, X[tr], y[tr]) # asbob - faqat o'quvda
baho = Baholovchi(klf, X[tr], X[va], y[va]) # mos yozuv: val
r = baho(model.namuna(y[va], seed=1000 + s), y[va]) # togri, FD, P, R, yodlash, nusxa
d = fd[nomzod] - fd[eng]; yomon = d.mean() > 2 * d.std(ddof=1) / np.sqrt(3)
tanlov = next(n for n in SODDALIK if not yomon[n] and nusxa_max[n] <= k.nusxa_max)
baho_test = Baholovchi(klf, X[ish], X[te], y[te]) # test BIR MARTA
torch.save({"konfig": asdict(k), "holat": {...tenzorlar...},
"nazorat": {"c": c, "seed": 7, "namuna": namuna}}, yol)
p = torch.load(yol, weights_only=True)
assert torch.equal(torch.tensor(YuklanganGMM(p["holat"]).namuna(c, seed=7)), p["nazorat"]["namuna"])
z = z_ball(chiqish(G8, KALIT, k.wm_a), KALIT) # z > 4 -> watermark borAmaliyot xulosasi
konfig -> bo'lish (test qulf) -> asbob (faqat o'quvda) -> asbobni kalibrlash
asosiy metrika oldindan: FD; darvoza: nusxa ulushi
nomzodlar: GMM < cVAE < diffusion; w validatsiyada
3 urug' juftlashgan FD -> eng sodda munosib (bu yerda: GMM)
test bir marta; paket: tenzorlar + urug'li nazorat; weights_only=True
chiqishga watermark; foydalilik va FPR tekshiruvi; model kartasi4. Batafsil misollar
Misollar real numpy/sklearn/torch bilan (Python 3.14, torch 2.14 CPU). Har misol mustaqil ishlaydi, shuning uchun umumiy kod (konfig, ma'lumot, asbob, modellar) har birida takrorlanadi.
Misol 1 — Konfig, bo'lish, baholash asbobi va uni kalibrlash
"""1-qadam: konfig, bo'lish, baholash klassifikatori va o'lchov asbobini kalibrlash."""
import warnings
from dataclasses import dataclass
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from scipy import linalg
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
@dataclass(frozen=True)
class Konfig:
seed: int = 0
pca: int = 20
gmm_k: int = 3
vae_z: int = 8
vae_h: int = 128
vae_qadam: int = 800
dif_T: int = 50
dif_h: int = 192
dif_qadam: int = 1000
ema: float = 0.99
p_shartsiz: float = 0.1
cfg_w: float = 0.3 # 2-qadamda validatsiyada tanlangan
bs: int = 128
lr: float = 2e-3
klf_qadam: int = 600
urug_soni: int = 3
nusxa_max: float = 0.10 # yodlash darvozasi (haqiqiyda ~0.05)
wm_a: float = 0.04 # watermark kuchi (26.9)
def malumot(k):
X, y = load_digits(return_X_y=True)
X = (X / 16).astype(np.float32)
i = np.arange(len(X))
ish, te = train_test_split(i, test_size=0.2, stratify=y, random_state=k.seed)
tr, va = train_test_split(ish, test_size=0.25, stratify=y[ish], random_state=k.seed)
return X, y, tr, va, te
# ---------------- baholash asbobi (faqat o'quv qismida o'rgatiladi) ----------------
class Klf(nn.Module):
def __init__(self):
super().__init__()
self.f = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, 64), nn.ReLU())
self.bosh = nn.Linear(64, 10)
def forward(self, x):
return self.bosh(self.f(x))
def orgat_klf(k, X, y):
torch.manual_seed(k.seed)
m = Klf()
opt = torch.optim.AdamW(m.parameters(), lr=k.lr, weight_decay=1e-3)
X, y = torch.tensor(X), torch.tensor(y)
g = torch.Generator().manual_seed(k.seed)
for _ in range(k.klf_qadam):
i = torch.randint(0, len(X), (128,), generator=g)
xb = (X[i] + 0.05 * torch.randn(X[i].shape, generator=g)).clamp(0, 1)
loss = F.cross_entropy(m(xb), y[i])
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
def frechet(a, b):
m1, m2 = a.mean(0), b.mean(0)
s1, s2 = np.cov(a, rowvar=False), np.cov(b, rowvar=False)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
cs = np.real(linalg.sqrtm(s1 @ s2))
return float(((m1 - m2) ** 2).sum() + np.trace(s1 + s2 - 2 * cs))
def prec_recall(real, gen, k=3):
"""k-NN precision/recall: namuna boshqa to'plamning k-NN sharlaridan biriga tushadimi."""
real, gen = torch.tensor(real), torch.tensor(gen)
rr = torch.cdist(real, real).kthvalue(k + 1, dim=1).values
rg = torch.cdist(gen, gen).kthvalue(k + 1, dim=1).values
d = torch.cdist(gen, real)
return (float((d <= rr[None]).any(1).float().mean()),
float((d.T <= rg[None]).any(1).float().mean()))
class Baholovchi:
"""Bitta mos yozuvli haqiqiy to'plam (val yoki test) bilan barcha metrikalar."""
def __init__(self, klf, X_oquv, X_ref, y_ref):
self.klf, self.X_oquv = klf, torch.tensor(X_oquv)
self.y_ref = y_ref
self.f_ref = self.xus(X_ref)
d = torch.cdist(torch.tensor(X_ref), self.X_oquv).min(1).values
self.d_real = float(d.mean()) # yangi haqiqiy namuna o'quvdan qancha uzoq
self.q05 = float(d.quantile(0.05))
@torch.no_grad()
def xus(self, X):
return self.klf.f(torch.as_tensor(X, dtype=torch.float32)).double().numpy()
@torch.no_grad()
def __call__(self, G, c):
G = torch.as_tensor(G, dtype=torch.float32)
togri = float((self.klf(G).argmax(1).numpy() == c).mean())
fg = self.xus(G)
p, r = prec_recall(self.f_ref, fg)
d = torch.cdist(G, self.X_oquv).min(1).values
return {"togri": togri, "FD": frechet(fg, self.f_ref), "precision": p, "recall": r,
"yodlash": float(d.mean()) / self.d_real, "nusxa": float((d < self.q05).float().mean())}
def main() -> None:
torch.set_num_threads(1)
k = Konfig()
print("=== 1. Konfig va ma'lumot ===")
print(f" {k}")
X, y, tr, va, te = malumot(k)
print(f" digits: {len(X)} rasm 8x8, qiymatlar [0, 1]; o'quv {len(tr)}, val {len(va)}, "
f"test {len(te)} (sinf bo'yicha stratifikatsiya)")
print(f" umumiy indekslar: o'quv-val {len(np.intersect1d(tr, va))}, "
f"o'quv-test {len(np.intersect1d(tr, te))}, val-test {len(np.intersect1d(va, te))}")
d = torch.cdist(torch.tensor(X[te]), torch.tensor(X[tr])).min(1).values
print(f" testda o'quvdagi rasmning AYNAN nusxasi: {int((d == 0).sum())} ta")
print(" sinflar (o'quv): " + " ".join(str(int(v)) for v in np.bincount(y[tr])))
print(" TEST QULFLANDI - faqat 4-qadamda bir marta ochiladi")
print("\n=== 2. Baholash klassifikatori (faqat o'quv qismida) ===")
klf = orgat_klf(k, X[tr], y[tr])
with torch.no_grad():
acc = (klf(torch.tensor(X[va])).argmax(1).numpy() == y[va]).mean()
n_par = sum(p.numel() for p in klf.parameters())
print(f" MLP 64-128-64-10 ({n_par} parametr), val aniqligi {acc:.3f}")
print(" xususiyatlar: 64 o'lchamli oxirgi yashirin qatlam (FD va k-NN uchun)")
print("\n=== 3. O'lchov asbobini kalibrlash: ma'lum 'generatorlar' ===")
baho = Baholovchi(klf, X[tr], X[va], y[va])
c = y[va]
rng = np.random.default_rng(k.seed)
nusxachi = np.array([rng.choice(tr[y[tr] == s]) for s in c])
orta = np.stack([X[tr][y[tr] == s].mean(0) for s in range(10)])
etalon = {
"nusxachi (o'quvdan)": X[nusxachi],
"nusxa + shovqin 0.1": np.clip(X[nusxachi] + rng.normal(0, 0.1, (len(c), 64)), 0, 1),
"nusxa + shovqin 0.3": np.clip(X[nusxachi] + rng.normal(0, 0.3, (len(c), 64)), 0, 1),
"sinf o'rtachasi": orta[c],
"tasodifiy shovqin": rng.random((len(c), 64)),
}
metrikalar = ["togri", "FD", "precision", "recall", "yodlash", "nusxa"]
print(" generator " + "".join(f"{m:>10}" for m in metrikalar))
natija = {}
for nom, G in etalon.items():
natija[nom] = baho(G.astype(np.float32), c)
print(f" {nom:<21} " + "".join(f"{natija[nom][m]:>10.3f}" for m in metrikalar))
print(f" haqiqiy yangi namuna (val): yodlash 1.000, nusxa 0.050 (ta'rif bo'yicha); "
f"q05 = {baho.q05:.3f}")
print("\n=== 4. Asbob nimani ushlaydi (natijadan) ===")
n = natija["nusxachi (o'quvdan)"]
if n["FD"] < 2 * natija["nusxa + shovqin 0.3"]["FD"] and n["nusxa"] > 0.9:
print(f" nusxachi: FD {n['FD']:.3f} - eng yaxshi ko'rinadi, lekin nusxa {n['nusxa']:.3f}"
" -> FAQAT yodlash darvozasi ushlaydi")
o = natija["sinf o'rtachasi"]
print(f" sinf o'rtachasi: to'g'ri sinf {o['togri']:.3f}, lekin recall {o['recall']:.3f} "
"-> aniqlik yolg'iz aldaydi")
s = natija["nusxa + shovqin 0.1"]
print(f" shovqinli nusxa 0.1-bob: nusxa ulushi {s['nusxa']:.3f} "
f"-> {'ushlandi' if s['nusxa'] > k.nusxa_max else 'ushlanmadi'}")
s = natija["nusxa + shovqin 0.3"]
print(f" shovqinli nusxa 0.3-bob: nusxa ulushi {s['nusxa']:.3f} "
f"-> {'ushlandi' if s['nusxa'] > k.nusxa_max else 'ushlanmadi'}, lekin FD {s['FD']:.3f}")
print("\n=== 5. FD namunalar soniga bog'liq (nusxachi, turli n) ===")
for m in (90, 180, 360):
i = rng.choice(len(va), m, replace=False)
b = Baholovchi(klf, X[tr], X[va][i], y[va][i])
print(f" n = {m:>3}: FD {b(X[nusxachi][i], c[i])['FD']:.3f}")
print(" -> barcha nomzodlar AYNAN bir xil n va bir xil mos yozuv bilan solishtiriladi")
print(" ASOSIY METRIKA (oldindan belgilangan): FD; darvoza: nusxa <= "
f"{k.nusxa_max:.2f}; qolganlari - diagnostika")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Konfig va ma'lumot ===
Konfig(seed=0, pca=20, gmm_k=3, vae_z=8, vae_h=128, vae_qadam=800, dif_T=50, dif_h=192, dif_qadam=1000, ema=0.99, p_shartsiz=0.1, cfg_w=0.3, bs=128, lr=0.002, klf_qadam=600, urug_soni=3, nusxa_max=0.1, wm_a=0.04)
digits: 1797 rasm 8x8, qiymatlar [0, 1]; o'quv 1077, val 360, test 360 (sinf bo'yicha stratifikatsiya)
umumiy indekslar: o'quv-val 0, o'quv-test 0, val-test 0
testda o'quvdagi rasmning AYNAN nusxasi: 0 ta
sinflar (o'quv): 107 109 106 109 109 109 109 107 104 108
TEST QULFLANDI - faqat 4-qadamda bir marta ochiladi
=== 2. Baholash klassifikatori (faqat o'quv qismida) ===
MLP 64-128-64-10 (17226 parametr), val aniqligi 0.972
xususiyatlar: 64 o'lchamli oxirgi yashirin qatlam (FD va k-NN uchun)
=== 3. O'lchov asbobini kalibrlash: ma'lum 'generatorlar' ===
generator togri FD precision recall yodlash nusxa
nusxachi (o'quvdan) 1.000 1.434 0.919 0.886 0.000 1.000
nusxa + shovqin 0.1 0.994 1.625 0.894 0.906 0.595 0.817
nusxa + shovqin 0.3 0.867 10.185 0.664 0.944 1.662 0.000
sinf o'rtachasi 1.000 10.002 1.000 0.000 0.898 0.000
tasodifiy shovqin 0.094 188.548 0.061 0.011 3.274 0.000
haqiqiy yangi namuna (val): yodlash 1.000, nusxa 0.050 (ta'rif bo'yicha); q05 = 0.715
=== 4. Asbob nimani ushlaydi (natijadan) ===
nusxachi: FD 1.434 - eng yaxshi ko'rinadi, lekin nusxa 1.000 -> FAQAT yodlash darvozasi ushlaydi
sinf o'rtachasi: to'g'ri sinf 1.000, lekin recall 0.000 -> aniqlik yolg'iz aldaydi
shovqinli nusxa 0.1-bob: nusxa ulushi 0.817 -> ushlandi
shovqinli nusxa 0.3-bob: nusxa ulushi 0.000 -> ushlanmadi, lekin FD 10.185
=== 5. FD namunalar soniga bog'liq (nusxachi, turli n) ===
n = 90: FD 6.474
n = 180: FD 2.538
n = 360: FD 1.434
-> barcha nomzodlar AYNAN bir xil n va bir xil mos yozuv bilan solishtiriladi
ASOSIY METRIKA (oldindan belgilangan): FD; darvoza: nusxa <= 0.10; qolganlari - diagnostikaNima ko'rsatdi: 2.1, 2.2-bo'limlar. Bo'linishlar orasida umumiy indeks yo'q va testda o'quv rasmining aynan nusxasi 0 ta — test haqiqatan yangi. Sinflar muvozanatli (104-109). Asbob — 17 226 parametrli MLP — val da 0.972 aniqlik berdi. Kalibrlash jadvali asbobning har qismi nima uchun kerakligini ko'rsatdi: FD nusxachini "eng yaxshi" deb biladi, uni faqat nusxa ulushi ushlaydi; to'g'ri sinf ulushi sinf o'rtachasini ham 100% deb biladi, uni recall ushlaydi; FD esa n ga kuchli bog'liq. Shu kalibrlashdan keyin asosiy metrika (FD) va darvoza (nusxa ≤ 0.10) natijalarni ko'rmasdan oldin belgilandi.
Misol 2 — Uch nomzod validatsiyada: guidance, metrikalar, narx va namunalar
"""2-qadam: uch nomzod validatsiyada - guidance tanlovi, metrikalar, hisob narxi va namunalar."""
import copy
import math
import warnings
from dataclasses import dataclass
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from scipy import linalg
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.mixture import GaussianMixture
from sklearn.model_selection import train_test_split
SODDALIK = ["GMM", "cVAE", "diffusion"] # soddadan murakkabga
@dataclass(frozen=True)
class Konfig:
seed: int = 0
pca: int = 20
gmm_k: int = 3
vae_z: int = 8
vae_h: int = 128
vae_qadam: int = 800
dif_T: int = 50
dif_h: int = 192
dif_qadam: int = 1000
ema: float = 0.99
p_shartsiz: float = 0.1
cfg_w: float = 0.3 # 2-qadamda validatsiyada tanlangan
bs: int = 128
lr: float = 2e-3
klf_qadam: int = 600
urug_soni: int = 3
nusxa_max: float = 0.10 # yodlash darvozasi (haqiqiyda ~0.05)
wm_a: float = 0.04 # watermark kuchi (26.9)
def malumot(k):
X, y = load_digits(return_X_y=True)
X = (X / 16).astype(np.float32)
i = np.arange(len(X))
ish, te = train_test_split(i, test_size=0.2, stratify=y, random_state=k.seed)
tr, va = train_test_split(ish, test_size=0.25, stratify=y[ish], random_state=k.seed)
return X, y, tr, va, te
# ---------------- baholash asbobi (faqat o'quv qismida o'rgatiladi) ----------------
class Klf(nn.Module):
def __init__(self):
super().__init__()
self.f = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, 64), nn.ReLU())
self.bosh = nn.Linear(64, 10)
def forward(self, x):
return self.bosh(self.f(x))
def orgat_klf(k, X, y):
torch.manual_seed(k.seed)
m = Klf()
opt = torch.optim.AdamW(m.parameters(), lr=k.lr, weight_decay=1e-3)
X, y = torch.tensor(X), torch.tensor(y)
g = torch.Generator().manual_seed(k.seed)
for _ in range(k.klf_qadam):
i = torch.randint(0, len(X), (128,), generator=g)
xb = (X[i] + 0.05 * torch.randn(X[i].shape, generator=g)).clamp(0, 1)
loss = F.cross_entropy(m(xb), y[i])
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
def frechet(a, b):
m1, m2 = a.mean(0), b.mean(0)
s1, s2 = np.cov(a, rowvar=False), np.cov(b, rowvar=False)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
cs = np.real(linalg.sqrtm(s1 @ s2))
return float(((m1 - m2) ** 2).sum() + np.trace(s1 + s2 - 2 * cs))
def prec_recall(real, gen, k=3):
"""k-NN precision/recall: namuna boshqa to'plamning k-NN sharlaridan biriga tushadimi."""
real, gen = torch.tensor(real), torch.tensor(gen)
rr = torch.cdist(real, real).kthvalue(k + 1, dim=1).values
rg = torch.cdist(gen, gen).kthvalue(k + 1, dim=1).values
d = torch.cdist(gen, real)
return (float((d <= rr[None]).any(1).float().mean()),
float((d.T <= rg[None]).any(1).float().mean()))
class Baholovchi:
"""Bitta mos yozuvli haqiqiy to'plam (val yoki test) bilan barcha metrikalar."""
def __init__(self, klf, X_oquv, X_ref, y_ref):
self.klf, self.X_oquv = klf, torch.tensor(X_oquv)
self.y_ref = y_ref
self.f_ref = self.xus(X_ref)
d = torch.cdist(torch.tensor(X_ref), self.X_oquv).min(1).values
self.d_real = float(d.mean()) # yangi haqiqiy namuna o'quvdan qancha uzoq
self.q05 = float(d.quantile(0.05))
@torch.no_grad()
def xus(self, X):
return self.klf.f(torch.as_tensor(X, dtype=torch.float32)).double().numpy()
@torch.no_grad()
def __call__(self, G, c):
G = torch.as_tensor(G, dtype=torch.float32)
togri = float((self.klf(G).argmax(1).numpy() == c).mean())
fg = self.xus(G)
p, r = prec_recall(self.f_ref, fg)
d = torch.cdist(G, self.X_oquv).min(1).values
return {"togri": togri, "FD": frechet(fg, self.f_ref), "precision": p, "recall": r,
"yodlash": float(d.mean()) / self.d_real, "nusxa": float((d < self.q05).float().mean())}
# ---------------- nomzodlar ----------------
class ShartliGMM:
"""Har sinfga PCA fazosida GaussianMixture; namuna torch.Generator bilan."""
def __init__(self, k, X, y, seed):
pca = PCA(k.pca, random_state=seed).fit(X)
Z = pca.transform(X)
self.komp = torch.tensor(pca.components_, dtype=torch.float64)
self.orta = torch.tensor(pca.mean_, dtype=torch.float64)
w, mu, L = [], [], []
for c in range(10):
with warnings.catch_warnings():
warnings.simplefilter("ignore")
gm = GaussianMixture(k.gmm_k, random_state=seed).fit(Z[y == c])
w.append(gm.weights_)
mu.append(gm.means_)
L.append(np.linalg.cholesky(gm.covariances_ + 1e-6 * np.eye(k.pca)))
self.w, self.mu, self.L = (torch.tensor(np.array(a)) for a in (w, mu, L))
def namuna(self, c, seed):
g = torch.Generator().manual_seed(seed)
c = torch.as_tensor(c)
j = torch.multinomial(self.w[c], 1, generator=g)[:, 0]
e = torch.randn(len(c), self.mu.shape[2], generator=g, dtype=torch.float64)
z = self.mu[c, j] + (self.L[c, j] @ e[:, :, None])[:, :, 0]
return (z @ self.komp + self.orta).clamp(0, 1).float().numpy()
def parametrlar(self):
return sum(t.numel() for t in (self.komp, self.orta, self.w, self.mu)) + \
10 * self.L.shape[1] * self.L.shape[2] * (self.L.shape[2] + 1) // 2
class CVAE(nn.Module):
def __init__(self, k):
super().__init__()
self.z = k.vae_z
self.enc = nn.Sequential(nn.Linear(74, k.vae_h), nn.ReLU(), nn.Linear(k.vae_h, 2 * k.vae_z))
self.dec = nn.Sequential(nn.Linear(k.vae_z + 10, k.vae_h), nn.ReLU(), nn.Linear(k.vae_h, 64))
def loss(self, x, c, g):
oh = F.one_hot(c, 10).float()
mu, logv = self.enc(torch.cat([x, oh], 1)).chunk(2, 1)
z = mu + torch.randn(mu.shape, generator=g) * (0.5 * logv).exp()
r = self.dec(torch.cat([z, oh], 1))
kl = -0.5 * (1 + logv - mu ** 2 - logv.exp()).sum(1)
return (F.binary_cross_entropy_with_logits(r, x, reduction="none").sum(1) + kl).mean()
@torch.no_grad()
def namuna(self, c, seed):
g = torch.Generator().manual_seed(seed)
c = torch.as_tensor(c)
z = torch.randn(len(c), self.z, generator=g)
return torch.sigmoid(self.dec(torch.cat([z, F.one_hot(c, 10).float()], 1))).numpy()
def jadval(T):
beta = torch.linspace(1e-4 * 1000 / T, 0.02 * 1000 / T, T)
return beta, 1 - beta, torch.cumprod(1 - beta, 0)
class Diffusion(nn.Module):
"""eps-bashoratchi MLP; sinf 10 = shartsiz (classifier-free guidance uchun)."""
def __init__(self, k):
super().__init__()
self.T, self.w = k.dif_T, k.cfg_w
self.emb = nn.Embedding(11, 32)
self.net = nn.Sequential(nn.Linear(128, k.dif_h), nn.SiLU(), nn.Linear(k.dif_h, k.dif_h),
nn.SiLU(), nn.Linear(k.dif_h, 64))
def forward(self, x, t, c):
f = torch.exp(-math.log(1000) * torch.arange(16) / 16)
a = t.float()[:, None] * f[None]
return self.net(torch.cat([x, a.sin(), a.cos(), self.emb(c)], 1))
def loss(self, x, c, g, p_shartsiz):
_, _, ab = jadval(self.T)
x = x * 2 - 1
t = torch.randint(0, self.T, (len(x),), generator=g)
e = torch.randn(x.shape, generator=g)
a = ab[t][:, None]
c = torch.where(torch.rand(len(x), generator=g) < p_shartsiz, 10, c)
return F.mse_loss(self(a.sqrt() * x + (1 - a).sqrt() * e, t, c), e)
@torch.no_grad()
def namuna(self, c, seed, w=None):
w = self.w if w is None else w
g = torch.Generator().manual_seed(seed)
beta, alfa, ab = jadval(self.T)
c = torch.as_tensor(c)
n = len(c)
x = torch.randn(n, 64, generator=g)
for t in reversed(range(self.T)):
tt = torch.full((2 * n,), t)
e = self(torch.cat([x, x]), tt, torch.cat([c, torch.full_like(c, 10)]))
e = (1 + w) * e[:n] - w * e[n:] # classifier-free guidance
x = (x - beta[t] / (1 - ab[t]).sqrt() * e) / alfa[t].sqrt()
if t > 0:
x = x + beta[t].sqrt() * torch.randn(n, 64, generator=g)
return ((x.clamp(-1, 1) + 1) / 2).numpy()
def orgat_nn(k, model, X, y, seed, qadamlar, ema=None):
torch.manual_seed(seed)
opt = torch.optim.Adam(model.parameters(), lr=k.lr)
jad = torch.optim.lr_scheduler.LambdaLR(opt, lambda s: 0.5 * (1 + math.cos(math.pi * s / qadamlar)))
X, y = torch.tensor(X), torch.tensor(y)
g = torch.Generator().manual_seed(seed)
orta = copy.deepcopy(model) if ema else None
for _ in range(qadamlar):
i = torch.randint(0, len(X), (k.bs,), generator=g)
if isinstance(model, Diffusion):
loss = model.loss(X[i], y[i], g, k.p_shartsiz)
else:
loss = model.loss(X[i], y[i], g)
opt.zero_grad()
loss.backward()
opt.step()
jad.step()
if orta is not None:
with torch.no_grad():
for po, p in zip(orta.parameters(), model.parameters()):
po.lerp_(p, 1 - ema)
return (orta if orta is not None else model).eval()
def yarat(nom, k, X, y, seed):
if nom == "GMM":
return ShartliGMM(k, X, y, seed)
torch.manual_seed(seed)
if nom == "cVAE":
return orgat_nn(k, CVAE(k), X, y, seed, k.vae_qadam)
return orgat_nn(k, Diffusion(k), X, y, seed, k.dif_qadam, ema=k.ema)
BELGI = " .:-=+*#%@"
def chiz(x):
q = np.clip(np.round(x.reshape(8, 8) * 9), 0, 9).astype(int)
return ["".join(BELGI[v] * 2 for v in qator) for qator in q]
def narx(nom, m, k):
"""Parametrlar, bitta namunaga tarmoq chaqiruvlari va taxminiy FLOP."""
if nom == "GMM":
return m.parametrlar(), 0, 2 * k.pca * k.pca + 2 * k.pca * 64
n_par = sum(p.numel() for p in m.parameters())
if nom == "cVAE":
return n_par, 1, 2 * ((k.vae_z + 10) * k.vae_h + k.vae_h * 64)
bir = 2 * (128 * k.dif_h + k.dif_h * k.dif_h + k.dif_h * 64)
return n_par, 2 * k.dif_T, 2 * k.dif_T * bir # CFG: har qadamda 2 chaqiruv
def main() -> None:
torch.set_num_threads(1)
k = Konfig()
X, y, tr, va, te = malumot(k)
klf = orgat_klf(k, X[tr], y[tr])
baho = Baholovchi(klf, X[tr], X[va], y[va])
c = y[va]
metrikalar = ["togri", "FD", "precision", "recall", "yodlash", "nusxa"]
print("=== 1. Diffusion: guidance kuchi w ni validatsiyada tanlash (seed 0) ===")
dif = yarat("diffusion", k, X[tr], y[tr], seed=0)
print(" w " + "".join(f"{m:>10}" for m in metrikalar))
fd_w = {}
for w in (0.0, 0.3, 0.5, 1.0):
r = baho(dif.namuna(c, seed=1000, w=w), c)
fd_w[w] = r["FD"]
print(f" {w:<5} " + "".join(f"{r[m]:>10.3f}" for m in metrikalar))
w_eng = min(fd_w, key=fd_w.get)
print(f" FD bo'yicha eng yaxshi w = {w_eng} (Konfig.cfg_w = {k.cfg_w})")
print(" w oshsa: to'g'ri sinf ulushi oshadi, recall tushadi (26.6 murosasi)")
print("\n=== 2. Uch nomzod validatsiyada (seed 0, bir xil 360 ta shart) ===")
modellar = {"GMM": yarat("GMM", k, X[tr], y[tr], seed=0),
"cVAE": yarat("cVAE", k, X[tr], y[tr], seed=0), "diffusion": dif}
print(" model " + "".join(f"{m:>10}" for m in metrikalar))
namunalar = {}
for nom, m in modellar.items():
namunalar[nom] = m.namuna(c, seed=1000)
r = baho(namunalar[nom], c)
print(f" {nom:<9} " + "".join(f"{r[m_]:>10.3f}" for m_ in metrikalar))
print("\n=== 3. Hisob narxi ===")
print(" model parametrlar tarmoq chaqiruvi/namuna ~FLOP/namuna")
for nom, m in modellar.items():
p, ch, fl = narx(nom, m, k)
print(f" {nom:<10} {p:>11} {ch:>24} {fl:>14,}".replace(",", " "))
print("\n=== 4. '3' raqami: haqiqiy (val) va har modeldan bittadan namuna ===")
i = int(np.flatnonzero(c == 3)[0])
rasmlar = [X[va][i]] + [namunalar[n][i] for n in modellar]
print((" " + "".join(f"{n:<20}" for n in ["haqiqiy"] + list(modellar))).rstrip())
for qatorlar in zip(*[chiz(r) for r in rasmlar]):
print(" " + "".join(f"{q:<20}" for q in qatorlar).rstrip())
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Diffusion: guidance kuchi w ni validatsiyada tanlash (seed 0) ===
w togri FD precision recall yodlash nusxa
0.0 0.811 8.886 0.800 0.828 1.536 0.000
0.3 0.928 4.452 0.828 0.797 1.462 0.000
0.5 0.969 4.857 0.839 0.786 1.416 0.000
1.0 1.000 13.950 0.847 0.653 1.346 0.000
FD bo'yicha eng yaxshi w = 0.3 (Konfig.cfg_w = 0.3)
w oshsa: to'g'ri sinf ulushi oshadi, recall tushadi (26.6 murosasi)
=== 2. Uch nomzod validatsiyada (seed 0, bir xil 360 ta shart) ===
model togri FD precision recall yodlash nusxa
GMM 0.989 1.951 0.931 0.781 0.953 0.031
cVAE 1.000 6.586 1.000 0.014 0.915 0.036
diffusion 0.928 4.452 0.828 0.797 1.462 0.000
=== 3. Hisob narxi ===
model parametrlar tarmoq chaqiruvi/namuna ~FLOP/namuna
GMM 8274 0 3 360
cVAE 22352 1 20 992
diffusion 74528 100 14 745 600
=== 4. '3' raqami: haqiqiy (val) va har modeldan bittadan namuna ===
haqiqiy GMM cVAE diffusion
..++%%-- ..**%%##.. ++%%%%**.. **++@@==
%%**--** ..@@##**@@:: ::##**####:: ::@@..@@@@ --
::%%..::%% --%% **@@ ..::::##++ .. @@@@::
--..##++ :: @@** ..++%%:: --@@++
**##.. ::@@%%.. ..++%%-- @@%%
==** .. --##:: ..::****.. -- @@##
##++::::%% --==**%%:: ==++##++ ==..:: ==@@##
..**@@%%**.. ..####++:: **%%**.. ==--@@@@++Nima ko'rsatdi: 2.3-bo'lim. Guidance kuchi FD bo'yicha tanlandi (w = 0.3) — ham w = 0 (so'ralgan sinf 81.1%), ham w = 1.0 (recall 0.653) dan yaxshi. Bitta urug'da (seed 0) GMM FD 1.951, diffusion 4.452, cVAE 6.586. ASCII rasmlar metrikalarni "ko'z bilan" tasdiqlaydi: GMM ning "3" i haqiqiyga o'xshash, cVAE niki silliq va o'rtachalashgan (26.2 dagi xiralik), diffusion niki esa "3" shaklida, lekin shovqinli piksellar bilan. Lekin qaror ko'zga emas, keyingi misoldagi uch urug'ga asoslanadi. Narx jadvali: diffusion 74 528 parametr, har namunaga 100 tarmoq chaqiruvi va ~14.7 MFLOP; GMM — 8 274 parametr va ~3.4 kFLOP.
Misol 3 — Uch urug'da juftlashgan taqqoslash va qaror
"""3-qadam: uch urug'da juftlashgan taqqoslash, yodlash darvozasi va eng sodda munosib model."""
import copy
import math
import warnings
from dataclasses import dataclass
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from scipy import linalg
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.mixture import GaussianMixture
from sklearn.model_selection import train_test_split
SODDALIK = ["GMM", "cVAE", "diffusion"] # soddadan murakkabga
@dataclass(frozen=True)
class Konfig:
seed: int = 0
pca: int = 20
gmm_k: int = 3
vae_z: int = 8
vae_h: int = 128
vae_qadam: int = 800
dif_T: int = 50
dif_h: int = 192
dif_qadam: int = 1000
ema: float = 0.99
p_shartsiz: float = 0.1
cfg_w: float = 0.3 # 2-qadamda validatsiyada tanlangan
bs: int = 128
lr: float = 2e-3
klf_qadam: int = 600
urug_soni: int = 3
nusxa_max: float = 0.10 # yodlash darvozasi (haqiqiyda ~0.05)
wm_a: float = 0.04 # watermark kuchi (26.9)
def malumot(k):
X, y = load_digits(return_X_y=True)
X = (X / 16).astype(np.float32)
i = np.arange(len(X))
ish, te = train_test_split(i, test_size=0.2, stratify=y, random_state=k.seed)
tr, va = train_test_split(ish, test_size=0.25, stratify=y[ish], random_state=k.seed)
return X, y, tr, va, te
# ---------------- baholash asbobi (faqat o'quv qismida o'rgatiladi) ----------------
class Klf(nn.Module):
def __init__(self):
super().__init__()
self.f = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, 64), nn.ReLU())
self.bosh = nn.Linear(64, 10)
def forward(self, x):
return self.bosh(self.f(x))
def orgat_klf(k, X, y):
torch.manual_seed(k.seed)
m = Klf()
opt = torch.optim.AdamW(m.parameters(), lr=k.lr, weight_decay=1e-3)
X, y = torch.tensor(X), torch.tensor(y)
g = torch.Generator().manual_seed(k.seed)
for _ in range(k.klf_qadam):
i = torch.randint(0, len(X), (128,), generator=g)
xb = (X[i] + 0.05 * torch.randn(X[i].shape, generator=g)).clamp(0, 1)
loss = F.cross_entropy(m(xb), y[i])
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
def frechet(a, b):
m1, m2 = a.mean(0), b.mean(0)
s1, s2 = np.cov(a, rowvar=False), np.cov(b, rowvar=False)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
cs = np.real(linalg.sqrtm(s1 @ s2))
return float(((m1 - m2) ** 2).sum() + np.trace(s1 + s2 - 2 * cs))
def prec_recall(real, gen, k=3):
"""k-NN precision/recall: namuna boshqa to'plamning k-NN sharlaridan biriga tushadimi."""
real, gen = torch.tensor(real), torch.tensor(gen)
rr = torch.cdist(real, real).kthvalue(k + 1, dim=1).values
rg = torch.cdist(gen, gen).kthvalue(k + 1, dim=1).values
d = torch.cdist(gen, real)
return (float((d <= rr[None]).any(1).float().mean()),
float((d.T <= rg[None]).any(1).float().mean()))
class Baholovchi:
"""Bitta mos yozuvli haqiqiy to'plam (val yoki test) bilan barcha metrikalar."""
def __init__(self, klf, X_oquv, X_ref, y_ref):
self.klf, self.X_oquv = klf, torch.tensor(X_oquv)
self.y_ref = y_ref
self.f_ref = self.xus(X_ref)
d = torch.cdist(torch.tensor(X_ref), self.X_oquv).min(1).values
self.d_real = float(d.mean()) # yangi haqiqiy namuna o'quvdan qancha uzoq
self.q05 = float(d.quantile(0.05))
@torch.no_grad()
def xus(self, X):
return self.klf.f(torch.as_tensor(X, dtype=torch.float32)).double().numpy()
@torch.no_grad()
def __call__(self, G, c):
G = torch.as_tensor(G, dtype=torch.float32)
togri = float((self.klf(G).argmax(1).numpy() == c).mean())
fg = self.xus(G)
p, r = prec_recall(self.f_ref, fg)
d = torch.cdist(G, self.X_oquv).min(1).values
return {"togri": togri, "FD": frechet(fg, self.f_ref), "precision": p, "recall": r,
"yodlash": float(d.mean()) / self.d_real, "nusxa": float((d < self.q05).float().mean())}
# ---------------- nomzodlar ----------------
class ShartliGMM:
"""Har sinfga PCA fazosida GaussianMixture; namuna torch.Generator bilan."""
def __init__(self, k, X, y, seed):
pca = PCA(k.pca, random_state=seed).fit(X)
Z = pca.transform(X)
self.komp = torch.tensor(pca.components_, dtype=torch.float64)
self.orta = torch.tensor(pca.mean_, dtype=torch.float64)
w, mu, L = [], [], []
for c in range(10):
with warnings.catch_warnings():
warnings.simplefilter("ignore")
gm = GaussianMixture(k.gmm_k, random_state=seed).fit(Z[y == c])
w.append(gm.weights_)
mu.append(gm.means_)
L.append(np.linalg.cholesky(gm.covariances_ + 1e-6 * np.eye(k.pca)))
self.w, self.mu, self.L = (torch.tensor(np.array(a)) for a in (w, mu, L))
def namuna(self, c, seed):
g = torch.Generator().manual_seed(seed)
c = torch.as_tensor(c)
j = torch.multinomial(self.w[c], 1, generator=g)[:, 0]
e = torch.randn(len(c), self.mu.shape[2], generator=g, dtype=torch.float64)
z = self.mu[c, j] + (self.L[c, j] @ e[:, :, None])[:, :, 0]
return (z @ self.komp + self.orta).clamp(0, 1).float().numpy()
def parametrlar(self):
return sum(t.numel() for t in (self.komp, self.orta, self.w, self.mu)) + \
10 * self.L.shape[1] * self.L.shape[2] * (self.L.shape[2] + 1) // 2
class CVAE(nn.Module):
def __init__(self, k):
super().__init__()
self.z = k.vae_z
self.enc = nn.Sequential(nn.Linear(74, k.vae_h), nn.ReLU(), nn.Linear(k.vae_h, 2 * k.vae_z))
self.dec = nn.Sequential(nn.Linear(k.vae_z + 10, k.vae_h), nn.ReLU(), nn.Linear(k.vae_h, 64))
def loss(self, x, c, g):
oh = F.one_hot(c, 10).float()
mu, logv = self.enc(torch.cat([x, oh], 1)).chunk(2, 1)
z = mu + torch.randn(mu.shape, generator=g) * (0.5 * logv).exp()
r = self.dec(torch.cat([z, oh], 1))
kl = -0.5 * (1 + logv - mu ** 2 - logv.exp()).sum(1)
return (F.binary_cross_entropy_with_logits(r, x, reduction="none").sum(1) + kl).mean()
@torch.no_grad()
def namuna(self, c, seed):
g = torch.Generator().manual_seed(seed)
c = torch.as_tensor(c)
z = torch.randn(len(c), self.z, generator=g)
return torch.sigmoid(self.dec(torch.cat([z, F.one_hot(c, 10).float()], 1))).numpy()
def jadval(T):
beta = torch.linspace(1e-4 * 1000 / T, 0.02 * 1000 / T, T)
return beta, 1 - beta, torch.cumprod(1 - beta, 0)
class Diffusion(nn.Module):
"""eps-bashoratchi MLP; sinf 10 = shartsiz (classifier-free guidance uchun)."""
def __init__(self, k):
super().__init__()
self.T, self.w = k.dif_T, k.cfg_w
self.emb = nn.Embedding(11, 32)
self.net = nn.Sequential(nn.Linear(128, k.dif_h), nn.SiLU(), nn.Linear(k.dif_h, k.dif_h),
nn.SiLU(), nn.Linear(k.dif_h, 64))
def forward(self, x, t, c):
f = torch.exp(-math.log(1000) * torch.arange(16) / 16)
a = t.float()[:, None] * f[None]
return self.net(torch.cat([x, a.sin(), a.cos(), self.emb(c)], 1))
def loss(self, x, c, g, p_shartsiz):
_, _, ab = jadval(self.T)
x = x * 2 - 1
t = torch.randint(0, self.T, (len(x),), generator=g)
e = torch.randn(x.shape, generator=g)
a = ab[t][:, None]
c = torch.where(torch.rand(len(x), generator=g) < p_shartsiz, 10, c)
return F.mse_loss(self(a.sqrt() * x + (1 - a).sqrt() * e, t, c), e)
@torch.no_grad()
def namuna(self, c, seed, w=None):
w = self.w if w is None else w
g = torch.Generator().manual_seed(seed)
beta, alfa, ab = jadval(self.T)
c = torch.as_tensor(c)
n = len(c)
x = torch.randn(n, 64, generator=g)
for t in reversed(range(self.T)):
tt = torch.full((2 * n,), t)
e = self(torch.cat([x, x]), tt, torch.cat([c, torch.full_like(c, 10)]))
e = (1 + w) * e[:n] - w * e[n:] # classifier-free guidance
x = (x - beta[t] / (1 - ab[t]).sqrt() * e) / alfa[t].sqrt()
if t > 0:
x = x + beta[t].sqrt() * torch.randn(n, 64, generator=g)
return ((x.clamp(-1, 1) + 1) / 2).numpy()
def orgat_nn(k, model, X, y, seed, qadamlar, ema=None):
torch.manual_seed(seed)
opt = torch.optim.Adam(model.parameters(), lr=k.lr)
jad = torch.optim.lr_scheduler.LambdaLR(opt, lambda s: 0.5 * (1 + math.cos(math.pi * s / qadamlar)))
X, y = torch.tensor(X), torch.tensor(y)
g = torch.Generator().manual_seed(seed)
orta = copy.deepcopy(model) if ema else None
for _ in range(qadamlar):
i = torch.randint(0, len(X), (k.bs,), generator=g)
if isinstance(model, Diffusion):
loss = model.loss(X[i], y[i], g, k.p_shartsiz)
else:
loss = model.loss(X[i], y[i], g)
opt.zero_grad()
loss.backward()
opt.step()
jad.step()
if orta is not None:
with torch.no_grad():
for po, p in zip(orta.parameters(), model.parameters()):
po.lerp_(p, 1 - ema)
return (orta if orta is not None else model).eval()
def yarat(nom, k, X, y, seed):
if nom == "GMM":
return ShartliGMM(k, X, y, seed)
torch.manual_seed(seed)
if nom == "cVAE":
return orgat_nn(k, CVAE(k), X, y, seed, k.vae_qadam)
return orgat_nn(k, Diffusion(k), X, y, seed, k.dif_qadam, ema=k.ema)
def main() -> None:
torch.set_num_threads(1)
k = Konfig()
X, y, tr, va, te = malumot(k)
klf = orgat_klf(k, X[tr], y[tr])
baho = Baholovchi(klf, X[tr], X[va], y[va]) # test TEGILMAYDI
c = y[va]
print(f"=== 1. {k.urug_soni} urug' x 3 nomzod, validatsiya ({len(va)} namuna) ===")
natija = {n: [] for n in SODDALIK}
for s in range(k.urug_soni):
for nom in SODDALIK:
m = yarat(nom, k, X[tr], y[tr], seed=s)
natija[nom].append(baho(m.namuna(c, seed=1000 + s), c))
metrikalar = ["togri", "FD", "precision", "recall", "yodlash", "nusxa"]
print(" model (o'rtacha) " + "".join(f"{m:>10}" for m in metrikalar))
for nom in SODDALIK:
print(f" {nom:<16} " + "".join(f"{np.mean([r[m] for r in natija[nom]]):>10.3f}"
for m in metrikalar))
print(" FD urug'lar bo'yicha:")
for nom in SODDALIK:
print(f" {nom:<10} " + ", ".join(f"{r['FD']:.3f}" for r in natija[nom]))
print("\n=== 2. Juftlashgan farq: asosiy metrika FD (kichik = yaxshi) ===")
fd = {n: np.array([r["FD"] for r in natija[n]]) for n in SODDALIK}
eng = min(SODDALIK, key=lambda n: fd[n].mean())
print(f" eng yaxshi (o'rtacha FD): {eng}")
yomon = {eng: False}
for nom in SODDALIK:
if nom == eng:
continue
d = fd[nom] - fd[eng]
se = d.std(ddof=1) / math.sqrt(len(d))
yomon[nom] = bool(d.mean() > 2 * se)
holat = "sezilarli yomon" if yomon[nom] else "sezilarli farq yo'q"
print(f" {nom:<10} - {eng}: {d.mean():+.3f}, SE {se:.3f} -> {holat}")
for m in ("togri", "recall"):
v = {n: np.array([r[m] for r in natija[n]]) for n in SODDALIK}
print(f" (diagnostika) {m}: " + ", ".join(f"{n} {v[n].mean():.3f}" for n in SODDALIK))
print("\n=== 3. Yodlash darvozasi va qaror ===")
otdi = {}
for nom in SODDALIK:
ns = np.array([r["nusxa"] for r in natija[nom]])
yd = np.mean([r["yodlash"] for r in natija[nom]])
otdi[nom] = bool(ns.max() <= k.nusxa_max)
print(f" {nom:<10} nusxa ulushi (max urug') {ns.max():.3f}, yodlash nisbati {yd:.3f} "
f"-> {'OK' if otdi[nom] else 'XAVF'}")
munosib = [n for n in SODDALIK if not yomon[n] and otdi[n]]
tanlov = munosib[0] if munosib else None
print(f" munosib (sezilarli yomon emas + darvozadan o'tgan): {munosib}")
print(f" QAROR: eng sodda munosib model -> {tanlov}")
if tanlov == SODDALIK[0]:
print(" murakkab nomzodlar bu byudjetda murakkabligini oqlamadi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. 3 urug' x 3 nomzod, validatsiya (360 namuna) ===
model (o'rtacha) togri FD precision recall yodlash nusxa
GMM 0.978 2.151 0.941 0.806 0.947 0.022
cVAE 1.000 6.605 1.000 0.021 0.915 0.043
diffusion 0.923 4.584 0.787 0.793 1.457 0.000
FD urug'lar bo'yicha:
GMM 1.951, 2.169, 2.331
cVAE 6.586, 6.671, 6.557
diffusion 4.452, 4.815, 4.486
=== 2. Juftlashgan farq: asosiy metrika FD (kichik = yaxshi) ===
eng yaxshi (o'rtacha FD): GMM
cVAE - GMM: +4.454, SE 0.121 -> sezilarli yomon
diffusion - GMM: +2.433, SE 0.146 -> sezilarli yomon
(diagnostika) togri: GMM 0.978, cVAE 1.000, diffusion 0.923
(diagnostika) recall: GMM 0.806, cVAE 0.021, diffusion 0.793
=== 3. Yodlash darvozasi va qaror ===
GMM nusxa ulushi (max urug') 0.031, yodlash nisbati 0.947 -> OK
cVAE nusxa ulushi (max urug') 0.053, yodlash nisbati 0.915 -> OK
diffusion nusxa ulushi (max urug') 0.000, yodlash nisbati 1.457 -> OK
munosib (sezilarli yomon emas + darvozadan o'tgan): ['GMM']
QAROR: eng sodda munosib model -> GMM
murakkab nomzodlar bu byudjetda murakkabligini oqlamadiNima ko'rsatdi: 2.4-bo'lim. Uch urug'da GMM FD 1.951–2.331, diffusion 4.452–4.815, cVAE 6.557–6.671 — urug'lar orasidagi tarqalish nomzodlar orasidagi farqdan ancha kichik. Juftlashgan farqlar: cVAE +4.454 (SE 0.121), diffusion +2.433 (SE 0.146) — ikkalasi ham 2·SE dan ancha katta. Yodlash darvozasidan uchalasi ham o'tdi (nusxa max 0.031, 0.053, 0.000). Qoida GMM ni tanladi. Diagnostika ustunlari manzarani to'ldiradi: cVAE so'ralgan sinfni doim beradi (1.000), lekin qamrovi yo'q (recall 0.021); diffusion qamrovda GMM ga yaqin (0.793 va 0.806), lekin to'g'ri sinf ulushi past (0.923) va namunalari shovqinli (yodlash nisbati 1.457).
Misol 4 — Test, paket, deterministik nazorat, watermark va hisobot
"""4-qadam: test bir marta, weights_only paket, deterministik namuna, watermark va hisobot."""
import io
import sys
import tempfile
import warnings
from dataclasses import asdict, dataclass
from pathlib import Path
import numpy as np
import sklearn
import torch
import torch.nn as nn
import torch.nn.functional as F
from PIL import Image
from scipy import linalg
from scipy.ndimage import uniform_filter
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.mixture import GaussianMixture
from sklearn.model_selection import train_test_split
TANLOV = "GMM" # 3-qadam qarori
@dataclass(frozen=True)
class Konfig:
seed: int = 0
pca: int = 20
gmm_k: int = 3
vae_z: int = 8
vae_h: int = 128
vae_qadam: int = 800
dif_T: int = 50
dif_h: int = 192
dif_qadam: int = 1000
ema: float = 0.99
p_shartsiz: float = 0.1
cfg_w: float = 0.3 # 2-qadamda validatsiyada tanlangan
bs: int = 128
lr: float = 2e-3
klf_qadam: int = 600
urug_soni: int = 3
nusxa_max: float = 0.10 # yodlash darvozasi (haqiqiyda ~0.05)
wm_a: float = 0.04 # watermark kuchi (26.9)
def malumot(k):
X, y = load_digits(return_X_y=True)
X = (X / 16).astype(np.float32)
i = np.arange(len(X))
ish, te = train_test_split(i, test_size=0.2, stratify=y, random_state=k.seed)
tr, va = train_test_split(ish, test_size=0.25, stratify=y[ish], random_state=k.seed)
return X, y, tr, va, te
# ---------------- baholash asbobi (faqat o'quv qismida o'rgatiladi) ----------------
class Klf(nn.Module):
def __init__(self):
super().__init__()
self.f = nn.Sequential(nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, 64), nn.ReLU())
self.bosh = nn.Linear(64, 10)
def forward(self, x):
return self.bosh(self.f(x))
def orgat_klf(k, X, y):
torch.manual_seed(k.seed)
m = Klf()
opt = torch.optim.AdamW(m.parameters(), lr=k.lr, weight_decay=1e-3)
X, y = torch.tensor(X), torch.tensor(y)
g = torch.Generator().manual_seed(k.seed)
for _ in range(k.klf_qadam):
i = torch.randint(0, len(X), (128,), generator=g)
xb = (X[i] + 0.05 * torch.randn(X[i].shape, generator=g)).clamp(0, 1)
loss = F.cross_entropy(m(xb), y[i])
opt.zero_grad()
loss.backward()
opt.step()
return m.eval()
def frechet(a, b):
m1, m2 = a.mean(0), b.mean(0)
s1, s2 = np.cov(a, rowvar=False), np.cov(b, rowvar=False)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
cs = np.real(linalg.sqrtm(s1 @ s2))
return float(((m1 - m2) ** 2).sum() + np.trace(s1 + s2 - 2 * cs))
def prec_recall(real, gen, k=3):
"""k-NN precision/recall: namuna boshqa to'plamning k-NN sharlaridan biriga tushadimi."""
real, gen = torch.tensor(real), torch.tensor(gen)
rr = torch.cdist(real, real).kthvalue(k + 1, dim=1).values
rg = torch.cdist(gen, gen).kthvalue(k + 1, dim=1).values
d = torch.cdist(gen, real)
return (float((d <= rr[None]).any(1).float().mean()),
float((d.T <= rg[None]).any(1).float().mean()))
class Baholovchi:
"""Bitta mos yozuvli haqiqiy to'plam (val yoki test) bilan barcha metrikalar."""
def __init__(self, klf, X_oquv, X_ref, y_ref):
self.klf, self.X_oquv = klf, torch.tensor(X_oquv)
self.y_ref = y_ref
self.f_ref = self.xus(X_ref)
d = torch.cdist(torch.tensor(X_ref), self.X_oquv).min(1).values
self.d_real = float(d.mean()) # yangi haqiqiy namuna o'quvdan qancha uzoq
self.q05 = float(d.quantile(0.05))
@torch.no_grad()
def xus(self, X):
return self.klf.f(torch.as_tensor(X, dtype=torch.float32)).double().numpy()
@torch.no_grad()
def __call__(self, G, c):
G = torch.as_tensor(G, dtype=torch.float32)
togri = float((self.klf(G).argmax(1).numpy() == c).mean())
fg = self.xus(G)
p, r = prec_recall(self.f_ref, fg)
d = torch.cdist(G, self.X_oquv).min(1).values
return {"togri": togri, "FD": frechet(fg, self.f_ref), "precision": p, "recall": r,
"yodlash": float(d.mean()) / self.d_real, "nusxa": float((d < self.q05).float().mean())}
# ---------------- nomzodlar ----------------
class ShartliGMM:
"""Har sinfga PCA fazosida GaussianMixture; namuna torch.Generator bilan."""
def __init__(self, k, X, y, seed):
pca = PCA(k.pca, random_state=seed).fit(X)
Z = pca.transform(X)
self.komp = torch.tensor(pca.components_, dtype=torch.float64)
self.orta = torch.tensor(pca.mean_, dtype=torch.float64)
w, mu, L = [], [], []
for c in range(10):
with warnings.catch_warnings():
warnings.simplefilter("ignore")
gm = GaussianMixture(k.gmm_k, random_state=seed).fit(Z[y == c])
w.append(gm.weights_)
mu.append(gm.means_)
L.append(np.linalg.cholesky(gm.covariances_ + 1e-6 * np.eye(k.pca)))
self.w, self.mu, self.L = (torch.tensor(np.array(a)) for a in (w, mu, L))
def namuna(self, c, seed):
g = torch.Generator().manual_seed(seed)
c = torch.as_tensor(c)
j = torch.multinomial(self.w[c], 1, generator=g)[:, 0]
e = torch.randn(len(c), self.mu.shape[2], generator=g, dtype=torch.float64)
z = self.mu[c, j] + (self.L[c, j] @ e[:, :, None])[:, :, 0]
return (z @ self.komp + self.orta).clamp(0, 1).float().numpy()
def parametrlar(self):
return sum(t.numel() for t in (self.komp, self.orta, self.w, self.mu)) + \
10 * self.L.shape[1] * self.L.shape[2] * (self.L.shape[2] + 1) // 2
FORMAT = 1
KALIT = 2026 # watermark kaliti - SIR: paketga yozilmaydi (sirlar omborida)
CHEGARA = 4.0
class YuklanganGMM(ShartliGMM):
"""Paketdagi tenzorlardan tiklanadi - sklearn obyekti kerak emas."""
def __init__(self, holat):
self.komp, self.orta = holat["komp"], holat["orta"]
self.w, self.mu, self.L = holat["w"], holat["mu"], holat["L"]
def naqsh(kalit):
g = torch.Generator().manual_seed(kalit)
return (torch.randint(0, 2, (16, 16), generator=g) * 2 - 1).numpy().astype(float)
def chiqish(x8, kalit=None, a=0.0):
"""Xizmat formati: 8x8 -> 16x16; kalit berilsa ko'rinmas watermark 26.9-bob."""
x = np.clip(uniform_filter(np.kron(x8.reshape(-1, 8, 8), np.ones((1, 2, 2))),
size=(1, 3, 3)), 0, 1)
return x if kalit is None else np.clip(x + a * naqsh(kalit), 0, 1)
def z_ball(x, kalit):
def yuq(v):
return v - uniform_filter(v, size=(1, 3, 3), mode="nearest")
r = yuq(x).reshape(len(x), -1)
w = yuq(naqsh(kalit)[None]).reshape(-1)
r, w = r - r.mean(1, keepdims=True), w - w.mean()
return np.sqrt(r.shape[1]) * (r @ w) / (np.linalg.norm(r, axis=1) * np.linalg.norm(w) + 1e-12)
def jpeg(x, sifat):
chiq = []
for rasm in x:
buf = io.BytesIO()
Image.fromarray((rasm * 255).round().astype(np.uint8)).save(buf, "JPEG", quality=sifat)
chiq.append(np.asarray(Image.open(io.BytesIO(buf.getvalue())), dtype=float) / 255)
return np.array(chiq)
def kichrayt(x16):
return x16.reshape(-1, 8, 2, 8, 2).mean((2, 4)).reshape(-1, 64).astype(np.float32)
def main() -> None:
torch.set_num_threads(1)
k = Konfig()
X, y, tr, va, te = malumot(k)
ish = np.r_[tr, va]
klf = orgat_klf(k, X[tr], y[tr]) # baholash asbobi - o'sha, faqat o'quvda
print(f"=== 1. Yakuniy model (3-qadam qarori: {TANLOV}) ish to'plamida ===")
model = ShartliGMM(k, X[ish], y[ish], seed=k.seed)
print(f" o'quv + val = {len(ish)} rasm; PCA {k.pca}, har sinfga {k.gmm_k} komponent; "
f"{model.parametrlar()} parametr")
print("\n=== 2. Testni BIR MARTA ochamiz ===")
baho = Baholovchi(klf, X[ish], X[te], y[te])
c = y[te]
metrikalar = ["togri", "FD", "precision", "recall", "yodlash", "nusxa"]
print(" manba " + "".join(f"{m:>10}" for m in metrikalar))
rng = np.random.default_rng(k.seed)
nus = np.array([rng.choice(ish[y[ish] == s]) for s in c])
r0 = baho(X[nus], c)
print(" nusxachi (pastki FD) " + "".join(f"{r0[m]:>10.3f}" for m in metrikalar))
test = [baho(model.namuna(c, seed=s), c) for s in (1, 2, 3)]
for i, r in enumerate(test, 1):
print(f" GMM, namuna urug'i {i} " + "".join(f"{r[m]:>10.3f}" for m in metrikalar))
tfd = np.array([r["FD"] for r in test])
tn = max(r["nusxa"] for r in test)
print(f" test FD {tfd.mean():.3f} (+- {tfd.std(ddof=1):.3f}); nusxa max {tn:.3f} -> "
f"{'darvozadan otdi' if tn <= k.nusxa_max else 'DARVOZA BUZILDI'}".replace("otdi", "o'tdi"))
with tempfile.TemporaryDirectory() as papka:
print("\n=== 3. Paket: torch.save + torch.load(weights_only=True) ===")
nazorat_c = torch.arange(10).repeat(2)
paket = {
"format": FORMAT,
"konfig": asdict(k),
"tanlov": TANLOV,
"holat": {"komp": model.komp, "orta": model.orta, "w": model.w,
"mu": model.mu, "L": model.L},
"metrika": {"test_FD": round(float(tfd.mean()), 4),
"test_togri": round(float(np.mean([r["togri"] for r in test])), 4),
"nusxa_max": round(float(tn), 4)},
"watermark": {"usul": "16x16, +-a naqsh, z-test", "a": k.wm_a, "kalit_id": "wm-01"},
"versiyalar": {"torch": str(torch.__version__), "sklearn": sklearn.__version__,
"python": sys.version.split()[0]},
"nazorat": {"c": nazorat_c, "seed": 7,
"namuna": torch.tensor(model.namuna(nazorat_c, seed=7))},
}
yol = Path(papka) / "raqam_generatori.pt"
torch.save(paket, yol)
p = torch.load(yol, weights_only=True)
print(f" kalitlar: {sorted(p)}")
print(f" holat: {len(p['holat'])} tenzor, sklearn obyekti yo'q; kalit paketda: "
f"{'HA' if 'kalit' in p['watermark'] else 'yoq'}".replace("yoq", "yo'q"))
yuk = YuklanganGMM(p["holat"])
n = p["nazorat"]
a1 = torch.tensor(yuk.namuna(n["c"], seed=n["seed"]))
a2 = torch.tensor(yuk.namuna(n["c"], seed=n["seed"]))
b = torch.tensor(yuk.namuna(n["c"], seed=n["seed"] + 1))
print(f" nazorat (saqlangan namuna bilan aynan): {'OK' if torch.equal(a1, n['namuna']) else 'XATO'}")
print(f" bir xil urug' ikki marta: {torch.equal(a1, a2)}; boshqa urug': "
f"{'farqli' if not torch.equal(a1, b) else 'BIR XIL'}")
print(f"\n=== 4. Chiqishga watermark (a = {k.wm_a}) va uni aniqlash ===")
G8 = yuk.namuna(c, seed=11)
belgili = chiqish(G8, KALIT, k.wm_a)
toza = chiqish(yuk.namuna(c, seed=12))
haqiqiy = chiqish(X[te])
qatorlar = [("belgili chiqish", belgili), ("belgili + JPEG 70", jpeg(belgili, 70)),
("belgisiz chiqish", toza), ("haqiqiy test", haqiqiy)]
for nom, h in qatorlar:
z = z_ball(h, KALIT)
print(f" {nom:<18} 'bor' ulushi {np.mean(z > CHEGARA):>6.1%} z o'rtacha {z.mean():>6.2f}")
with torch.no_grad():
t0 = (klf(torch.tensor(kichrayt(chiqish(G8)))).argmax(1).numpy() == c).mean()
t1 = (klf(torch.tensor(kichrayt(belgili))).argmax(1).numpy() == c).mean()
print(f" foydalilik: to'g'ri sinf ulushi watermarksiz {t0:.3f}, watermark bilan {t1:.3f}")
print("\n=== 5. Yakuniy hisobot (model kartasi qisqacha) ===")
print(" VAZIFA: shartli raqam generatori (8x8, sinf 0-9)")
print(" METRIKA: asosiy - FD (o'z klassifikator xususiyatlarida); darvoza - nusxa ulushi")
print(f" QAROR: 3 urug', juftlashgan FD -> {TANLOV} (eng sodda, qolganlar sezilarli yomon)")
print(f" TEST: FD {tfd.mean():.3f}, to'g'ri sinf {np.mean([r['togri'] for r in test]):.3f}, "
f"recall {np.mean([r['recall'] for r in test]):.3f}; nusxachi FD {r0['FD']:.3f}")
print(f" MAXFIYLIK: nusxa ulushi {tn:.3f} (haqiqiy yangi rasmda 0.05)")
print(f" PAKET: format {FORMAT}, weights_only=True, deterministik nazorat OK; kalit alohida")
print(" CHEKLOVLAR: 8x8 raqamlar; a'zolik hujumi tekshirilmagan; watermark xiralash")
print(" va siljitishga chidamsiz 26.9-bob; FD kichik n da shovqinli")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Yakuniy model (3-qadam qarori: GMM) ish to'plamida ===
o'quv + val = 1437 rasm; PCA 20, har sinfga 3 komponent; 8274 parametr
=== 2. Testni BIR MARTA ochamiz ===
manba togri FD precision recall yodlash nusxa
nusxachi (pastki FD) 0.989 2.176 0.903 0.872 0.000 1.000
GMM, namuna urug'i 1 0.981 2.480 0.953 0.831 0.954 0.036
GMM, namuna urug'i 2 0.983 2.237 0.947 0.803 0.949 0.039
GMM, namuna urug'i 3 0.989 2.368 0.964 0.792 0.945 0.036
test FD 2.362 (+- 0.122); nusxa max 0.039 -> darvozadan o'tdi
=== 3. Paket: torch.save + torch.load(weights_only=True) ===
kalitlar: ['format', 'holat', 'konfig', 'metrika', 'nazorat', 'tanlov', 'versiyalar', 'watermark']
holat: 5 tenzor, sklearn obyekti yo'q; kalit paketda: yo'q
nazorat (saqlangan namuna bilan aynan): OK
bir xil urug' ikki marta: True; boshqa urug': farqli
=== 4. Chiqishga watermark (a = 0.04) va uni aniqlash ===
belgili chiqish 'bor' ulushi 100.0% z o'rtacha 9.98
belgili + JPEG 70 'bor' ulushi 99.7% z o'rtacha 5.79
belgisiz chiqish 'bor' ulushi 0.0% z o'rtacha 1.02
haqiqiy test 'bor' ulushi 0.0% z o'rtacha 0.92
foydalilik: to'g'ri sinf ulushi watermarksiz 0.967, watermark bilan 0.969
=== 5. Yakuniy hisobot (model kartasi qisqacha) ===
VAZIFA: shartli raqam generatori (8x8, sinf 0-9)
METRIKA: asosiy - FD (o'z klassifikator xususiyatlarida); darvoza - nusxa ulushi
QAROR: 3 urug', juftlashgan FD -> GMM (eng sodda, qolganlar sezilarli yomon)
TEST: FD 2.362, to'g'ri sinf 0.984, recall 0.808; nusxachi FD 2.176
MAXFIYLIK: nusxa ulushi 0.039 (haqiqiy yangi rasmda 0.05)
PAKET: format 1, weights_only=True, deterministik nazorat OK; kalit alohida
CHEKLOVLAR: 8x8 raqamlar; a'zolik hujumi tekshirilmagan; watermark xiralash
va siljitishga chidamsiz 26.9-bob; FD kichik n da shovqinliNima ko'rsatdi: 2.5, 2.6-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Eng zamonaviy model — eng yaxshi" | Bu vazifa va byudjetda GMM FD 2.151, diffusion 4.584 — sezilarli farq |
| "FD eng past — eng yaxshi generator" | Nusxachi FD 1.434 bilan eng yaxshi; faqat nusxa darvozasi ushlaydi |
| "So'ralgan sinfni 100% beradi — model yaxshi" | Sinf o'rtachasi va cVAE 1.000, lekin recall 0.000 va 0.021 |
| "FD — mutlaq sifat bahosi" | n ga bog'liq: 6.474 (n=90) va 1.434 (n=360) — faqat bir xil n da solishtiriladi |
| "Guidance qancha kuchli — shuncha yaxshi" | w = 1.0 da FD 13.950, recall 0.653 |
| "Baholash klassifikatori — shunchaki vosita" | U ham faqat o'quvda o'rgatiladi, aks holda asbob sizadi |
| "Generativ modelni pickle bilan saqlash yetarli" | Tenzorlar + weights_only=True + urug'li nazorat |
| "Watermark rasmni buzadi" | To'g'ri sinf ulushi 0.967 → 0.969 |
6. Keng tarqalgan xatolar va yechimlari
1. Asbob butun ma'lumotda
klf = orgat_klf(k, X, y) # ⚠️ val/test ham ko'rilgan
klf = orgat_klf(k, X[tr], y[tr]) # ✅ faqat o'quv2. Turli n bilan FD
fd_gmm = baho(gmm.namuna(c_1000, 0), c_1000)["FD"]; fd_dif = baho(dif.namuna(c_200, 0), c_200)["FD"] # ⚠️
fd = {n: baho(m.namuna(c, seed=1000), c)["FD"] for n, m in modellar.items()} # ✅ bir xil c3. Darvozasiz tanlov
tanlov = min(SODDALIK, key=lambda n: fd[n].mean()) # ⚠️ nusxachi ham o'tadi
tanlov = next(n for n in SODDALIK if not yomon[n] and otdi[n]) # ✅ + nusxa darvozasi4. Guidance ni testda tanlash
w = min(ws, key=lambda w: baho_test(dif.namuna(y[te], 0, w), y[te])["FD"]) # ⚠️
w = min(ws, key=lambda w: baho(dif.namuna(y[va], 1000, w), y[va])["FD"]) # ✅ val5. Global urug' bilan namuna
z = torch.randn(n, 20) # ⚠️ nazorat takrorlanmaydi
z = torch.randn(n, 20, generator=torch.Generator().manual_seed(seed)) # ✅6. sklearn obyektini saqlash
torch.save({"gmm": gaussian_mixture}, yol); torch.load(yol, weights_only=False) # ⚠️ pickle
torch.save({"holat": {"mu": mu, "L": L, "w": w, ...}}, yol) # ✅ tenzorlar7. Watermark kaliti paketda
paket["watermark"] = {"kalit": 2026, "a": 0.04} # ⚠️ sir tarqaladi
paket["watermark"] = {"kalit_id": "wm-01", "a": 0.04} # ✅ kalit - sirlar omborida7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 21.12, 22.14, 23.14, 24.12, 25.14-darslar (o'tilgan): Loyiha skeleti — konfig, test qulfi, juftlashgan qaror,
weights_onlypaket - 16-qism (o'tilgan): PCA va Gauss aralashmasi — bu yerda ular eng kuchli bazaviy bo'ldi
- 26.1-26.8-darslar (o'tilgan): Butun qism — VAE, GAN, diffusion, guidance, baholash metrikalari, multimodal modellar
- 26.9-dars (o'tilgan): Yodlash tekshiruvi va watermark — bu yerda loyiha darvozasi va mahsulot qismi
- MLOps va deploy qismida: paketni xizmatga aylantirish, sampling urug'ini so'rov ID sidan olish, watermark kalitini sirlar omborida saqlash va chiqishlarni kuzatish
8. Eng yaxshi amaliyotlar
Baholash asbobini faqat o'quvda o'rgating va ma'lum "generatorlar" bilan kalibrlang.
Asosiy metrika va darvozani natijani ko'rishdan oldin yozing.
FD ni faqat bir xil n va bir xil mos yozuv to'plami bilan solishtiring.
Nomzodlarni soddalik tartibida yozing; oddiy statistik bazaviy majburiy.
Giperparametrlarni (w, qadamlar) validatsiyada tanlang; narxni sifat yonida yozing.
Qarorni bir necha urug'dagi juftlashgan farq, yodlash darvozasi va soddalik qoidasi bilan qabul qiling; byudjetni qarorga yozing.
Paketda faqat tenzorlar; urug'li nazorat namunasi bilan determinizmni tekshiring.
Chiqishni watermark bilan belgilang, kalitni alohida saqlang va foydalilik hamda FPR ni tekshiring.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # nega baholash klassifikatori faqat o'quv qismida o'rgatiladi?
2. # nusxachi FD bo'yicha qanday natija beradi va uni nima ushlaydi?
3. # sinf o'rtachasi generatori qaysi metrikada 1.0, qaysisida ~0?
4. # n = 90 va n = 360 dagi FD larni solishtirish mumkinmi?
5. # guidance w oshsa to'g'ri sinf ulushi va recall qanday o'zgaradi?
6. # diffusion bitta namuna uchun necha marta tarmoq chaqiradi (T = 50, CFG)?
7. # "sezilarli yomon" mezoni (3 urug')?
8. # GMM va diffusion farqi 2*SE ichida bo'lsa - qaysi tanlanadi?
9. # nusxa ulushi haqiqiy yangi rasmlarda nechaga teng va nega?
10. # nega GMM paketda sklearn obyekti sifatida emas, tenzorlar sifatida saqlanadi?
11. # deterministik nazorat nimani tekshiradi?
12. # watermark kaliti qayerda saqlanadi?Javoblar
- Asbob ham ma'lumotdan o'rganadi; u val/test ni ko'rsa, o'lchov o'sha to'plamlarga moslashadi (sizish)
- Eng yaxshi FD lardan birini (
1.434) — uni faqat nusxa ulushi (1.000) ushlaydi - To'g'ri sinf ulushi
1.000, recall0.000 - Yo'q — FD kichik n da yuqoriga siljigan (
6.474va1.434) - To'g'ri sinf ulushi oshadi (
0.811→1.000), recall tushadi (0.828→0.653) 2 * 50 = 100mean(d) > 2 * std(d) / sqrt(3)- GMM — soddarog'i
0.05— chegara q05 aynan haqiqiy yangi rasmlarning 5-foizligiweights_only=Truefaqat tenzor va oddiy turlarni yuklaydi; pickle ixtiyoriy kod bajarishi mumkin- Yuklangan model aynan saqlangan namunani qaytarishini: model o'zgarmagan va sampling urug' bilan deterministik
- Paketdan tashqarida — sirlar omborida; paketda faqat
kalit_id
Vazifa 2: Xatolarni tuzating
1. klf = orgat_klf(k, X[np.r_[tr, va]], y[np.r_[tr, va]])
baho = Baholovchi(klf, X[tr], X[va], y[va])
2. for w in (0.0, 0.3, 0.5, 1.0):
print(w, Baholovchi(klf, X[tr], X[te], y[te])(dif.namuna(y[te], 0, w), y[te])["FD"])
3. eng = min(SODDALIK, key=lambda n: fd[n].mean())
print("tanlov:", eng)
4. torch.save({"model": model}, yol)
model = torch.load(yol, weights_only=False)
5. paket["nazorat"] = {"namuna": torch.tensor(model.namuna(c, seed=7))}Javoblar
1. klf = orgat_klf(k, X[tr], y[tr]) # asbob faqat o'quvda
baho = Baholovchi(klf, X[tr], X[va], y[va])
2. for w in (0.0, 0.3, 0.5, 1.0): # tanlov - validatsiyada
print(w, baho(dif.namuna(y[va], 1000, w), y[va])["FD"])
3. munosib = [n for n in SODDALIK if not yomon[n] and otdi[n]]
print("tanlov:", munosib[0]) # eng sodda munosib
4. torch.save({"holat": {"komp": m.komp, "orta": m.orta, "w": m.w, "mu": m.mu, "L": m.L}}, yol)
m = YuklanganGMM(torch.load(yol, weights_only=True)["holat"])
5. paket["nazorat"] = {"c": c, "seed": 7, # shart va urug' ham kerak
"namuna": torch.tensor(model.namuna(c, seed=7))}Vazifa 3: Asbob
Modellang:
- Klassifikatorni boshqa arxitektura bilan (masalan, kichik CNN) — nomzodlar tartibi o'zgaradimi?
- FD ni 1000 ta namuna bilan — mos yozuv sifatida o'quvning bir qismini ishlatish mumkinmi?
- Nusxa darvozasi chegarasini 0.05, 0.10, 0.20 qiling — qaysi etalon generatorlar o'tadi?
- Asbobga a'zolik hujumini qo'shing (GMM da
score_samplesbilan)
Yechim yo'nalishi
Asbobni almashtirish — o'lchov "o'lchagichni" almashtirish; tartib saqlansa, xulosa ishonchliroq. Mos yozuv sifatida o'quvdan foydalanish mumkin emas — nusxachi va yodlagan modellar foyda ko'radi. GMM uchun a'zolik hujumi: har sinf GMM ining score_samples qiymatini o'quv va val rasmlarida solishtirib AUC hisoblang (26.9, 1-misol usuli).
Vazifa 4: Byudjet
Modellang:
dif_qadam= 1000, 3000, 6000 — diffusion FD GMM ga yetib oladimi?dif_T= 25, 50, 100 — sifat va FLOP murosasi- cVAE ga
beta(KL og'irligi) 0.5 va 2 — recall o'zgaradimi? - GMM ga
gmm_k= 1, 3, 10 vapca= 10, 20, 40
Yechim yo'nalishi
dataclasses.replace(k, dif_qadam=q) bilan Konfig ni o'zgartiring va 3-misolni qayta ishga tushiring (vaqt ko'payadi — urug'larni ketma-ket ishga tushiring). Natija qanday bo'lsa, shunday yozing: agar ko'p qadamda diffusion GMM dan sezilarli yomon bo'lmay qolsa, qoida baribir GMM ni tanlaydi (soddaroq); diffusion faqat sezilarli yaxshi bo'lsagina tanlanadi. gmm_k = 10 da har sinfda ~108 ta rasm uchun 10 ta to'liq kovariatsiya — yodlash xavfi oshadi, nusxa darvozasiga qarang.
Vazifa 5: Taqqoslash
Modellang:
- 5 urug' — SE qanchaga kichrayadi?
- Asosiy metrika sifatida recall — qaror o'zgaradimi?
- Sinf bo'yicha FD (har raqam uchun alohida) — qaysi raqamda diffusion yaxshiroq?
- GAN 26.3-bob ni to'rtinchi nomzod sifatida qo'shing
Yechim yo'nalishi
Asosiy metrikani natijadan keyin almashtirish — "p-hacking" ning bir turi; buni faqat alohida tahlil sifatida, oldingi qarorni o'zgartirmasdan qiling. Sinf bo'yicha FD kichik n (36) da juda shovqinli — sinf bo'yicha to'g'ri sinf ulushi va recall ishonchliroq. GAN ni soddalik tartibida cVAE va diffusion orasiga qo'ying.
Vazifa 6: Topshirish
Modellang:
Generatorxizmat sinfi:generatsiya(sinf, urug')→ watermarkli 16x16 PNG baytlari- Paketga model kartasi maydonini qo'shing (maqsad, cheklovlar, metrikalar)
- Watermark aniqlovchi alohida funksiya — kalitni muhit o'zgaruvchisidan oladi
- So'rov ID sidan urug' (masalan,
hashlib.sha256) — bir xil so'rov → bir xil rasm
Yechim yo'nalishi
PIL.Image.fromarray(...).save(buf, "PNG") — PNG siqilishsiz, watermark to'liq saqlanadi (JPEG 70 da ham 99.7% edi). Urug' uchun int(hashlib.sha256(sorov_id.encode()).hexdigest()[:8], 16). Kalitni os.environ dan oling va paketga yozmang; aniqlovchi faqat kalit_id bo'yicha kerakli kalitni topadi.
Vazifa 7: O'ylash
Mahsulot rahbari aytdi: "GMM — 1990-yillarning texnologiyasi. Investorlar 'diffusion' so'zini eshitishni xohlaydi. Diffusion ni tanlaymiz, qolgani ahamiyatsiz." Siz nima deysiz?
Javob
Qisqa javob: texnologiya tanlovi — o'lchangan natija va narxga asoslangan muhandislik qarori; bu loyihada ikkalasi ham GMM tomonida. Lekin rahbarning xavotiri ham tushunarli — uni to'g'ri savolga aylantirish kerak.
1. Natija. 3-misolda uch urug'da diffusion FD 4.584, GMM 2.151, juftlashgan farq +2.433 (SE 0.146) — sezilarli. Diffusion so'ralgan sinfni kamroq beradi (0.923 va 0.978) va namunalari shovqinli. Testda GMM FD 2.362 — "mukammal generator" chegarasi (2.176) ga yaqin.
2. Narx. Diffusion har rasmga 100 tarmoq chaqiruvi va ~14.7 MFLOP, GMM ~3.4 kFLOP — taxminan 4400 marta kam. Serverda bu to'g'ridan-to'g'ri pul va kechikish.
3. Qaror chegarasi. Natija "diffusion yomon" emas, balki "8x8 raqamlar va shu byudjetda murakkablik o'zini oqlamadi". Agar mahsulot kattaroq rasmlarga, rangli rasmlarga yoki matn bilan boshqaruvga o'tsa — xuddi shu skelet bilan qayta o'lchaymiz, va u yerda diffusion yutishi mumkin (26.5-26.8).
4. Investorlar uchun. Ularga texnologiya nomi emas, jarayon muhim: biz bir nechta zamonaviy yondashuvni halol solishtirdik, yodlashni tekshirdik, chiqishlarni watermark bilan belgiladik. Bu ishonchli jamoa belgisi.
Tavsiya:
# 1. Hozir: GMM ni ishga tushirish (qaror, test, paket tayyor)
# 2. Diffusion byudjet egri chizig'i: dif_qadam 1000 -> 6000 (Vazifa 4)
# 3. Mahsulot talablari o'zgarsa (16x16+, rang, matn) - xuddi shu skelet bilan qayta
# 4. Model kartasida: "diffusion sinaldi, bu vazifada sezilarli yomon, narx 4400x"Rahbarga javob: "Diffusion ni sinab ko'rdik va o'lchadik: bu vazifada u sezilarli yomonroq va minglab marta qimmatroq. GMM ni ishga tushiramiz; mahsulot murakkablashsa, tayyor skelet bilan diffusion ni qayta sinaymiz — natija o'zgarsa, almashtiramiz."
Nimani mustahkamlaydi: 2.2, 2.4, 2.5, 2.6-bo'limlar.
Xulosa
Bu darsda to'liq generativ loyiha qurdik: ma'lumot va o'lchov asbobidan watermark qo'shilgan, tekshirilgan paketgacha.
Eng muhim uch fikr:
O'lchov asbobi — generativ loyihaning markazi. 1-misolda o'quvda o'rgatilgan klassifikator (val aniqligi
0.972) asosida FD, precision/recall, yodlash va nusxa ulushini qurdik va ularni ma'lum "generatorlar" da kalibrladik: nusxachi FD bo'yicha eng yaxshi (1.434) — uni faqat nusxa darvozasi (1.000) ushlaydi; sinf o'rtachasi100%to'g'ri taniladi, lekin recall0.000; FD n ga kuchli bog'liq (6.474→1.434). Asosiy metrika (FD) va darvoza (nusxa ≤ 0.10) natijalardan oldin belgilandi.Eng sodda model yutdi — va buni juftlashgan taqqoslash ko'rsatdi. 3-misolda uch urug'da GMM FD
2.151, diffusion (CFGw = 0.3)4.584, cVAE6.605; farqlar+2.433(SE 0.146) va+4.454(SE 0.121) — sezilarli. Uchala nomzod ham yodlash darvozasidan o'tdi, qoida GMM ni tanladi. U diffusion ga nisbatan har namunada taxminan 4400 marta kam FLOP sarflaydi. Halol chegara: bu natija 8x8 ma'lumot va kichik CPU byudjeti uchun.Test bir marta ochildi, paket va watermark tekshirildi. Testda GMM FD
2.362(nusxachi chegarasi2.176), to'g'ri sinf0.984, nusxa ulushi0.039(haqiqiyda0.05). Paket faqat tenzorlardan iborat,weights_only=Truebilan yuklandi, urug'li nazorat aynan mos keldi, watermark kaliti paketga yozilmadi. Watermark chiqishlarda100%aniqlandi (JPEG 70 dan keyin99.7%), belgisiz va haqiqiy rasmlarda yolg'on musbat0.0%, foydalilik saqlandi (0.967→0.969).
Bu bilan 26-qism — Generativ AI yakunlandi. Endi bizda generativ modellashtirishning to'liq xaritasi bor: taqsimotni o'rganish g'oyasidan VAE ning yashirin fazosi, GAN ning raqobati va uning muammolari, diffusion ning shovqindan tiklash jarayoni, sampling va guidance tugmalarigacha; generativ modelni raqam bilan baholashdan (FD, precision/recall, yodlash) matn-rasm modellari va etika-xavfsizlik (yodlash, tarafkashlik, watermark, detektorlar) gacha — va nihoyat bularning hammasini oddiy bazaviy bilan halol solishtiradigan loyihagacha. Bu va oldingi qismlardagi loyihalarning barchasi bitta joyda to'xtadi: weights_only=True bilan yuklanadigan paket va hisobot. Keyingi qism — MLOps va deploy: paketni haqiqiy xizmatga aylantirish, versiyalash va tajribalarni kuzatish, modelni API orqali taqdim etish, ishlab chiqarishda sifat va ma'lumot siljishini kuzatish — shu jumladan bu darsdagi sampling urug'lari, watermark kalitlari va model kartasini boshqarish.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!