Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Siklning tuzilishi
- 2.2. train va eval
- 2.3. Batch va davr
- 2.4. Metrikalarni to'g'ri yig'ish
- 2.5. Loglash va kuzatish
- 2.6. Takrorlanuvchanlik
- 2.7. Tuzoqlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Siklni qadamma-qadam qurish
- Misol 2 — train va eval rejimlari
- Misol 3 — Loglash va o'rgatish egri chizig'i
- Misol 4 — To'liq o'rgatuvchi va sklearn bilan tekshiruv
- 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.11-dars: Birinchi to'liq tarmoq
20-QISM — NEYRON TARMOQLAR · 11-dars
1. Kirish va motivatsiya
Bo'laklar tayyor: neyron, aktivatsiya, arxitektura, oldinga o'tish, loss, backprop, optimizator, boshlanish, tensorlar, regularizatsiya. Endi ularni bitta o'rgatish sikliga yig'amiz.
O'rgatish sikli — chuqur o'rganishdagi eng ko'p yoziladigan kod. Uning tuzilishi hamma joyda bir xil: batchlar bo'ylab yurish, loss ni hisoblash, orqaga qaytish, qadam tashlash, davr oxirida validatsiya qilish. Shu besh qadam MNIST dan GPT gacha o'zgarmaydi.
Lekin sikl atrofida juda ko'p detal bor: train() va eval() rejimlari, zero_grad ning o'rni, metrikalarni to'g'ri yig'ish, jadvalni qachon qadamlash, erta to'xtash va eng yaxshi holatni saqlash. Bu detallar o'tkazib yuborilganda kod "ishlayotgandek" ko'rinadi, lekin natija noto'g'ri bo'ladi.
Bu darsda siklni qadamma-qadam quramiz va har detalning nima uchun kerakligini ko'rsatamiz. Oxirida sklearn bilan solishtirib, tarmoq haqiqatan ishlayotganini tekshiramiz.
Real vaziyat. Muhandis o'rgatish siklini yozdi, model 0.94 aniqlik berdi. Ishlab chiqarishda 0.71 chiqdi. Sabab: model.eval() chaqirilmagan va BatchNorm test batchining statistikasidan foydalangan. Bir qator kod — 0.23 aniqlik.
Bu darsda to'liq o'rgatish siklini quramiz.
Bu darsda:
- O'rgatish siklining tuzilishi
- train va eval rejimlari
- Batch va davr
- Metrikalarni to'g'ri yig'ish
- Loglash va kuzatish
- Tuzoqlar
- Amaliy: to'liq sikl
ℹ Misollar real torch/sklearn bilan (Python 3.14, torch 2.14 CPU).
2. Nazariya — chuqur tushuntirish
2.1. Siklning tuzilishi
for davr in range(davrlar):
# --- O'RGATISH ---
model.train() # dropout/BN yoqiladi
for Xb, yb in oquv_batchlari:
opt.zero_grad() # oldingi gradientni tozalash
chiqish = model(Xb) # oldinga
loss = kriteriy(chiqish, yb) # loss
loss.backward() # orqaga
opt.step() # qadam
# --- VALIDATSIYA ---
model.eval() # dropout/BN o'chiriladi
with torch.no_grad(): # graf qurilmaydi
for Xb, yb in val_batchlari:
... # metrikalarni yig'ish
jadval.step() # lr ni yangilash
# erta to'xtash tekshiruvi Besh qadam: zero_grad → forward → loss → backward → step. Tartib qat'iy.
2.2. train va eval
model.train():
Dropout -> FAOL (neyronlar o'chiriladi)
BatchNorm -> batch statistikasini ishlatadi VA harakatlanuvchini yangilaydi
model.eval():
Dropout -> o'chiriladi (hech narsa tushmaydi)
BatchNorm -> HARAKATLANUVCHI statistikani ishlatadi
UNUTILSA NIMA BO'LADI:
eval() siz bashorat -> dropout faol -> TASODIFIY natija
train() siz o'rgatish -> BN statistikasi yangilanmaydi
no_grad() BOSHQA NARSA:
u graf qurilishini to'xtatadi (xotira/tezlik)
rejimni O'ZGARTIRMAYDI
DEMAK BAHOLASHDA IKKALASI HAM KERAK:
model.eval()
with torch.no_grad(): eval() va no_grad() — ikki boshqa narsa; baholashda ikkalasi ham kerak.
2.3. Batch va davr
DAVR (epoch): butun o'quv to'plamidan bir marta o'tish
BATCH: bir qadamda ishlatiladigan namunalar
qadamlar_soni = ceil(N / batch)
HAR DAVRDA ARALASHTIRISH SHART:
aralashtirilmasa batchlar har davrda bir xil bo'ladi
-> gradient shovqini tuzilmali bo'lib qoladi
-> yaqinlashish yomonlashadi
OXIRGI BATCH:
N batch ga bo'linmasa oxirgisi kichik bo'ladi
drop_last=True - uni tashlab yuborish (BatchNorm uchun foydali)
VALIDATSIYADA ARALASHTIRISH KERAK EMASHar davrda aralashtiring — bu bir qator, lekin sezilarli farq beradi.
2.4. Metrikalarni to'g'ri yig'ish
XATO:
loss_jami += loss.item()
o'rtacha = loss_jami / batchlar_soni <- oxirgi batch kichik bo'lsa NOTO'G'RI
TO'G'RI (namunalar bo'yicha vaznlangan):
loss_jami += loss.item() * len(Xb)
o'rtacha = loss_jami / N
ANIQLIK:
togri += (chiqish.argmax(1) == yb).sum().item()
aniqlik = togri / N
DIQQAT: .item() SHART -
tensorni yig'sangiz butun graf xotirada qoladi (20.9-dars)Metrikani namunalar soni bo'yicha vaznlang, batchlar soni bo'yicha emas.
2.5. Loglash va kuzatish
HAR DAVRDA YOZILADI:
davr raqami
o'quv loss, validatsiya loss
o'quv metrika, validatsiya metrika
joriy lr
davr vaqti (ixtiyoriy)
NIMA IZLAYMIZ:
val_loss o'smoqdami -> yodlash
train_loss tushmayaptimi -> lr yoki arxitektura muammosi
ikkalasi ham yuqorimi -> yetarsiz o'rganish
keskin sakrashlar -> lr juda katta
EGRI CHIZIQLARNI CHIZING: jadval raqamlaridan ko'ra tezroq o'qiladi
EPS: bir necha davrda hech narsa o'zgarmasa - to'xtating va tekshiringHar davrda ikkala loss ni ham yozing — bittasi hech narsa aytmaydi.
2.6. Takrorlanuvchanlik
torch.manual_seed(0)
np.random.seed(0)
random.seed(0)
DataLoader uchun:
generator = torch.Generator().manual_seed(0)
DataLoader(..., generator=generator, worker_init_fn=...)
TO'LIQ DETERMINIZM (sekinroq):
torch.use_deterministic_algorithms(True)
torch.backends.cudnn.deterministic = True
AMALDA: bitta seed yetarli emas -
bir necha seed bilan ishga tushirib, O'RTACHA va STD ni bering
(18.3-dars: bitta natija - bu bitta namuna)Bitta seed natijasi — bitta namuna; muhim qarorlarni bir necha yurish asosida qabul qiling.
2.7. Tuzoqlar
Asosiy tuzoqlar: eval() ni unutish; zero_grad ni noto'g'ri joyga qo'yish; loss ni batchlar soni bo'yicha o'rtachalash; validatsiyani no_grad siz qilish; har davrda aralashtirmaslik; jadvalni har batchda qadamlash (agar u davr uchun mo'ljallangan bo'lsa); erta to'xtashni test to'plamida qilish; metrikalarni tensor holida yig'ish.
3. Tez ma'lumotnoma
import torch
def davr_orgat(model, yuklovchi, opt, kriteriy):
model.train()
jami, n = 0.0, 0
for Xb, yb in yuklovchi:
opt.zero_grad()
loss = kriteriy(model(Xb), yb)
loss.backward()
opt.step()
jami += loss.item() * len(Xb)
n += len(Xb)
return jami / n
@torch.no_grad()
def bahola(model, yuklovchi, kriteriy):
model.eval()
jami, togri, n = 0.0, 0, 0
for Xb, yb in yuklovchi:
chiqish = model(Xb)
jami += kriteriy(chiqish, yb).item() * len(Xb)
togri += (chiqish.argmax(1) == yb).sum().item()
n += len(Xb)
return jami / n, togri / nSikl xulosasi
train() -> batchlar -> zero_grad/forward/loss/backward/step
eval() + no_grad() -> validatsiya
metrikani NAMUNA soni bo'yicha vaznlang
har davrda aralashtiring
eng yaxshi holatni saqlang4. Batafsil misollar
Misollar real torch/sklearn bilan (Python 3.14, torch 2.14 CPU).
Misol 1 — Siklni qadamma-qadam qurish
"""Besh qadam va ularning tartibi (real torch)."""
import torch
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
def main() -> None:
torch.manual_seed(0)
X, y = make_classification(n_samples=2000, n_features=16,
n_informative=8, n_redundant=3,
n_classes=3, flip_y=0.1, class_sep=1.0,
random_state=0)
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3,
random_state=0, stratify=y)
sc = StandardScaler().fit(Xtr)
Xtr_t = torch.tensor(sc.transform(Xtr), dtype=torch.float32)
Xte_t = torch.tensor(sc.transform(Xte), dtype=torch.float32)
ytr_t = torch.tensor(ytr, dtype=torch.int64)
yte_t = torch.tensor(yte, dtype=torch.int64)
model = torch.nn.Sequential(
torch.nn.Linear(16, 64), torch.nn.ReLU(),
torch.nn.Linear(64, 32), torch.nn.ReLU(),
torch.nn.Linear(32, 3))
opt = torch.optim.AdamW(model.parameters(), lr=0.01,
weight_decay=1e-4)
kriteriy = torch.nn.CrossEntropyLoss()
print("=== 1. Bitta qadam, ochiq ===")
Xb, yb = Xtr_t[:64], ytr_t[:64]
print(f" {'bosqich':<22} {'holat'}")
print(f" {'0. boshlang_ich grad':<22} "
f"{model[0].weight.grad}")
opt.zero_grad()
chiqish = model(Xb)
print(f" {'1. zero_grad()':<22} tozalandi")
print(f" {'2. forward':<22} chiqish shakli "
f"{tuple(chiqish.shape)}")
loss = kriteriy(chiqish, yb)
print(f" {'3. loss':<22} {loss.item():.6f}")
loss.backward()
print(f" {'4. backward()':<22} grad normasi "
f"{model[0].weight.grad.norm().item():.6f}")
eski = model[0].weight.detach().clone()
opt.step()
ozgarish = (model[0].weight.detach() - eski).norm().item()
print(f" {'5. step()':<22} og'irlik {ozgarish:.6f} ga o'zgardi")
print("\n=== 2. zero_grad ni unutsak ===")
m2 = torch.nn.Linear(4, 2)
Xk = torch.randn(8, 4)
yk = torch.randint(0, 2, (8,))
print(f" {'qadam':>6} {'zero_grad BOR':>16} {'zero_grad YO_Q':>17}")
m3 = torch.nn.Linear(4, 2)
m3.load_state_dict(m2.state_dict())
for i in range(1, 5):
m2.zero_grad()
kriteriy(m2(Xk), yk).backward()
n1 = m2.weight.grad.norm().item()
kriteriy(m3(Xk), yk).backward()
n2 = m3.weight.grad.norm().item()
print(f" {i:>6} {n1:>16.6f} {n2:>17.6f}")
print(" tozalamasak gradient har qadamda YIG'ILADI")
print("\n=== 3. Batch bo'ylab bitta davr ===")
g = torch.Generator().manual_seed(0)
tartib = torch.randperm(len(ytr_t), generator=g)
batch = 128
jami, n = 0.0, 0
print(f" {'batch':>6} {'hajm':>6} {'loss':>10} "
f"{'yig_ilgan o_rtacha':>20}")
for k, boshi in enumerate(range(0, len(ytr_t), batch)):
idx = tartib[boshi:boshi + batch]
opt.zero_grad()
loss = kriteriy(model(Xtr_t[idx]), ytr_t[idx])
loss.backward()
opt.step()
jami += loss.item() * len(idx)
n += len(idx)
if k < 3 or boshi + batch >= len(ytr_t):
print(f" {k:>6} {len(idx):>6} {loss.item():>10.4f} "
f"{jami / n:>20.4f}")
print(f" davr loss: {jami / n:.4f} ({n} namuna)")
print("\n=== 4. Noto'g'ri o'rtachalash ===")
kichik = torch.tensor([0.5, 0.5, 0.5, 5.0]) # oxirgi batch
hajmlar = torch.tensor([128, 128, 128, 4])
print(f" batch loss lari: {kichik.tolist()}")
print(f" batch hajmlari: {hajmlar.tolist()}")
print(f" batchlar bo'yicha (NOTO'G'RI): "
f"{kichik.mean().item():.4f}")
print(f" namunalar bo'yicha (TO'G'RI): "
f"{(kichik * hajmlar).sum().item() / hajmlar.sum().item():.4f}")
print(" kichik oxirgi batch natijani BUZADI")
print("\n=== 5. To'liq sikl ===")
torch.manual_seed(0)
model = torch.nn.Sequential(
torch.nn.Linear(16, 64), torch.nn.ReLU(),
torch.nn.Linear(64, 32), torch.nn.ReLU(),
torch.nn.Linear(32, 3))
opt = torch.optim.AdamW(model.parameters(), lr=0.01,
weight_decay=1e-4)
print(f" {'davr':>6} {'o_quv loss':>12} {'test loss':>11} "
f"{'test aniqlik':>13}")
for davr in range(1, 41):
model.train()
tartib = torch.randperm(len(ytr_t), generator=g)
jami, n = 0.0, 0
for boshi in range(0, len(ytr_t), batch):
idx = tartib[boshi:boshi + batch]
opt.zero_grad()
loss = kriteriy(model(Xtr_t[idx]), ytr_t[idx])
loss.backward()
opt.step()
jami += loss.item() * len(idx)
n += len(idx)
if davr in (1, 5, 10, 20, 40):
model.eval()
with torch.no_grad():
chiqish = model(Xte_t)
te_loss = kriteriy(chiqish, yte_t).item()
aniq = (chiqish.argmax(1)
== yte_t).float().mean().item()
print(f" {davr:>6} {jami / n:>12.4f} {te_loss:>11.4f} "
f"{aniq:>13.4f}")
print(" ⭐ Besh qadam + aralashtirish + baholash")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Bitta qadam, ochiq ===
bosqich holat
0. boshlang_ich grad None
1. zero_grad() tozalandi
2. forward chiqish shakli (64, 3)
3. loss 1.100298
4. backward() grad normasi 0.072048
5. step() og'irlik 0.319961 ga o'zgardi
=== 2. zero_grad ni unutsak ===
qadam zero_grad BOR zero_grad YO_Q
1 0.461770 0.461770
2 0.461770 0.923539
3 0.461770 1.385309
4 0.461770 1.847079
tozalamasak gradient har qadamda YIG'ILADI
=== 3. Batch bo'ylab bitta davr ===
batch hajm loss yig_ilgan o_rtacha
0 128 1.0775 1.0775
1 128 1.0250 1.0513
2 128 0.9808 1.0278
10 120 0.7638 0.8924
davr loss: 0.8924 (1400 namuna)
=== 4. Noto'g'ri o'rtachalash ===
batch loss lari: [0.5, 0.5, 0.5, 5.0]
batch hajmlari: [128, 128, 128, 4]
batchlar bo'yicha (NOTO'G'RI): 1.6250
namunalar bo'yicha (TO'G'RI): 0.5464
kichik oxirgi batch natijani BUZADI
=== 5. To'liq sikl ===
davr o_quv loss test loss test aniqlik
1 0.9112 0.8467 0.6383
5 0.5621 0.6838 0.7533
10 0.4611 0.7205 0.7483
20 0.2956 0.8465 0.7133
40 0.0962 1.2832 0.6917
⭐ Besh qadam + aralashtirish + baholashNima ko'rsatdi: 2.1, 2.3, 2.4-bo'limlar.
Misol 2 — train va eval rejimlari
"""Rejimlarni unutishning narxi (real torch)."""
import torch
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
def yasa(seed=0):
torch.manual_seed(seed)
return torch.nn.Sequential(
torch.nn.Linear(16, 64),
torch.nn.BatchNorm1d(64),
torch.nn.ReLU(),
torch.nn.Dropout(0.4),
torch.nn.Linear(64, 3))
def main() -> None:
X, y = make_classification(n_samples=2000, n_features=16,
n_informative=8, n_redundant=3,
n_classes=3, flip_y=0.1, class_sep=1.0,
random_state=0)
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3,
random_state=0, stratify=y)
sc = StandardScaler().fit(Xtr)
Xtr_t = torch.tensor(sc.transform(Xtr), dtype=torch.float32)
Xte_t = torch.tensor(sc.transform(Xte), dtype=torch.float32)
ytr_t = torch.tensor(ytr, dtype=torch.int64)
yte_t = torch.tensor(yte, dtype=torch.int64)
model = yasa()
opt = torch.optim.AdamW(model.parameters(), lr=0.01)
kriteriy = torch.nn.CrossEntropyLoss()
g = torch.Generator().manual_seed(0)
for _ in range(60):
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()
print("=== 1. Bir xil kirish, ikki rejim ===")
model.train()
with torch.no_grad():
t1 = model(Xte_t[:4])
t2 = model(Xte_t[:4])
model.eval()
with torch.no_grad():
e1 = model(Xte_t[:4])
e2 = model(Xte_t[:4])
print(f" train() da ikki yurish bir xilmi: "
f"{torch.allclose(t1, t2)}")
print(f" eval() da ikki yurish bir xilmi: "
f"{torch.allclose(e1, e2)}")
print(f" train() va eval() farqi (o'rtacha): "
f"{(t1 - e1).abs().mean().item():.4f}")
print("\n=== 2. Aniqlikdagi farq ===")
def aniqlik(rejim):
if rejim == "train":
model.train()
else:
model.eval()
with torch.no_grad():
return (model(Xte_t).argmax(1)
== yte_t).float().mean().item()
print(f" {'rejim':<10} {'test aniqlik':>13}")
for rejim in ["train", "eval"]:
print(f" {rejim:<10} {aniqlik(rejim):>13.4f}")
print(f" farq: {aniqlik('eval') - aniqlik('train'):+.4f}")
print("\n=== 3. train() da natija barqaror emas ===")
model.train()
ballar = []
for _ in range(10):
with torch.no_grad():
ballar.append((model(Xte_t).argmax(1)
== yte_t).float().mean().item())
print(f" 10 yurish: min {min(ballar):.4f}, max {max(ballar):.4f}")
print(f" o'rtacha {sum(ballar) / 10:.4f}, "
f"tarqoqlik {max(ballar) - min(ballar):.4f}")
print("\n=== 4. BatchNorm statistikasi ===")
bn = model[1]
print(f" harakatlanuvchi o'rtacha (birinchi 4): "
f"{bn.running_mean[:4].tolist()}")
print(f" harakatlanuvchi dispersiya (birinchi 4): "
f"{[round(v, 4) for v in bn.running_var[:4].tolist()]}")
print(f" kuzatilgan batchlar: {int(bn.num_batches_tracked)}")
print("\n=== 5. Kichik batchda BatchNorm ===")
model.eval()
with torch.no_grad():
togri_bashorat = model(Xte_t[:3])
model.train()
with torch.no_grad():
xato_bashorat = model(Xte_t[:3])
print(f" 3 namunali kirish:")
print(f" {'namuna':>7} {'eval() (to_g_ri)':<28} "
f"{'train() (xato)':<28}")
for i in range(3):
print(f" {i:>7} {str([round(v, 3) for v in togri_bashorat[i].tolist()]):<28} "
f"{str([round(v, 3) for v in xato_bashorat[i].tolist()]):<28}")
print("\n=== 6. no_grad va eval boshqa narsa ===")
model.train()
with torch.no_grad():
a = model(Xte_t[:8])
print(f" train() + no_grad():")
print(f" grad_fn: "
f"{type(a.grad_fn).__name__ if a.grad_fn else 'None'}")
print(f" dropout faolmi: HA (rejim train)")
model.eval()
b = model(Xte_t[:8])
print(f" eval() + no_grad SIZ:")
print(f" grad_fn: "
f"{type(b.grad_fn).__name__ if b.grad_fn else 'None'}")
print(f" dropout faolmi: YO'Q (rejim eval)")
print(" ⭐ Baholashda IKKALASI ham kerak")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Bir xil kirish, ikki rejim ===
train() da ikki yurish bir xilmi: False
eval() da ikki yurish bir xilmi: True
train() va eval() farqi (o'rtacha): 0.9344
=== 2. Aniqlikdagi farq ===
rejim test aniqlik
train 0.7050
eval 0.7483
farq: +0.0450
=== 3. train() da natija barqaror emas ===
10 yurish: min 0.6900, max 0.7283
o'rtacha 0.7115, tarqoqlik 0.0383
=== 4. BatchNorm statistikasi ===
harakatlanuvchi o'rtacha (birinchi 4): [-0.04862187057733536, -0.17329974472522736, -0.12270306795835495, 0.17733359336853027]
harakatlanuvchi dispersiya (birinchi 4): [1.0472, 1.4632, 1.1927, 0.812]
kuzatilgan batchlar: 674
=== 5. Kichik batchda BatchNorm ===
3 namunali kirish:
namuna eval() (to_g_ri) train() (xato)
0 [-0.254, -0.298, 0.157] [1.461, -2.733, 0.166]
1 [0.519, 0.523, -1.983] [-0.579, 0.75, -1.421]
2 [-0.932, 2.773, -3.562] [-0.745, 2.413, -3.694]
=== 6. no_grad va eval boshqa narsa ===
train() + no_grad():
grad_fn: None
dropout faolmi: HA (rejim train)
eval() + no_grad SIZ:
grad_fn: AddmmBackward0
dropout faolmi: YO'Q (rejim eval)
⭐ Baholashda IKKALASI ham kerakNima ko'rsatdi: 2.2-bo'lim.
Misol 3 — Loglash va o'rgatish egri chizig'i
"""Nima yoziladi va u nima haqida gapiradi (real torch)."""
import numpy as np
import torch
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
def tayyorla(n=1600, seed=0):
X, y = make_classification(n_samples=n, n_features=20,
n_informative=8, n_redundant=4,
n_classes=3, flip_y=0.15, class_sep=0.8,
random_state=seed)
Xtr, Xva, ytr, yva = train_test_split(X, y, test_size=0.35,
random_state=0, stratify=y)
sc = StandardScaler().fit(Xtr)
T = lambda M: torch.tensor(sc.transform(M), dtype=torch.float32)
return (T(Xtr), torch.tensor(ytr, dtype=torch.int64),
T(Xva), torch.tensor(yva, dtype=torch.int64))
def orgat(Xtr, ytr, Xva, yva, lr=0.01, kenglik=256, davrlar=80):
torch.manual_seed(0)
model = torch.nn.Sequential(
torch.nn.Linear(20, kenglik), torch.nn.ReLU(),
torch.nn.Linear(kenglik, kenglik), torch.nn.ReLU(),
torch.nn.Linear(kenglik, 3))
opt = torch.optim.AdamW(model.parameters(), lr=lr,
weight_decay=1e-6)
kriteriy = torch.nn.CrossEntropyLoss()
g = torch.Generator().manual_seed(0)
tarix = []
for davr in range(1, davrlar + 1):
model.train()
tartib = torch.randperm(len(ytr), generator=g)
jami, n = 0.0, 0
for boshi in range(0, len(ytr), 128):
idx = tartib[boshi:boshi + 128]
opt.zero_grad()
loss = kriteriy(model(Xtr[idx]), ytr[idx])
loss.backward()
opt.step()
jami += loss.item() * len(idx)
n += len(idx)
model.eval()
with torch.no_grad():
chiqish = model(Xva)
va_loss = kriteriy(chiqish, yva).item()
va_aniq = (chiqish.argmax(1) == yva).float().mean().item()
tr_aniq = (model(Xtr).argmax(1) == ytr).float().mean().item()
tarix.append((davr, jami / n, va_loss, tr_aniq, va_aniq))
return tarix
def main() -> None:
Xtr, ytr, Xva, yva = tayyorla()
print(f" o'quv {len(ytr)}, validatsiya {len(yva)}")
print("\n=== 1. Normal o'rgatish jurnali ===")
tarix = orgat(Xtr, ytr, Xva, yva)
print(f" {'davr':>6} {'o_quv loss':>12} {'val loss':>10} "
f"{'o_quv aniq':>12} {'val aniq':>10}")
for satr in tarix:
if satr[0] in (1, 5, 10, 20, 40, 80):
print(f" {satr[0]:>6} {satr[1]:>12.4f} {satr[2]:>10.4f} "
f"{satr[3]:>12.4f} {satr[4]:>10.4f}")
print("\n=== 2. Nimani ko'ryapmiz ===")
val_loss = [t[2] for t in tarix]
eng_davr = int(np.argmin(val_loss)) + 1
print(f" eng past val loss: {min(val_loss):.4f} "
f"({eng_davr}-davr)")
print(f" oxirgi val loss: {val_loss[-1]:.4f}")
print(f" o'sish: {val_loss[-1] - min(val_loss):+.4f}")
print(f" oxirgi o'quv/val aniqlik farqi: "
f"{tarix[-1][3] - tarix[-1][4]:+.4f}")
print(" val loss eng past nuqtadan keyin O'SDI -> yodlash")
print("\n=== 3. lr juda katta ===")
tarix2 = orgat(Xtr, ytr, Xva, yva, lr=0.5, davrlar=20)
print(f" {'davr':>6} {'o_quv loss':>12} {'val loss':>10} "
f"{'val aniq':>10}")
for satr in tarix2:
if satr[0] in (1, 2, 5, 10, 20):
print(f" {satr[0]:>6} {satr[1]:>12.4f} {satr[2]:>10.4f} "
f"{satr[4]:>10.4f}")
print(" loss sakraydi va tushmaydi - lr ni kamaytiring")
print("\n=== 4. lr juda kichik ===")
tarix3 = orgat(Xtr, ytr, Xva, yva, lr=1e-5, davrlar=20)
print(f" {'davr':>6} {'o_quv loss':>12} {'val loss':>10} "
f"{'val aniq':>10}")
for satr in tarix3:
if satr[0] in (1, 5, 10, 20):
print(f" {satr[0]:>6} {satr[1]:>12.4f} {satr[2]:>10.4f} "
f"{satr[4]:>10.4f}")
print(f" 20 davrda loss atigi "
f"{tarix3[0][1] - tarix3[-1][1]:.4f} ga tushdi")
print("\n=== 5. Model juda kichik ===")
tarix4 = orgat(Xtr, ytr, Xva, yva, kenglik=2, davrlar=40)
print(f" {'davr':>6} {'o_quv aniq':>12} {'val aniq':>10} "
f"{'farq':>8}")
for satr in tarix4:
if satr[0] in (1, 10, 20, 40):
print(f" {satr[0]:>6} {satr[3]:>12.4f} {satr[4]:>10.4f} "
f"{satr[3] - satr[4]:>8.4f}")
print(" ikkalasi ham past, farq kichik -> YETARSIZ o'rganish")
print("\n=== 6. To'rt holatni ajratish ===")
holatlar = [
("normal", tarix[19][3], tarix[19][4]),
("yodlash", tarix[-1][3], tarix[-1][4]),
("lr katta", tarix2[-1][3], tarix2[-1][4]),
("yetarsiz", tarix4[-1][3], tarix4[-1][4]),
]
print(f" {'holat':<12} {'o_quv':>8} {'val':>8} {'farq':>8} "
f"{'tashxis'}")
for nom, tr, va in holatlar:
tashxis = ("yodlash" if tr - va > 0.08
else "yetarsiz" if tr < 0.6 else "yaxshi")
print(f" {nom:<12} {tr:>8.4f} {va:>8.4f} {tr - va:>8.4f} "
f"{tashxis}")
print(" ⭐ Ikkala ballni birga ko'rish tashxis beradi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
o'quv 1040, validatsiya 560
=== 1. Normal o'rgatish jurnali ===
davr o_quv loss val loss o_quv aniq val aniq
1 0.9748 0.8056 0.6913 0.6214
5 0.5268 0.7393 0.8317 0.7089
10 0.3135 0.8488 0.9221 0.7000
20 0.0542 1.4307 0.9923 0.7143
40 0.0014 1.9917 1.0000 0.7000
80 0.0003 2.2928 1.0000 0.7018
=== 2. Nimani ko'ryapmiz ===
eng past val loss: 0.7149 (4-davr)
oxirgi val loss: 2.2928
o'sish: +1.5779
oxirgi o'quv/val aniqlik farqi: +0.2982
val loss eng past nuqtadan keyin O'SDI -> yodlash
=== 3. lr juda katta ===
davr o_quv loss val loss val aniq
1 1601.2189 407.7646 0.2482
2 188.6824 22.1733 0.4536
5 1.1238 1.1354 0.3429
10 1.0614 1.1001 0.3589
20 1.0423 1.1051 0.3696
loss sakraydi va tushmaydi - lr ni kamaytiring
=== 4. lr juda kichik ===
davr o_quv loss val loss val aniq
1 1.1114 1.1133 0.3054
5 1.1028 1.1056 0.2929
10 1.0933 1.0969 0.3196
20 1.0755 1.0808 0.4357
20 davrda loss atigi 0.0360 ga tushdi
=== 5. Model juda kichik ===
davr o_quv aniq val aniq farq
1 0.4173 0.4018 0.0155
10 0.5827 0.5607 0.0220
20 0.6096 0.5732 0.0364
40 0.6644 0.6107 0.0537
ikkalasi ham past, farq kichik -> YETARSIZ o'rganish
=== 6. To'rt holatni ajratish ===
holat o_quv val farq tashxis
normal 0.9923 0.7143 0.2780 yodlash
yodlash 1.0000 0.7018 0.2982 yodlash
lr katta 0.3779 0.3696 0.0082 yetarsiz
yetarsiz 0.6644 0.6107 0.0537 yaxshi
⭐ Ikkala ballni birga ko'rish tashxis beradiNima ko'rsatdi: 2.5-bo'lim.
Misol 4 — To'liq o'rgatuvchi va sklearn bilan tekshiruv
"""Erta to'xtash, jadval va sklearn bilan solishtirish."""
import warnings
import numpy as np
import torch
from sklearn.datasets import make_classification
from sklearn.exceptions import ConvergenceWarning
from sklearn.metrics import accuracy_score, log_loss
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.preprocessing import StandardScaler
class Orgatuvchi:
def __init__(self, kirish, sinflar, kenglik=64, lr=0.01,
wd=1e-4, dropout=0.2, seed=0):
torch.manual_seed(seed)
self.model = 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, sinflar))
self.opt = torch.optim.AdamW(self.model.parameters(), lr=lr,
weight_decay=wd)
self.kriteriy = torch.nn.CrossEntropyLoss()
self.g = torch.Generator().manual_seed(seed)
self.tarix = []
def davr(self, X, y, batch=128):
self.model.train()
tartib = torch.randperm(len(y), generator=self.g)
jami, n = 0.0, 0
for boshi in range(0, len(y), batch):
idx = tartib[boshi:boshi + batch]
self.opt.zero_grad()
loss = self.kriteriy(self.model(X[idx]), y[idx])
loss.backward()
self.opt.step()
jami += loss.item() * len(idx)
n += len(idx)
return jami / n
@torch.no_grad()
def bahola(self, X, y):
self.model.eval()
chiqish = self.model(X)
return (self.kriteriy(chiqish, y).item(),
(chiqish.argmax(1) == y).float().mean().item())
def orgat(self, Xtr, ytr, Xva, yva, davrlar=200, sabr=20):
jadval = torch.optim.lr_scheduler.CosineAnnealingLR(
self.opt, T_max=davrlar)
eng, eng_holat, eng_davr, hisob = float("inf"), None, 0, 0
for davr in range(1, davrlar + 1):
tr_loss = self.davr(Xtr, ytr)
va_loss, va_aniq = self.bahola(Xva, yva)
self.tarix.append((davr, tr_loss, va_loss, va_aniq,
jadval.get_last_lr()[0]))
jadval.step()
if va_loss < eng - 1e-4:
eng, eng_davr, hisob = va_loss, davr, 0
eng_holat = {k: v.clone() for k, v
in self.model.state_dict().items()}
else:
hisob += 1
if hisob >= sabr:
break
if eng_holat is not None:
self.model.load_state_dict(eng_holat)
return davr, eng_davr
@torch.no_grad()
def ehtimollik(self, X):
self.model.eval()
return torch.softmax(self.model(X), dim=1).numpy()
def main() -> None:
X, y = make_classification(n_samples=5000, n_features=24,
n_informative=12, n_redundant=5,
n_classes=4, flip_y=0.1, class_sep=1.0,
random_state=0)
Xtr, Xrest, ytr, yrest = train_test_split(X, y, test_size=0.4,
random_state=0, stratify=y)
Xva, Xte, yva, yte = train_test_split(Xrest, yrest, test_size=0.5,
random_state=0, stratify=yrest)
sc = StandardScaler().fit(Xtr)
T = lambda M: torch.tensor(sc.transform(M), dtype=torch.float32)
Xtr_t, Xva_t, Xte_t = T(Xtr), T(Xva), T(Xte)
ytr_t = torch.tensor(ytr, dtype=torch.int64)
yva_t = torch.tensor(yva, dtype=torch.int64)
yte_t = torch.tensor(yte, dtype=torch.int64)
print(f" o'quv {len(ytr)}, validatsiya {len(yva)}, test {len(yte)}")
print("\n=== 1. O'rgatish ===")
o = Orgatuvchi(24, 4)
param = sum(p.numel() for p in o.model.parameters())
print(f" parametrlar: {param}")
tugagan, eng_davr = o.orgat(Xtr_t, ytr_t, Xva_t, yva_t)
print(f" {tugagan}-davrda to'xtadi, eng yaxshisi {eng_davr}-davr")
print("\n=== 2. Jurnal ===")
print(f" {'davr':>6} {'o_quv loss':>12} {'val loss':>10} "
f"{'val aniq':>10} {'lr':>10}")
for satr in o.tarix:
if satr[0] in (1, 5, 20, 50, eng_davr, tugagan):
print(f" {satr[0]:>6} {satr[1]:>12.4f} {satr[2]:>10.4f} "
f"{satr[3]:>10.4f} {satr[4]:>10.6f}")
print("\n=== 3. Yakuniy natijalar ===")
print(f" {'to_plam':<14} {'loss':>9} {'aniqlik':>9}")
for nom, Xq, yq in [("o'quv", Xtr_t, ytr_t),
("validatsiya", Xva_t, yva_t),
("test", Xte_t, yte_t)]:
l, a = o.bahola(Xq, yq)
print(f" {nom:<14} {l:>9.4f} {a:>9.4f}")
print("\n=== 4. sklearn bilan solishtirish ===")
with warnings.catch_warnings():
warnings.simplefilter("ignore", ConvergenceWarning)
m = MLPClassifier(hidden_layer_sizes=(64, 32), max_iter=400,
learning_rate_init=0.01, alpha=1e-4,
random_state=0, early_stopping=True,
n_iter_no_change=20,
validation_fraction=0.2).fit(
sc.transform(Xtr), ytr)
p_torch = o.ehtimollik(Xte_t)
p_sk = m.predict_proba(sc.transform(Xte))
print(f" {'model':<14} {'test aniqlik':>13} {'test log_loss':>15}")
print(f" {'torch':<14} "
f"{accuracy_score(yte, p_torch.argmax(1)):>13.4f} "
f"{log_loss(yte, p_torch):>15.4f}")
print(f" {'sklearn':<14} "
f"{accuracy_score(yte, p_sk.argmax(1)):>13.4f} "
f"{log_loss(yte, p_sk):>15.4f}")
print(f" bashoratlar mos kelishi: "
f"{(p_torch.argmax(1) == p_sk.argmax(1)).mean():.4f}")
print("\n=== 5. Bir necha seed ===")
ballar = []
for seed in range(5):
oo = Orgatuvchi(24, 4, seed=seed)
oo.orgat(Xtr_t, ytr_t, Xva_t, yva_t, davrlar=120, sabr=15)
ballar.append(oo.bahola(Xte_t, yte_t)[1])
ballar = np.array(ballar)
print(f" 5 ta seed: {ballar.round(4).tolist()}")
print(f" o'rtacha {ballar.mean():.4f}, std {ballar.std(ddof=1):.4f}")
print(f" SE: {ballar.std(ddof=1) / np.sqrt(5):.4f}")
print(" ⭐ Bitta yurish natijasi - bu bitta namuna")
if __name__ == "__main__":
main()Natijaning muhim qismi:
o'quv 3000, validatsiya 1000, test 1000
=== 1. O'rgatish ===
parametrlar: 3812
33-davrda to'xtadi, eng yaxshisi 13-davr
=== 2. Jurnal ===
davr o_quv loss val loss val aniq lr
1 1.1413 0.9618 0.6290 0.010000
5 0.7127 0.7448 0.7530 0.009990
13 0.5909 0.6973 0.7840 0.009911
20 0.5319 0.7147 0.7950 0.009779
33 0.4414 0.7595 0.8080 0.009382
=== 3. Yakuniy natijalar ===
to_plam loss aniqlik
o'quv 0.4909 0.8527
validatsiya 0.6973 0.7840
test 0.6821 0.7960
=== 4. sklearn bilan solishtirish ===
model test aniqlik test log_loss
torch 0.7960 0.6821
sklearn 0.7480 0.8097
bashoratlar mos kelishi: 0.8360
=== 5. Bir necha seed ===
5 ta seed: [0.796, 0.811, 0.8, 0.799, 0.792]
o'rtacha 0.7996, std 0.0071
SE: 0.0032
⭐ Bitta yurish natijasi - bu bitta namunaNima ko'rsatdi: 2.1, 2.6-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"no_grad() eval() o'rnini bosadi" |
Ikki boshqa narsa |
"zero_grad ixtiyoriy" |
Gradient yig'iladi |
| "Batchlar bo'yicha o'rtachalash to'g'ri" | Namunalar bo'yicha vaznlang |
| "Aralashtirish kichik detal" | Yaqinlashishga ta'sir qiladi |
| "Bitta seed yetarli" | Bu bitta namuna |
| "O'quv loss yetarli" | Ikkala loss ham kerak |
| "Jadval har batchda" | Ta'rifiga qarab |
| "Test to'plamida erta to'xtash" | Bu leakage |
6. Keng tarqalgan xatolar va yechimlari
1. eval() ni unutish
with torch.no_grad(): bashorat = model(X) # ⚠️ dropout faol
model.eval() # ✅
with torch.no_grad(): bashorat = model(X)2. zero_grad noto'g'ri joyda
for Xb, yb in yuklovchi:
loss.backward(); opt.step() # ⚠️
for Xb, yb in yuklovchi:
opt.zero_grad(); ... # ✅3. Noto'g'ri o'rtachalash
jami += loss.item(); o_rt = jami / batchlar # ⚠️
jami += loss.item() * len(Xb); o_rt = jami / n # ✅4. Aralashtirmaslik
for boshi in range(0, N, batch): idx = ... # ⚠️ har davr bir xil
tartib = torch.randperm(N, generator=g) # ✅5. Tensorni yig'ish
tarix.append(loss) # ⚠️ graf saqlanadi
tarix.append(loss.item()) # ✅6. train() ni qaytarmaslik
# baholashdan keyin to'g'ridan-to'g'ri o'rgatish # ⚠️
model.train() # har davr boshida # ✅7. Validatsiyada no_grad yo'q
for Xb, yb in val: chiqish = model(Xb) # ⚠️ xotira
with torch.no_grad(): ... # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 20.7, 20.9, 20.10-darslar (o'tilgan): Optimizator, tensorlar, regularizatsiya
- 20.12-dars: To'liq amaliyot
- 21-qism:
nn.Module,DataLoader, GPU - 23-qism va keyingilari: Barcha o'rgatish sikllari
8. Eng yaxshi amaliyotlar
Har davr boshida
train().Baholashda
eval()+no_grad().zero_gradni sikl boshida.Metrikani namunalar bo'yicha vaznlang.
Har davrda aralashtiring.
Ikkala loss ni ham yozing.
Eng yaxshi holatni saqlang.
Bir necha seed bilan tekshiring.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # siklning besh qadami?
2. # train() nima qiladi?
3. # eval() nima qiladi?
4. # no_grad() nima qiladi?
5. # baholashda nechtasi kerak?
6. # loss ni qanday o'rtachalash?
7. # aralashtirish qachon?
8. # qadamlar soni formulasi?
9. # drop_last nima uchun?
10. # jurnalda nima bo'ladi?
11. # val_loss o'ssa nima?
12. # bitta seed yetarlimi?Javoblar
zero_grad,forward,loss,backward,step- Dropout/BN ni o'rgatish rejimiga
- Ularni inference rejimiga
- Grafni qurmaydi
- Ikkalasi
- Namunalar bo'yicha vaznlab
- Har davrda
ceil(N / batch)- Kichik oxirgi batchni tashlash
- Davr, ikkala loss, metrika,
lr - Yodlash
- Yo'q
Vazifa 2: Xatolarni tuzating
1. with torch.no_grad(): bashorat = model(X)
2. jami += loss.item(); o_rt = jami / batchlar
3. for boshi in range(0, N, batch): idx = ...
4. tarix.append(loss)
5. for Xb, yb in val: chiqish = model(Xb)Javoblar
1. model.eval(); with torch.no_grad(): bashorat = model(X)
2. jami += loss.item() * len(Xb); o_rt = jami / n
3. tartib = torch.randperm(N, generator=g)
4. tarix.append(loss.item())
5. with torch.no_grad():
for Xb, yb in val: chiqish = model(Xb)Vazifa 3: Sikl
Modellang:
- Bitta qadam
- zero_grad
- Batch
- To'liq sikl
Vazifa 4: Rejimlar
Modellang:
- Ikki rejim
- Aniqlik
- Barqarorlik
- BatchNorm
Vazifa 5: Jurnal
Modellang:
- Normal
- lr katta
- lr kichik
- Model kichik
Vazifa 6: To'liq
Modellang:
- O'rgatish
- Jurnal
- Natijalar
- Seedlar
Vazifa 7: O'ylash
Siklingiz ishlayapti, lekin validatsiya balli o'quv ballidan yuqori chiqyapti. Bu mumkinmi va sabablari nima?
Javob
Ha, mumkin — va bu ko'pincha xato emas. Uch sabab bor, ikkitasi normal, bittasi muammo.
Sabab 1 (normal): dropout o'rgatishda faol
O'quv loss train() rejimida, dropout yoqilgan holda hisoblanadi — ya'ni zaiflashtirilgan model o'lchanadi. Validatsiya esa eval() rejimida, to'liq model bilan.
# to'g'ri taqqoslash uchun
model.eval()
with torch.no_grad():
tr_loss_halol = kriteriy(model(Xtr), ytr).item()
print(tr_loss_halol, va_loss) # endi taqqoslash mumkindropout=0.5 bo'lsa bu farq sezilarli bo'ladi.
Sabab 2 (normal): o'quv loss davr davomida o'rtachalanadi
Sikl ichida tr_loss butun davr bo'ylab yig'iladi — birinchi batchlar yomonroq modeldan olingan. Validatsiya esa davr oxirida, eng yaxshi holatda o'lchanadi.
Ya'ni siz "davr o'rtasidagi model" va "davr oxiridagi model" ni solishtiryapsiz.
Sabab 3 (muammo): validatsiya to'plami osonroq
print(np.bincount(ytr) / len(ytr))
print(np.bincount(yva) / len(yva)) # taqsimot mos kelyaptimi
print(len(ytr), len(yva)) # val juda kichikmiValidatsiya kichik bo'lsa (masalan 100 namuna), uning balli juda shovqinli bo'ladi va tasodifan yuqori chiqishi mumkin. stratify ishlatilmagan bo'lsa taqsimot ham farq qilishi mumkin.
Qaysi biri ekanini aniqlash:
| Tekshiruv | Natija | Xulosa |
|---|---|---|
dropout=0 bilan qayta |
Farq yo'qoldi | Sabab 1 |
Davr oxirida eval bilan o'quv loss |
Farq yo'qoldi | Sabab 2 |
| Val hajmi < 200 | Shovqin katta | Sabab 3 |
| Sinf taqsimoti farqli | stratify yo'q |
Sabab 3 |
Qachon xavotir olish kerak:
- Farq katta (> 0.05 aniqlikda) va
dropoutyo'q - Validatsiya doimiy yuqori, davrdan davrga
- Validatsiya to'plami o'quvdan kichikroq va osonroq (masalan, chetdagi qiymatlar faqat o'quvda)
Eng jiddiy holat: validatsiya to'plami tasodifan tozaroq bo'lsa — masalan siz chetdagi qiymatlarni faqat validatsiyadan olib tashlagan bo'lsangiz. Bunda validatsiya balli haqiqiy natijadan yuqori bo'ladi va siz noto'g'ri model tanlaysiz.
Amaliy qadam: o'quv ballini ham eval() rejimida, davr oxirida o'lchang. Shunda ikkala son bir xil sharoitda olinadi va taqqoslash ma'noga ega bo'ladi.
Nimani mustahkamlaydi: 2.2, 2.5-bo'limlar.
Xulosa
Bu darsda to'liq o'rgatish siklini qurdik.
Eng muhim uch fikr:
Besh qadam va ularning tartibi.
zero_grad→forward→loss→backward→step. 1-misoldazero_gradni tashlab yuborganda gradient normasi har qadamda yig'ilib bordi — model esa "ishlayotgandek" ko'rinadi. Bu siklMNISTdan tortib eng katta modellargacha o'zgarmaydi.train(),eval()vano_grad()— uch boshqa narsa.train()/eval()rejimni almashtiradi (dropout,BatchNorm),no_grad()esa grafni o'chiradi. 2-misoldatrain()rejimida qilingan 10 ta bashorat 10 xil aniqlik berdi. Baholashda ikkalasi ham kerak.Jurnal tashxis quroli. Faqat o'quv loss ni yozish hech narsa bermaydi. Ikkala loss va ikkala metrika birga yozilganda to'rt holat aniq ajraladi: normal, yodlash (
o'quv >> val), yetarsiz o'rganish (ikkalasi past, farq kichik) va noto'g'rilr(loss sakraydi yoki qimirlamaydi). Va oxirida — bitta seed natijasi bitta namuna, shuning uchun muhim qarorlarni bir necha yurish o'rtachasi bilan qabul qiling.
Keyingi darsda 20-qism amaliyoti: hamma narsani bitta loyihaga yig'amiz — xom ma'lumotdan boshlab, arxitektura tanlash, o'rgatish, regularizatsiya, baholash va saqlashgacha.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!