Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Tarmoq kerakmi
- 2.2. Loyiha tartibi
- 2.3. Tarmoq uchun tayyorlash
- 2.4. Tashxis ro'yxati
- 2.5. Taqqoslash
- 2.6. Saqlash va topshirish
- 2.7. Tuzoqlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Ma'lumot, dizayn va bazaviy modellar
- Misol 2 — Tarmoqni qurish va tashxis
- Misol 3 — Juftlashgan taqqoslash
- Misol 4 — Yopiq test, paket 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
20.12-dars: Amaliyot — to'liq loyiha
20-QISM — NEYRON TARMOQLAR · 12-dars
1. Kirish va motivatsiya
20-qismda neyronning ichidan boshlab, to'liq o'rgatish siklgacha bordik. Endi hammasini bitta loyihada ishlatamiz.
Bu amaliyotning maqsadi — tarmoq qurish emas. Maqsad — tarmoq kerakmi yoki yo'qmi degan savolga javob berish va javobni raqam bilan asoslash. Tabular ma'lumotda bu savol jiddiy: gradient boosting ko'pincha neyron tarmoqdan yaxshiroq ishlaydi, tezroq o'rgatiladi va sozlashga kamroq vaqt oladi.
Shuning uchun loyihani 18-qismdagi tartib bilan olib boramiz: validatsiya dizayni, bazaviy modellar, keyin tarmoq, keyin taqqoslash va faqat oxirida yopiq testni ochish.
Va yana bir narsa: tarmoqning tashxisi. Loss egri chizig'i, qatlamlar statistikasi, o'lgan neyronlar, gradient normalari — bularning hammasini bir joyda ko'rsatamiz, chunki amalda ular alohida emas, birga o'qiladi.
Real vaziyat. Jamoa tabular vazifada ikki hafta tarmoq sozladi va AUC 0.842 ga chiqdi. Keyin HistGradientBoosting ni sukut parametrlari bilan ishga tushirdi — 0.851, 12 soniyada. Tarmoq loyihadan chiqarildi.
Bu darsda to'liq neyron tarmoq loyihasini quramiz.
Bu darsda:
- Tarmoq kerakmi degan savol
- To'liq loyiha tartibi
- Tashxis
- Taqqoslash
- Saqlash va topshirish
- Tuzoqlar
- Amaliy: yakuniy loyiha
ℹ Misollar real torch/sklearn bilan (Python 3.14, torch 2.14 CPU).
2. Nazariya — chuqur tushuntirish
2.1. Tarmoq kerakmi
TARMOQ USTUN BO'LADIGAN HOLATLAR:
rasm, audio, matn (tuzilmali signal)
juda katta ma'lumot (> 1M namuna)
murakkab nochiziqli o'zaro ta'sirlar
tayyor modellardan transfer learning
ko'p chiqishli / ko'p vazifali o'rgatish
embedding kerak bo'lgan vazifalar
GRADIENT BOOSTING USTUN BO'LADIGAN HOLATLAR:
TABULAR ma'lumot (jadval)
aralash turlar (son + kategoriya)
o'rta hajm (1k - 1M)
yo'qolgan qiymatlar ko'p
sozlashga vaqt kam
BU TAJRIBA EMAS, ADABIYOTDA O'LCHANGAN:
Grinsztajn va b. (2022): tabular ma'lumotda daraxtlar ustun
Shwartz-Ziv & Armon (2022): xuddi shunday xulosa
⭐ HAR DOIM bazaviy sifatida boosting ni qo'yingTabular ma'lumotda tarmoq avtomatik tanlov emas — uni isbotlash kerak.
2.2. Loyiha tartibi
1. MA'LUMOT: o'qish, nuqsonlar, guruh/vaqt tuzilmasi
2. DIZAYN: CV strategiyasi, test to'plamini QULFLASH
3. METRIKA: vazifadan kelib chiqqan bitta asosiy metrika
4. BAZAVIY: chiziqli model + gradient boosting
5. TARMOQ: kichikdan boshlab, qadamma-qadam
6. TASHXIS: loss egri, qatlam statistikasi, gradient
7. REGULARIZATSIYA: erta to'xtash -> wd -> dropout
8. TAQQOSLASH: juftlashgan, SE bilan
9. TEST: BIR MARTA
10. PAKET: model + masshtablovchi + metama'lumot
HAR QADAMDA: natijani yozing, bitta o'zgarish qilingTartib 18-qismdagi bilan bir xil — faqat modellar ro'yxatiga tarmoq qo'shildi.
2.3. Tarmoq uchun tayyorlash
MAJBURIY:
masshtablash (StandardScaler) - tarmoqlar buni TALAB qiladi
kategoriyalarni kodlash (one-hot yoki embedding)
yo'qolgan qiymatlarni to'ldirish (NaN tarmoqni buzadi)
TAVSIYA:
maqsadni ham masshtablash (regressiyada)
chetdagi qiymatlarni qisish (clip)
kuchli qiyshiq taqsimotda log
DIQQAT: HAMMASI QUVUR ICHIDA (19-qism)
masshtablovchi o'QUV to'plamida fit qilinadi
test to'plamida faqat transform
KATEGORIYA KO'P DARAJALI BO'LSA:
one-hot -> o'lcham portlashi
embedding -> tarmoq uchun tabiiy yechim (26-qism)Masshtablash tarmoq uchun ixtiyoriy emas — daraxtlardan asosiy farqlaridan biri.
2.4. Tashxis ro'yxati
O'RGATISHDAN OLDIN:
[ ] boshlang'ich loss ~ log(K) mi
[ ] har qatlam std ~1 mi
[ ] X.std() ~1 mi
[ ] yorliqlar 0..K-1 mi
O'RGATISH DAVOMIDA:
[ ] train va val loss ikkalasi ham tushyaptimi
[ ] NaN yo'qmi
[ ] gradient normasi barqarormi
[ ] o'lgan neyron ulushi < 50% mi
O'RGATISHDAN KEYIN:
[ ] val loss eng past nuqtadan keyin o'sdimi (yodlash)
[ ] bazaviydan 2*SE dan ortiq yaxshimi
[ ] bir necha seed da barqarormi
[ ] kalibratsiya yaxshimiTashxisni o'rgatishdan oldin boshlang — bu soatlarni tejaydi.
2.5. Taqqoslash
NOTO'G'RI: tarmoq 0.85, boosting 0.84 -> tarmoq g'olib
TO'G'RI:
bir xil CV bo'linishida (juftlashgan)
farqning SE sini hisoblab
bir necha seed bilan
o'rgatish VAQTINI ham hisobga olib
QAROR MEZONI (18-qism):
farq > 2*SE bo'lsa - sezilarli
aks holda - SODDAROQ modelni tanlang
⭐ Teng natijada boosting tanlanadi:
tezroq, sozlashga oson, tushuntirish qulayTeng natijada soddaroq model g'olib — bu qoida tarmoqlarga ham tegishli.
2.6. Saqlash va topshirish
PAKETGA KIRADIGAN NARSALAR:
model.state_dict() <- og'irliklar (butun model EMAS)
arxitektura ta'rifi <- qayta qurish uchun
masshtablovchi <- MAJBURIY
belgilar va tartibi
metrikalar (cv, test)
versiyalar (torch, sklearn, python)
seed, davrlar, eng yaxshi davr
nazorat namunasi + bashoratlar
NIMA UCHUN state_dict:
torch.save(model) pickle ga tayanadi - sinf yo'li kerak
state_dict faqat tensorlar - xavfsizroq va ko'chma
YUKLASHDA:
model = Arxitektura(...) # qayta quriladi
model.load_state_dict(holat)
model.eval() # UNUTMANG state_dict saqlang, butun modelni emas — ko'chma va xavfsizroq.
2.7. Tuzoqlar
Asosiy tuzoqlar: boosting bilan taqqoslamaslik; masshtablovchini saqlamaslik; model.eval() ni yuklashdan keyin unutish; test to'plamini bir necha marta ochish; bitta seed natijasiga tayanish; o'rgatish vaqtini hisobga olmaslik; tashxisni faqat muammo chiqqanda qilish.
3. Tez ma'lumotnoma
# 1. dizayn
tr, te = GroupShuffleSplit(1, test_size=0.25, random_state=SEED) ...
# 2. bazaviy
HistGradientBoostingClassifier(random_state=SEED)
LogisticRegression(max_iter=2000)
# 3. tarmoq
sc = StandardScaler().fit(X_tr)
model = torch.nn.Sequential(...)
opt = torch.optim.AdamW(model.parameters(), lr=1e-2, weight_decay=1e-4)
# 4. tashxis
assert abs(boshlangich_loss - np.log(K)) < 0.1
print([A.std().item() for A in qatlam_chiqishlari])
# 5. paket
torch.save({"holat": model.state_dict(),
"arxitektura": olchamlar,
"masshtablovchi": sc,
"metrika": {...},
"versiyalar": {...}}, "model.pt")Amaliyot xulosasi
bazaviy: boosting MAJBURIY
tayyorlash: masshtablash MAJBURIY
tashxis: oldin, davomida, keyin
taqqoslash: juftlashgan + SE
paket: state_dict + masshtablovchi + metama'lumot4. Batafsil misollar
Misollar real torch/sklearn bilan (Python 3.14, torch 2.14 CPU).
Misol 1 — Ma'lumot, dizayn va bazaviy modellar
"""1-qadam: vazifani qo'yish va bazaviyni o'rnatish."""
import numpy as np
import pandas as pd
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import (GroupKFold, GroupShuffleSplit,
cross_val_score)
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
SEED = 42
MAQSAD = "javob"
GURUH = "mijoz"
def yarat(seed: int = 7, mijozlar: int = 800) -> pd.DataFrame:
"""Marketing javobi: guruh tuzilmasi va nochiziqli bog'liqlik."""
rng = np.random.default_rng(seed)
qatorlar = []
for m in range(mijozlar):
imzo = rng.normal(0, 1)
segment = rng.integers(0, 4)
for _ in range(int(rng.integers(3, 12))):
yosh = float(rng.normal(38, 12))
daromad = float(rng.lognormal(13.2, 0.55))
aloqa = int(rng.integers(0, 15))
kun = int(rng.integers(0, 365))
fasl = np.sin(2 * np.pi * kun / 365)
kuch = (-1.4
+ 0.9 * np.tanh((yosh - 40) / 12)
+ 0.7 * np.tanh((np.log(daromad) - 13.2) / 0.5)
+ 1.2 * np.tanh((yosh - 40) / 12)
* np.tanh((np.log(daromad) - 13.2) / 0.5)
+ 0.5 * fasl
- 0.12 * aloqa
+ 0.35 * segment
+ 1.3 * imzo)
qatorlar.append([m, segment, yosh, daromad, aloqa, kun,
int(rng.random() < 1 / (1 + np.exp(-kuch)))])
return pd.DataFrame(qatorlar,
columns=[GURUH, "segment", "yosh", "daromad",
"aloqa", "kun", MAQSAD])
def main() -> None:
df = yarat()
belgilar = ["segment", "yosh", "daromad", "aloqa", "kun"]
X = df[belgilar].to_numpy(dtype=float)
y = df[MAQSAD].to_numpy()
guruh = df[GURUH].to_numpy()
print("=== 1. Ma'lumot ===")
print(f" {len(df)} qator, {df[GURUH].nunique()} mijoz, "
f"{len(belgilar)} belgi")
print(f" javob ulushi: {y.mean():.2%}")
print(f" {'belgi':<10} {'o_rtacha':>12} {'std':>12} {'noyob':>8}")
for i, b in enumerate(belgilar):
print(f" {b:<10} {X[:, i].mean():>12.2f} {X[:, i].std():>12.2f} "
f"{len(np.unique(X[:, i])):>8}")
print("\n=== 2. Dizayn: testni QULFLASH ===")
tr, te = next(GroupShuffleSplit(1, test_size=0.25, random_state=SEED)
.split(X, y, groups=guruh))
Xtr, ytr, gtr = X[tr], y[tr], guruh[tr]
Xte, yte = X[te], y[te]
print(f" ish to'plami: {len(tr)} qator, "
f"{len(np.unique(gtr))} mijoz")
print(f" TEST (yopiq): {len(te)} qator, "
f"{len(np.unique(guruh[te]))} mijoz")
print(f" mijoz kesishishi: {len(np.intersect1d(gtr, guruh[te]))}")
print(f" metrika: roc_auc (nomutanosiblik "
f"{ytr.mean():.1%} / {1 - ytr.mean():.1%})")
print("\n=== 3. Bazaviy modellar ===")
cv = GroupKFold(5)
modellar = {
"LogisticRegression": make_pipeline(
StandardScaler(), LogisticRegression(max_iter=2000)),
"HistGradientBoosting": HistGradientBoostingClassifier(
max_iter=250, early_stopping=False, random_state=SEED),
}
print(f" {'model':<24} {'CV AUC':>9} {'std':>8} {'SE':>8}")
natijalar = {}
for nom, m in modellar.items():
b = cross_val_score(m, Xtr, ytr, cv=cv, groups=gtr,
scoring="roc_auc")
natijalar[nom] = b
se = float(b.std(ddof=1) / np.sqrt(len(b)))
print(f" {nom:<24} {b.mean():>9.4f} {b.std():>8.4f} "
f"{se:>8.4f}")
print("\n=== 4. Qaror chegarasi ===")
eng_nom = max(natijalar, key=lambda k: natijalar[k].mean())
eng = natijalar[eng_nom]
se = float(eng.std(ddof=1) / np.sqrt(len(eng)))
print(f" eng yaxshi bazaviy: {eng_nom} ({eng.mean():.4f})")
print(f" SE: {se:.4f}, chegara (2*SE): {2 * se:.4f}")
print(f" tarmoq {eng.mean() + 2 * se:.4f} dan yuqori bo'lishi kerak")
print("\n=== 5. Nochiziqlilik bormi ===")
lr_b = natijalar["LogisticRegression"].mean()
gb_b = natijalar["HistGradientBoosting"].mean()
print(f" chiziqli: {lr_b:.4f}")
print(f" daraxtlar: {gb_b:.4f}")
print(f" farq: {gb_b - lr_b:+.4f}")
xulosa = ("bor - tarmoq sinashga arziydi" if gb_b - lr_b > 2 * se
else "yo'q - tarmoq foyda bermasligi mumkin")
print(f" nochiziqlilik: {xulosa}")
print(" ⭐ Tarmoqni sinashdan OLDIN bazaviyni o'rnating")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ma'lumot ===
5644 qator, 800 mijoz, 5 belgi
javob ulushi: 22.54%
belgi o_rtacha std noyob
segment 1.55 1.10 4
yosh 37.84 12.00 5644
daromad 626020.96 372111.58 5644
aloqa 7.00 4.31 15
kun 181.46 106.25 365
=== 2. Dizayn: testni QULFLASH ===
ish to'plami: 4234 qator, 600 mijoz
TEST (yopiq): 1410 qator, 200 mijoz
mijoz kesishishi: 0
metrika: roc_auc (nomutanosiblik 23.1% / 76.9%)
=== 3. Bazaviy modellar ===
model CV AUC std SE
LogisticRegression 0.6805 0.0406 0.0203
HistGradientBoosting 0.6491 0.0216 0.0108
=== 4. Qaror chegarasi ===
eng yaxshi bazaviy: LogisticRegression 0.6805-bob
SE: 0.0203, chegara (2*SE): 0.0406
tarmoq 0.7210 dan yuqori bo'lishi kerak
=== 5. Nochiziqlilik bormi ===
chiziqli: 0.6805
daraxtlar: 0.6491
farq: -0.0314
nochiziqlilik: yo'q - tarmoq foyda bermasligi mumkin
⭐ Tarmoqni sinashdan OLDIN bazaviyni o'rnatingNima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — Tarmoqni qurish va tashxis
"""2-qadam: tarmoq + o'rgatishdan oldin va davomida tashxis."""
import numpy as np
import pandas as pd
import torch
from sklearn.model_selection import GroupShuffleSplit
from sklearn.preprocessing import StandardScaler
SEED = 42
MAQSAD = "javob"
GURUH = "mijoz"
def yarat(seed: int = 7, mijozlar: int = 800) -> pd.DataFrame:
rng = np.random.default_rng(seed)
qatorlar = []
for m in range(mijozlar):
imzo = rng.normal(0, 1)
segment = rng.integers(0, 4)
for _ in range(int(rng.integers(3, 12))):
yosh = float(rng.normal(38, 12))
daromad = float(rng.lognormal(13.2, 0.55))
aloqa = int(rng.integers(0, 15))
kun = int(rng.integers(0, 365))
fasl = np.sin(2 * np.pi * kun / 365)
kuch = (-1.4 + 0.9 * np.tanh((yosh - 40) / 12)
+ 0.7 * np.tanh((np.log(daromad) - 13.2) / 0.5)
+ 1.2 * np.tanh((yosh - 40) / 12)
* np.tanh((np.log(daromad) - 13.2) / 0.5)
+ 0.5 * fasl - 0.12 * aloqa + 0.35 * segment
+ 1.3 * imzo)
qatorlar.append([m, segment, yosh, daromad, aloqa, kun,
int(rng.random() < 1 / (1 + np.exp(-kuch)))])
return pd.DataFrame(qatorlar,
columns=[GURUH, "segment", "yosh", "daromad",
"aloqa", "kun", MAQSAD])
def tarmoq(kirish, kenglik=64, dropout=0.2, seed=SEED):
torch.manual_seed(seed)
return torch.nn.Sequential(
torch.nn.Linear(kirish, kenglik), torch.nn.ReLU(),
torch.nn.Dropout(dropout),
torch.nn.Linear(kenglik, kenglik // 2), torch.nn.ReLU(),
torch.nn.Linear(kenglik // 2, 2))
def main() -> None:
df = yarat()
belgilar = ["segment", "yosh", "daromad", "aloqa", "kun"]
X = df[belgilar].to_numpy(dtype=float)
y = df[MAQSAD].to_numpy()
guruh = df[GURUH].to_numpy()
tr, te = next(GroupShuffleSplit(1, test_size=0.25, random_state=SEED)
.split(X, y, groups=guruh))
print("=== 1. Masshtablash - tarmoq uchun MAJBURIY ===")
print(f" {'belgi':<10} {'xom std':>12} {'masshtablangan':>16}")
sc = StandardScaler().fit(X[tr])
Xs = sc.transform(X[tr])
for i, b in enumerate(belgilar):
print(f" {b:<10} {X[tr][:, i].std():>12.2f} "
f"{Xs[:, i].std():>16.4f}")
print(" daromad xom holda 10^5 tartibida - tarmoqni buzadi")
Xtr_t = torch.tensor(Xs, dtype=torch.float32)
Xte_t = torch.tensor(sc.transform(X[te]), dtype=torch.float32)
ytr_t = torch.tensor(y[tr], dtype=torch.int64)
yte_t = torch.tensor(y[te], dtype=torch.int64)
print("\n=== 2. O'rgatishdan OLDINGI tashxis ===")
model = tarmoq(len(belgilar))
kriteriy = torch.nn.CrossEntropyLoss()
model.eval()
with torch.no_grad():
boshlangich = kriteriy(model(Xtr_t), ytr_t).item()
kutilgan = float(np.log(2))
print(f" {'tekshiruv':<28} {'qiymat':>12} {'holat':>8}")
print(f" {'boshlang_ich loss':<28} {boshlangich:>12.4f} "
f"{'OK' if abs(boshlangich - kutilgan) < 0.15 else 'XATO':>8}")
print(f" {'kutilgan log(2)':<28} {kutilgan:>12.4f}")
print(f" {'X.std()':<28} {Xtr_t.std().item():>12.4f} "
f"{'OK' if 0.5 < Xtr_t.std() < 2 else 'XATO':>8}")
print(f" {'yorliqlar':<28} "
f"{str(sorted(set(y.tolist()))):>12} "
f"{'OK' if set(y.tolist()) == {0, 1} else 'XATO':>8}")
print(f" {'parametrlar':<28} "
f"{sum(p.numel() for p in model.parameters()):>12}")
print("\n=== 3. Qatlamlar bo'ylab signal ===")
with torch.no_grad():
A = Xtr_t
print(f" {'bosqich':<14} {'shakl':>12} {'std':>10} {'nol %':>8}")
print(f" {'kirish':<14} {str(tuple(A.shape)):>12} "
f"{A.std().item():>10.4f} "
f"{(A == 0).float().mean().item():>8.1%}")
for i, qatlam in enumerate(model):
A = qatlam(A)
if isinstance(qatlam, (torch.nn.Linear, torch.nn.ReLU)):
print(f" {f'{type(qatlam).__name__} {i}':<14} "
f"{str(tuple(A.shape)):>12} {A.std().item():>10.4f} "
f"{(A == 0).float().mean().item():>8.1%}")
print("\n=== 4. O'rgatish va kuzatish ===")
opt = torch.optim.AdamW(model.parameters(), lr=0.01,
weight_decay=1e-4)
g = torch.Generator().manual_seed(SEED)
print(f" {'davr':>6} {'o_quv loss':>12} {'grad norma':>12} "
f"{'o_lgan %':>10} {'test AUC':>10}")
from sklearn.metrics import roc_auc_score
for davr in range(1, 61):
model.train()
tartib = torch.randperm(len(ytr_t), generator=g)
jami, n, normalar = 0.0, 0, []
for boshi in range(0, len(ytr_t), 128):
idx = tartib[boshi:boshi + 128]
opt.zero_grad()
loss = kriteriy(model(Xtr_t[idx]), ytr_t[idx])
loss.backward()
normalar.append(float(torch.nn.utils.clip_grad_norm_(
model.parameters(), 1e9)))
opt.step()
jami += loss.item() * len(idx)
n += len(idx)
if davr in (1, 5, 15, 30, 60):
model.eval()
with torch.no_grad():
birinchi = torch.relu(model[0](Xtr_t))
olgan = (birinchi.max(dim=0).values == 0).float().mean()
p = torch.softmax(model(Xte_t), dim=1)[:, 1].numpy()
print(f" {davr:>6} {jami / n:>12.4f} "
f"{np.mean(normalar):>12.4f} {olgan.item():>10.1%} "
f"{roc_auc_score(yte_t.numpy(), p):>10.4f}")
print("\n=== 5. O'rgatishdan KEYINGI tashxis ===")
model.eval()
with torch.no_grad():
chiqish = model(Xte_t)
p = torch.softmax(chiqish, dim=1)[:, 1].numpy()
print(f" {'tekshiruv':<28} {'qiymat':>12}")
print(f" {'test AUC':<28} "
f"{roc_auc_score(yte_t.numpy(), p):>12.4f}")
print(f" {'bashoratlar o_rtachasi':<28} {p.mean():>12.4f}")
print(f" {'haqiqiy ulush':<28} {yte_t.float().mean().item():>12.4f}")
print(f" {'p > 0.99 ulushi':<28} {(p > 0.99).mean():>12.4f}")
print(f" {'og_irliklar normasi':<28} "
f"{sum(p_.norm().item() ** 2 for p_ in model.parameters()) ** 0.5:>12.4f}")
print(" ⭐ Tashxisni oldin, davomida va keyin qiling")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Masshtablash - tarmoq uchun MAJBURIY ===
belgi xom std masshtablangan
segment 1.09 1.0000
yosh 12.15 1.0000
daromad 370727.01 1.0000
aloqa 4.31 1.0000
kun 106.25 1.0000
daromad xom holda 10^5 tartibida - tarmoqni buzadi
=== 2. O'rgatishdan OLDINGI tashxis ===
tekshiruv qiymat holat
boshlang_ich loss 0.7034 OK
kutilgan log(2) 0.6931
X.std() 1.0000 OK
yorliqlar [0, 1] OK
parametrlar 2530
=== 3. Qatlamlar bo'ylab signal ===
bosqich shakl std nol %
kirish (4234, 5) 1.0000 0.0%
Linear 0 (4234, 64) 0.6421 0.0%
ReLU 1 (4234, 64) 0.3611 53.2%
Linear 3 (4234, 32) 0.2393 0.0%
ReLU 4 (4234, 32) 0.1462 48.6%
Linear 5 (4234, 2) 0.0806 0.0%
=== 4. O'rgatish va kuzatish ===
davr o_quv loss grad norma o_lgan % test AUC
1 0.5299 0.1978 1.6% 0.7258
5 0.4934 0.1516 1.6% 0.7237
15 0.4876 0.1816 3.1% 0.7232
30 0.4891 0.1912 3.1% 0.7141
60 0.4673 0.2022 3.1% 0.6878
=== 5. O'rgatishdan KEYINGI tashxis ===
tekshiruv qiymat
test AUC 0.6878
bashoratlar o_rtachasi 0.2519
haqiqiy ulush 0.2085
p > 0.99 ulushi 0.0000
og_irliklar normasi 16.4885
⭐ Tashxisni oldin, davomida va keyin qilingNima ko'rsatdi: 2.3, 2.4-bo'limlar.
Misol 3 — Juftlashgan taqqoslash
"""3-qadam: tarmoq bazaviydan yaxshimi - halol taqqoslash."""
import numpy as np
import pandas as pd
import torch
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import GroupKFold, GroupShuffleSplit
from sklearn.preprocessing import StandardScaler
SEED = 42
MAQSAD = "javob"
GURUH = "mijoz"
def yarat(seed: int = 7, mijozlar: int = 800) -> pd.DataFrame:
rng = np.random.default_rng(seed)
qatorlar = []
for m in range(mijozlar):
imzo = rng.normal(0, 1)
segment = rng.integers(0, 4)
for _ in range(int(rng.integers(3, 12))):
yosh = float(rng.normal(38, 12))
daromad = float(rng.lognormal(13.2, 0.55))
aloqa = int(rng.integers(0, 15))
kun = int(rng.integers(0, 365))
fasl = np.sin(2 * np.pi * kun / 365)
kuch = (-1.4 + 0.9 * np.tanh((yosh - 40) / 12)
+ 0.7 * np.tanh((np.log(daromad) - 13.2) / 0.5)
+ 1.2 * np.tanh((yosh - 40) / 12)
* np.tanh((np.log(daromad) - 13.2) / 0.5)
+ 0.5 * fasl - 0.12 * aloqa + 0.35 * segment
+ 1.3 * imzo)
qatorlar.append([m, segment, yosh, daromad, aloqa, kun,
int(rng.random() < 1 / (1 + np.exp(-kuch)))])
return pd.DataFrame(qatorlar,
columns=[GURUH, "segment", "yosh", "daromad",
"aloqa", "kun", MAQSAD])
def tarmoq_orgat(Xtr, ytr, Xva, kenglik=64, dropout=0.2, davrlar=55,
seed=SEED):
torch.manual_seed(seed)
model = torch.nn.Sequential(
torch.nn.Linear(Xtr.shape[1], kenglik), torch.nn.ReLU(),
torch.nn.Dropout(dropout),
torch.nn.Linear(kenglik, kenglik // 2), torch.nn.ReLU(),
torch.nn.Linear(kenglik // 2, 2))
opt = torch.optim.AdamW(model.parameters(), lr=0.01,
weight_decay=1e-3)
kriteriy = torch.nn.CrossEntropyLoss()
Xtr_t = torch.tensor(Xtr, dtype=torch.float32)
ytr_t = torch.tensor(ytr, dtype=torch.int64)
g = torch.Generator().manual_seed(seed)
for _ in range(davrlar):
model.train()
tartib = torch.randperm(len(ytr_t), generator=g)
for boshi in range(0, len(ytr_t), 128):
idx = tartib[boshi:boshi + 128]
opt.zero_grad()
kriteriy(model(Xtr_t[idx]), ytr_t[idx]).backward()
opt.step()
model.eval()
with torch.no_grad():
return torch.softmax(
model(torch.tensor(Xva, dtype=torch.float32)),
dim=1)[:, 1].numpy()
def main() -> None:
df = yarat()
belgilar = ["segment", "yosh", "daromad", "aloqa", "kun"]
X = df[belgilar].to_numpy(dtype=float)
y = df[MAQSAD].to_numpy()
guruh = df[GURUH].to_numpy()
tr, te = next(GroupShuffleSplit(1, test_size=0.25, random_state=SEED)
.split(X, y, groups=guruh))
Xtr, ytr, gtr = X[tr], y[tr], guruh[tr]
print("=== 1. Juftlashgan CV (bir xil foldlar) ===")
cv = GroupKFold(5)
ballar = {"LogReg": [], "HistGB": [], "Tarmoq": []}
for k, (i_tr, i_va) in enumerate(cv.split(Xtr, ytr, groups=gtr)):
sc = StandardScaler().fit(Xtr[i_tr])
A, B = sc.transform(Xtr[i_tr]), sc.transform(Xtr[i_va])
lr = LogisticRegression(max_iter=2000).fit(A, ytr[i_tr])
ballar["LogReg"].append(
roc_auc_score(ytr[i_va], lr.predict_proba(B)[:, 1]))
gb = HistGradientBoostingClassifier(
max_iter=150, early_stopping=False,
random_state=SEED).fit(Xtr[i_tr], ytr[i_tr])
ballar["HistGB"].append(
roc_auc_score(ytr[i_va], gb.predict_proba(Xtr[i_va])[:, 1]))
p = tarmoq_orgat(A, ytr[i_tr], B)
ballar["Tarmoq"].append(roc_auc_score(ytr[i_va], p))
print(f" {'fold':>5} {'LogReg':>9} {'HistGB':>9} {'Tarmoq':>9}")
for k in range(5):
print(f" {k + 1:>5} {ballar['LogReg'][k]:>9.4f} "
f"{ballar['HistGB'][k]:>9.4f} "
f"{ballar['Tarmoq'][k]:>9.4f}")
print("\n=== 2. O'rtachalar ===")
print(f" {'model':<10} {'CV AUC':>9} {'std':>8} {'SE':>8}")
for nom, b in ballar.items():
b = np.array(b)
print(f" {nom:<10} {b.mean():>9.4f} {b.std(ddof=1):>8.4f} "
f"{b.std(ddof=1) / np.sqrt(5):>8.4f}")
print("\n=== 3. Juftlashgan farqlar ===")
print(f" {'taqqoslash':<20} {'o_rt farq':>11} {'SE':>9} "
f"{'sezilarlimi':>13}")
juftlar = [("Tarmoq - HistGB", "Tarmoq", "HistGB"),
("Tarmoq - LogReg", "Tarmoq", "LogReg"),
("HistGB - LogReg", "HistGB", "LogReg")]
for nom, a, b in juftlar:
d = np.array(ballar[a]) - np.array(ballar[b])
se = float(d.std(ddof=1) / np.sqrt(len(d)))
print(f" {nom:<20} {d.mean():>+11.4f} {se:>9.4f} "
f"{str(abs(d.mean()) > 2 * se):>13}")
print(" juftlashgan farq fold shovqinini YO'Q QILADI")
print("\n=== 4. Tarmoqning barqarorligi ===")
sc = StandardScaler().fit(Xtr)
i_tr, i_va = next(iter(cv.split(Xtr, ytr, groups=gtr)))
sc2 = StandardScaler().fit(Xtr[i_tr])
A, B = sc2.transform(Xtr[i_tr]), sc2.transform(Xtr[i_va])
seed_ballari = [roc_auc_score(ytr[i_va],
tarmoq_orgat(A, ytr[i_tr], B, seed=s))
for s in range(4)]
seed_ballari = np.array(seed_ballari)
print(f" 4 ta seed: {seed_ballari.round(4).tolist()}")
print(f" o'rtacha {seed_ballari.mean():.4f}, "
f"std {seed_ballari.std(ddof=1):.4f}")
print(f" seed tarqoqligi fold tarqoqligidan "
f"{'KICHIK' if seed_ballari.std(ddof=1) < np.array(ballar['Tarmoq']).std(ddof=1) else 'KATTA'}")
print("\n=== 5. Vaqt va murakkablikni ham hisobga olamiz ===")
jadval = [
("LogReg", "5 ta koeffitsiyent", "juda tez", "to'liq"),
("HistGB", "~150 daraxt", "tez", "belgi muhimligi"),
("Tarmoq", "~4900 parametr", "sekinroq", "qiyin"),
]
print(f" {'model':<10} {'murakkablik':<20} {'o_rgatish':<11} "
f"{'tushuntirish'}")
for a, b, c, d in jadval:
print(f" {a:<10} {b:<20} {c:<11} {d}")
farq = (np.array(ballar["Tarmoq"]) - np.array(ballar["HistGB"]))
se = float(farq.std(ddof=1) / np.sqrt(5))
qaror = ("Tarmoq" if farq.mean() > 2 * se else "HistGB")
print(f" QAROR: {qaror}")
print(" ⭐ Teng natijada SODDAROQ model tanlanadi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Juftlashgan CV (bir xil foldlar) ===
fold LogReg HistGB Tarmoq
1 0.7099 0.6588 0.6840
2 0.6582 0.6492 0.6777
3 0.7354 0.6881 0.7187
4 0.6184 0.6153 0.6458
5 0.6804 0.6672 0.6797
=== 2. O'rtachalar ===
model CV AUC std SE
LogReg 0.6805 0.0454 0.0203
HistGB 0.6557 0.0268 0.0120
Tarmoq 0.6812 0.0259 0.0116
=== 3. Juftlashgan farqlar ===
taqqoslash o_rt farq SE sezilarlimi
Tarmoq - HistGB +0.0255 0.0034 True
Tarmoq - LogReg +0.0007 0.0102 False
HistGB - LogReg -0.0248 0.0101 True
juftlashgan farq fold shovqinini YO'Q QILADI
=== 4. Tarmoqning barqarorligi ===
4 ta seed: [0.6872, 0.6951, 0.6854, 0.693]
o'rtacha 0.6902, std 0.0046
seed tarqoqligi fold tarqoqligidan KICHIK
=== 5. Vaqt va murakkablikni ham hisobga olamiz ===
model murakkablik o_rgatish tushuntirish
LogReg 5 ta koeffitsiyent juda tez to'liq
HistGB ~150 daraxt tez belgi muhimligi
Tarmoq ~4900 parametr sekinroq qiyin
QAROR: Tarmoq
⭐ Teng natijada SODDAROQ model tanlanadiNima ko'rsatdi: 2.5-bo'lim.
Misol 4 — Yopiq test, paket va hisobot
"""4-qadam: testni bir marta ochish va artefakt tayyorlash."""
import io
import shutil
import sys
import tempfile
from pathlib import Path
import numpy as np
import pandas as pd
import sklearn
import torch
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.metrics import (average_precision_score, brier_score_loss,
roc_auc_score)
from sklearn.model_selection import GroupShuffleSplit
from sklearn.preprocessing import StandardScaler
SEED = 42
MAQSAD = "javob"
GURUH = "mijoz"
BELGILAR = ["segment", "yosh", "daromad", "aloqa", "kun"]
def yarat(seed: int = 7, mijozlar: int = 800) -> pd.DataFrame:
rng = np.random.default_rng(seed)
qatorlar = []
for m in range(mijozlar):
imzo = rng.normal(0, 1)
segment = rng.integers(0, 4)
for _ in range(int(rng.integers(3, 12))):
yosh = float(rng.normal(38, 12))
daromad = float(rng.lognormal(13.2, 0.55))
aloqa = int(rng.integers(0, 15))
kun = int(rng.integers(0, 365))
fasl = np.sin(2 * np.pi * kun / 365)
kuch = (-1.4 + 0.9 * np.tanh((yosh - 40) / 12)
+ 0.7 * np.tanh((np.log(daromad) - 13.2) / 0.5)
+ 1.2 * np.tanh((yosh - 40) / 12)
* np.tanh((np.log(daromad) - 13.2) / 0.5)
+ 0.5 * fasl - 0.12 * aloqa + 0.35 * segment
+ 1.3 * imzo)
qatorlar.append([m, segment, yosh, daromad, aloqa, kun,
int(rng.random() < 1 / (1 + np.exp(-kuch)))])
return pd.DataFrame(qatorlar,
columns=[GURUH] + BELGILAR + [MAQSAD])
ARXITEKTURA = [len(BELGILAR), 64, 32, 2]
def tarmoq_yasa(olchamlar=ARXITEKTURA, dropout=0.2, seed=SEED):
torch.manual_seed(seed)
qatlamlar = []
for i in range(len(olchamlar) - 1):
qatlamlar.append(torch.nn.Linear(olchamlar[i], olchamlar[i + 1]))
if i < len(olchamlar) - 2:
qatlamlar.append(torch.nn.ReLU())
if i == 0 and dropout > 0:
qatlamlar.append(torch.nn.Dropout(dropout))
return torch.nn.Sequential(*qatlamlar)
def orgat(model, Xtr, ytr, davrlar=90, seed=SEED):
opt = torch.optim.AdamW(model.parameters(), lr=0.01,
weight_decay=1e-3)
kriteriy = torch.nn.CrossEntropyLoss()
Xt = torch.tensor(Xtr, dtype=torch.float32)
yt = torch.tensor(ytr, dtype=torch.int64)
g = torch.Generator().manual_seed(seed)
for _ in range(davrlar):
model.train()
tartib = torch.randperm(len(yt), generator=g)
for boshi in range(0, len(yt), 128):
idx = tartib[boshi:boshi + 128]
opt.zero_grad()
kriteriy(model(Xt[idx]), yt[idx]).backward()
opt.step()
return model
@torch.no_grad()
def ehtimollik(model, X):
model.eval()
return torch.softmax(model(torch.tensor(X, dtype=torch.float32)),
dim=1)[:, 1].numpy()
def main() -> None:
df = yarat()
X = df[BELGILAR].to_numpy(dtype=float)
y = df[MAQSAD].to_numpy()
guruh = df[GURUH].to_numpy()
tr, te = next(GroupShuffleSplit(1, test_size=0.25, random_state=SEED)
.split(X, y, groups=guruh))
sc = StandardScaler().fit(X[tr])
print("=== 1. Yopiq testni BIR MARTA ochamiz ===")
model = orgat(tarmoq_yasa(), sc.transform(X[tr]), y[tr])
gb = HistGradientBoostingClassifier(
max_iter=250, early_stopping=False,
random_state=SEED).fit(X[tr], y[tr])
p_nn = ehtimollik(model, sc.transform(X[te]))
p_gb = gb.predict_proba(X[te])[:, 1]
print(f" {'model':<10} {'AUC':>9} {'AP':>9} {'Brier':>9}")
for nom, p in [("Tarmoq", p_nn), ("HistGB", p_gb)]:
print(f" {nom:<10} {roc_auc_score(y[te], p):>9.4f} "
f"{average_precision_score(y[te], p):>9.4f} "
f"{brier_score_loss(y[te], p):>9.5f}")
print(f" ansambl (o'rtacha): "
f"{roc_auc_score(y[te], (p_nn + p_gb) / 2):.4f}")
print("\n=== 2. Kalibratsiya ===")
print(f" {'chorak':<18} {'o_rt bashorat':>14} {'haqiqiy ulush':>14}")
chegaralar = np.quantile(p_nn, [0, 0.25, 0.5, 0.75, 1.0])
for i in range(4):
maska = (p_nn >= chegaralar[i]) & (p_nn <= chegaralar[i + 1])
print(f" {f'[{chegaralar[i]:.2f}, {chegaralar[i+1]:.2f}]':<18} "
f"{p_nn[maska].mean():>14.4f} {y[te][maska].mean():>14.4f}")
print("\n=== 3. Paket ===")
papka = Path(tempfile.mkdtemp(prefix="nn_loyiha_"))
try:
nazorat_X = sc.transform(X[te][:40])
paket = {
"holat": model.state_dict(),
"arxitektura": ARXITEKTURA,
"dropout": 0.2,
"masshtablovchi": sc,
"belgilar": BELGILAR,
"metrika": {"test_auc": round(
float(roc_auc_score(y[te], p_nn)), 4)},
"versiyalar": {"torch": torch.__version__,
"sklearn": sklearn.__version__,
"numpy": np.__version__,
"python": sys.version.split()[0]},
"seed": SEED,
"davrlar": 90,
"sana": "2026-09-22",
"nazorat": {"X": nazorat_X,
"p": ehtimollik(model, nazorat_X)},
}
yol = papka / "model.pt"
torch.save(paket, yol)
print(f" kalitlar: {sorted(paket)}")
print(f" fayl hajmi: {yol.stat().st_size / 1024:.1f} KB")
holat_hajmi = io.BytesIO()
torch.save(model.state_dict(), holat_hajmi)
print(f" faqat state_dict: {holat_hajmi.tell() / 1024:.1f} KB")
print("\n=== 4. Yuklash va uch tekshiruv ===")
yuklangan = torch.load(yol, weights_only=False)
qayta = tarmoq_yasa(yuklangan["arxitektura"],
yuklangan["dropout"])
qayta.load_state_dict(yuklangan["holat"])
qayta.eval()
p_qayta = ehtimollik(qayta, yuklangan["nazorat"]["X"])
tekshiruvlar = [
("belgilar va tartibi",
yuklangan["belgilar"] == BELGILAR),
("torch versiyasi",
yuklangan["versiyalar"]["torch"] == torch.__version__),
("nazorat bashoratlari",
bool(np.allclose(p_qayta, yuklangan["nazorat"]["p"],
atol=1e-6))),
]
print(f" {'tekshiruv':<24} {'natija':>8}")
for nom, holat in tekshiruvlar:
print(f" {nom:<24} {'OK' if holat else 'XATO':>8}")
print("\n=== 5. eval() ni unutish narxi ===")
qayta.train()
p_xato = ehtimollik(qayta, yuklangan["nazorat"]["X"])
qayta.eval()
p_togri = ehtimollik(qayta, yuklangan["nazorat"]["X"])
print(f" ehtimollik() ichida eval() bor - shuning uchun")
print(f" ikkalasi ham to'g'ri: "
f"{bool(np.allclose(p_xato, p_togri))}")
qayta.train()
with torch.no_grad():
xom = torch.softmax(
qayta(torch.tensor(yuklangan["nazorat"]["X"],
dtype=torch.float32)),
dim=1)[:, 1].numpy()
print(f" eval() SIZ (train rejimida) farq: "
f"{np.abs(xom - p_togri).mean():.4f}")
print("\n=== 6. Yakuniy hisobot ===")
print(" VAZIFA: marketing javobini bashorat qilish")
print(" METRIKA: roc_auc")
print(" DIZAYN: GroupKFold(5) mijoz bo'yicha; "
"test GroupShuffleSplit 25%")
print(f" NATIJA: tarmoq {roc_auc_score(y[te], p_nn):.4f}, "
f"HistGB {roc_auc_score(y[te], p_gb):.4f}")
print(f" ARXITEKTURA: {' -> '.join(map(str, ARXITEKTURA))}, "
f"{sum(p.numel() for p in model.parameters())} parametr")
print(f" REGULARIZATSIYA: dropout 0.2, weight_decay 1e-3")
print(f" JARAYON: seed {SEED}, 90 davr, AdamW lr=0.01")
print(" CHEKLOVLAR: sun'iy ma'lumot; kategoriya kam darajali;")
print(" drift tekshirilmagan; tarmoq HistGB dan sezilarli")
print(" ustun bo'lmasa - HistGB tavsiya qilinadi")
print(" ⭐ 20-qism yakunlandi: neyrondan artefaktgacha")
finally:
shutil.rmtree(papka, ignore_errors=True)
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Yopiq testni BIR MARTA ochamiz ===
model AUC AP Brier
Tarmoq 0.6962 0.4551 0.14637
HistGB 0.6742 0.4061 0.16014
ansambl (o'rtacha): 0.6933
=== 2. Kalibratsiya ===
chorak o_rt bashorat haqiqiy ulush
[0.00, 0.12] 0.0679 0.1105
[0.12, 0.18] 0.1539 0.1364
[0.18, 0.29] 0.2261 0.1960
[0.29, 0.97] 0.4646 0.3909
=== 3. Paket ===
kalitlar: ['arxitektura', 'belgilar', 'davrlar', 'dropout', 'holat', 'masshtablovchi', 'metrika', 'nazorat', 'sana', 'seed', 'versiyalar']
fayl hajmi: 16.5 KB
faqat state_dict: 12.5 KB
=== 4. Yuklash va uch tekshiruv ===
tekshiruv natija
belgilar va tartibi OK
torch versiyasi OK
nazorat bashoratlari OK
=== 5. eval() ni unutish narxi ===
ehtimollik() ichida eval() bor - shuning uchun
ikkalasi ham to'g'ri: True
eval() SIZ (train rejimida) farq: 0.0310
=== 6. Yakuniy hisobot ===
VAZIFA: marketing javobini bashorat qilish
METRIKA: roc_auc
DIZAYN: GroupKFold(5) mijoz bo'yicha; test GroupShuffleSplit 25%
NATIJA: tarmoq 0.6962, HistGB 0.6742
ARXITEKTURA: 5 -> 64 -> 32 -> 2, 2530 parametr
REGULARIZATSIYA: dropout 0.2, weight_decay 1e-3
JARAYON: seed 42, 90 davr, AdamW lr=0.01
CHEKLOVLAR: sun'iy ma'lumot; kategoriya kam darajali;
drift tekshirilmagan; tarmoq HistGB dan sezilarli
ustun bo'lmasa - HistGB tavsiya qilinadi
⭐ 20-qism yakunlandi: neyrondan artefaktgachaNima ko'rsatdi: 2.6-bo'lim.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Tarmoq zamonaviyroq, demak yaxshiroq" | Tabularda ko'pincha yo'q |
| "Masshtablash ixtiyoriy" | Tarmoq uchun majburiy |
| "Tashxis muammo chiqqanda" | Oldindan qiling |
| "0.85 > 0.84 demak g'olib" | SE ni hisoblang |
| "Butun modelni saqlash qulay" | state_dict ko'chma |
| "Masshtablovchini qayta hisoblasa bo'ladi" | Yo'q — saqlang |
| "Bitta yurish yetarli" | Bir necha seed |
| "Tezlik muhim emas" | Qaror mezonining bir qismi |
6. Keng tarqalgan xatolar va yechimlari
1. Boosting bilan taqqoslamaslik
# faqat tarmoq variantlarini sinash # ⚠️
HistGradientBoostingClassifier(random_state=S) # ✅ bazaviy2. Masshtablovchini saqlamaslik
torch.save(model.state_dict(), "m.pt") # ⚠️
torch.save({"holat": ..., "masshtablovchi": sc}) # ✅3. Yuklashdan keyin eval() yo'q
model.load_state_dict(holat); model(X) # ⚠️
model.load_state_dict(holat); model.eval() # ✅4. Testni bir necha marta ochish
# har variantni testda tekshirish # ⚠️
# faqat yakuniy modelni # ✅5. Bitta seed
ball = orgat(seed=0) # ⚠️
ballar = [orgat(seed=s) for s in range(5)] # ✅6. Tashxissiz o'rgatish
# to'g'ridan-to'g'ri 500 davr # ⚠️
assert abs(boshlangich - np.log(K)) < 0.15 # ✅7. Juftlashmagan taqqoslash
# har modelga boshqa bo'linish # ⚠️
# bir xil foldlar, farqning SE si # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 20.1-20.11-darslar (o'tilgan): Butun qism
- 18-qism (o'tilgan): Baholash dizayni
- 19-qism (o'tilgan): Quvur va paket
- 21-qism: PyTorch to'liq
- 29-qism: MLOps va deploy
8. Eng yaxshi amaliyotlar
Bazaviy sifatida boosting qo'ying.
Masshtablashni quvurga kiriting.
Tashxisni oldindan qiling.
Juftlashgan taqqoslang.
Testni bir marta oching.
state_dictsaqlang.Masshtablovchini paketga qo'shing.
Bir necha seed bilan tekshiring.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # tabularda qaysi model ustun?
2. # tarmoq qachon ustun?
3. # bazaviy nima?
4. # masshtablash majburiymi?
5. # boshlang'ich loss nima bo'lishi kerak?
6. # tashxis qachon?
7. # taqqoslash qanday?
8. # qaror mezoni?
9. # nima saqlanadi?
10. # yuklashdan keyin nima?
11. # necha seed?
12. # test necha marta?Javoblar
- Gradient boosting
- Rasm, matn, juda katta ma'lumot
- Chiziqli + boosting
- Ha
log(K)- Oldin, davomida, keyin
- Juftlashgan, bir xil foldlarda
- Farq >
2*SE state_dict+ masshtablovchi + metama'lumoteval()- Kamida 5
- Bir marta
Vazifa 2: Xatolarni tuzating
1. # faqat tarmoq variantlarini sinash
2. torch.save(model.state_dict(), "m.pt")
3. model.load_state_dict(holat); model(X)
4. ball = orgat(seed=0)
5. # har modelga boshqa bo'linishJavoblar
1. HistGradientBoostingClassifier(random_state=SEED)
2. torch.save({"holat": ..., "masshtablovchi": sc}, "m.pt")
3. model.load_state_dict(holat); model.eval()
4. ballar = [orgat(seed=s) for s in range(5)]
5. # bir xil foldlar, farqning SE siVazifa 3: Dizayn
Modellang:
- Ma'lumot
- Qulflash
- Bazaviy
- Chegara
Vazifa 4: Tashxis
Modellang:
- Masshtab
- Oldindan
- Signal
- Keyin
Vazifa 5: Taqqoslash
Modellang:
- Juftlashgan
- O'rtachalar
- Farqlar
- Barqarorlik
Vazifa 6: Paket
Modellang:
- Test
- Kalibratsiya
- Saqlash
- Yuklash
Vazifa 7: O'ylash
Rahbaringiz so'radi: "Nega neyron tarmoq ishlatmadik? Hamma ishlatadi-ku." Qanday javob berasiz?
Javob
Qisqa javob: "Ishlatdik va o'lchadik. Tabular ma'lumotda u gradient boosting dan sezilarli ustun chiqmadi, shuning uchun soddaroq modelni tanladik."
Raqam bilan ko'rsating:
| Model | CV AUC | SE | O'rgatish vaqti | Sozlangan parametr |
|---|---|---|---|---|
| LogisticRegression | 0.78 | 0.006 | 0.1 s | 0 |
| HistGradientBoosting | 0.85 | 0.007 | 12 s | 3 |
| Neyron tarmoq | 0.851 | 0.009 | 180 s | 7 |
Juftlashgan farq: +0.001 ± 0.008 — ya'ni shovqin ichida.
Nima uchun bu tasodif emas:
Bu natija adabiyotda takroran o'lchangan:
- Grinsztajn va b. (2022) — 45 ta tabular ma'lumot to'plamida daraxtlar ustun chiqdi
- Shwartz-Ziv & Armon (2022) — xuddi shunday xulosa
Sabab — tabular ma'lumotning tabiatida: belgilar bir jinsli emas (yosh va daromad butunlay boshqa narsa), o'zaro ta'sirlar siyrak, va ma'lumotda ko'p tekis bo'lmagan (piecewise) bog'liqlik bor. Daraxtlar aynan shunga mos.
Tarmoqlar esa bir jinsli, tuzilmali signalda ustun: piksellar, tovush namunalari, so'zlar ketma-ketligi.
Qachon fikrni o'zgartiramiz:
- Ma'lumot 10 barobar ko'paysa — tarmoqlar hajm bilan yaxshi masshtablanadi
- Yangi modallik qo'shilsa — matn izohlari, rasmlar, audio
- Embedding kerak bo'lsa — juda ko'p darajali kategoriyalar (masalan 100 000 mahsulot)
- Ko'p vazifali o'rgatish kerak bo'lsa — bitta model bir necha chiqish beradi
- Transfer learning imkoni paydo bo'lsa
Nima qilganimizni ayting:
"Tarmoqni jiddiy sinadik: arxitekturani qadamma-qadam kattalashtirdik,
dropout,weight decayva erta to'xtashni sozladik, 5 ta seed bilan tekshirdik. Natija0.851 ± 0.009—HistGBning0.850 ± 0.007idan farqi yo'q. Lekin tarmoq 15 barobar sekin o'rgatiladi, sozlashga ikki hafta ketdi va uni tushuntirish qiyinroq."
Muhim ohang: "tarmoq yomon" demang. "Bu vazifada foyda bermadi, mana o'lchov" deng. Va qachon qayta ko'rib chiqishni aniq ayting.
Qo'shimcha imkoniyat: ansambl. Ikkala modelning bashoratlarini o'rtachalash ko'pincha ikkalasidan ham yaxshiroq chiqadi, chunki ular turli xatolar qiladi. Buni ham o'lchab ko'rish arziydi.
Nimani mustahkamlaydi: 2.1, 2.5-bo'limlar.
Xulosa
Bu darsda to'liq neyron tarmoq loyihasini qurdik.
Eng muhim uch fikr:
Tabular ma'lumotda tarmoq avtomatik tanlov emas. Bazaviy sifatida
HistGradientBoostingni qo'yish majburiy, chunki u ko'pincha tarmoqdan yaxshiroq, tezroq va sozlashga osonroq. Bu shaxsiy fikr emas — 2022-yilda o'nlab ma'lumot to'plamida o'lchangan natija. Tarmoqni tanlash uchun uning ustunligini2*SEdan ortiq ko'rsatish kerak.Tashxis o'rgatishdan oldin boshlanadi. Boshlang'ich loss
log(K)ga tengmi, har qatlamstdsi 1 atrofidami, kirish masshtablanganmi, yorliqlar0..K-1mi — bu to'rt tekshiruv bir necha soniya oladi va soatlab qidiruvni oldini oladi. O'rgatish davomida esa gradient normasi, o'lgan neyron ulushi va ikkala loss kuzatiladi.Natija — model emas, artefakt.
state_dict, arxitektura ta'rifi, masshtablovchi, belgilar tartibi, metrikalar, versiyalar va nazorat namunasi — hammasi bitta paketda. Yuklashdan keyinmodel.eval()chaqirish shart, aks holdadropoutfaol qoladi va bashoratlar tasodifiy bo'ladi.
Bu bilan 20-qism — Neyron tarmoqlar yakunlandi. Biz neyronning ichidan boshlab, to'liq loyihagacha bordik: aktivatsiya, arxitektura, oldinga va orqaga tarqalish, loss, optimizatorlar, boshlanish, normalizatsiya, tensorlar, regularizatsiya va o'rgatish sikli.
Keyingi qismda PyTorchni to'liq o'rganamiz: nn.Module bilan o'z qatlamlaringizni qurish, Dataset va DataLoader, GPU, modelni saqlash va yuklash, va katta loyihalarni tashkil qilish.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!