Гузариш ба мундариҷа
Мавзӯи 5 аз 6

Давраи омӯзиш

Давраи омӯзиш барои чӣ лозим аст

Модел бо вазнҳои тасодуфӣ ҳисоб карда метавонад, вале ҳанӯз масъаларо ҳал намекунад. Омӯзиш пешгӯиҳоро такроран бо ҷавобҳои дуруст муқоиса карда, вазнҳоро тағйир медиҳад. Давра қисмҳои шиносро мепайвандад: гузариши мустақими модел, функсияи хато, autograd ва навсозии параметрҳо.

Қадам, як навсозии параметрҳо, ва эпоха (epoch), як гузариши пурра аз маҷмӯи омӯзиширо, фарқ мекунем. Агар тамоми маҷмӯъ якбора истифода шавад, дар як эпоха як қадам ҳаст. Ҳангоми кор бо бастаҳо дар эпоха чанд қадам мешавад. Хато одатан аз қадам ба қадам тағйир меёбад; камшавии он дар маълумоти омӯзишӣ ҳанӯз сифати хубро дар маълумоти нав кафолат намедиҳад.

1. Функсияи хато ва вурудҳои он

Барои тасниф модел логитҳо (logits) бо шакли (N, C) медиҳад: барои ҳар яке аз N намуна C баҳо. Ҷавобҳои дуруст рақамҳои синф аз 0 то C−1 мебошанд, одатан тензори torch.long бо шакли (N,). nn.CrossEntropyLoss баҳоҳоро бо ҷавобҳо муқоиса карда, бо танзимоти пешфарз хатои миёнаи бастаро мегирад.

import torch
from torch import nn
logits = torch.tensor([[3.0, 0.0]])
loss_fn = nn.CrossEntropyLoss()
for labels in (torch.tensor([0]), torch.tensor([1])):
    print(round(loss_fn(logits, labels).item(), 3))

Натиҷа:

0.049
3.049

Барои синфи 0 хато хурд ва барои синфи 1 калон аст. Loss қувваи афзалияти синфро низ ба назар мегирад, на танҳо шумораи иштибоҳҳоро. Барои пешгӯии ададҳо nn.MSELoss, миёнаи квадрати хато, мувофиқ аст.

2. Оптимизатор

Оптимизатор (optimizer) истинодҳоро ба параметрҳои модел нигоҳ дошта, онҳоро бо .grad нав мекунад. torch.optim.SGD қадами фурӯравии градиентиро иҷро мекунад; lr андозаи онро муайян мекунад. torch.optim.Adam омори градиентҳои пешинаро низ нигоҳ дошта, навсозии параметрҳои гуногунро мутобиқ мекунад. Бартарии он ба масъала ва танзимот вобаста аст.

Оптимизаторро пеш аз давра созед: torch.optim.Adam(model.parameters(), lr=1e-3). Аз нав сохтани Adam оморро гум мекунад; step() градиентҳои аз backward() гирифтаро истифода мебарад.

3. Мисоли пурра барои регрессия

Як вуруди 1 ва ҷавоби ҳадафии 2 мегирем. Модел як вазни бе ҷойивазкунӣ дорад, ки аввал ошкоро сифр аст. Дар ҳар такрор градиентҳои пешинаро тоза карда, хатогиро ҳисоб мекунем, градиентҳои навро мегирем ва вазнро нав мекунем. Рақами қадам, хатои пеш аз навсозӣ ва вазни баъди онро чоп мекунем.

import torch
from torch import nn
model = nn.Linear(1, 1, bias=False)
with torch.no_grad():
    model.weight.zero_()
x = torch.tensor([[1.0]])
y = torch.tensor([[2.0]])
optimizer = torch.optim.SGD(model.parameters(), lr=0.25)
loss_fn = nn.MSELoss()
model.train()
for epoch in range(3):
    optimizer.zero_grad()
    loss = loss_fn(model(x), y)
    loss.backward()
    optimizer.step()
    print(epoch + 1, round(loss.item(), 4), round(model.weight.item(), 4))

Натиҷа:

1 4.0 1.0
2 1.0 1.5
3 0.25 1.75

Баъди навсозии аввал вазн 1, баъди дуюм 1.5 ва баъди сеюм 1.75 аст. Он ба 2 наздик мешавад. loss.item() ба гузариши мустақими аллакай иҷрошуда тааллуқ дорад: тағйири параметрҳо тензори пешинаи хатогиро аз нав ҳисоб намекунад. Барои хатои баъди қадам гузариши нави мустақим лозим аст.

4. Ҳолатҳои train ва eval

Баъзе қабатҳо ҳангоми санҷиш дигар хел рафтор мекунанд. Dropout ҳангоми омӯзиш ҳар унсурро мустақилона бо эҳтимоли p сифр мекунад; қиматҳои боқимонда ба 1 / (1 − p) зарб мешаванд, то миқёси миёна нигоҳ дошта шавад. Аз ин рӯ, бо p=0.5 аз якҳо сифрҳо ва дуҳо пайдо мешаванд. Шумораи сифрҳо ҳатман нисфи дақиқ нест.

import torch
from torch import nn
torch.manual_seed(7)
layer = nn.Dropout(0.5)
x = torch.ones(8, requires_grad=True)
layer.train()
y = layer(x)
print(sorted(set(y.tolist())), y.requires_grad)
layer.eval()
print(layer(x).tolist(), layer(x).requires_grad)
with torch.no_grad():
    print((layer(x) * 1).requires_grad)

Натиҷа:

[0.0, 2.0] True
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] True
False

eval() сифркунии тасодуфии Dropout-ро хомӯш мекунад. Вале autograd-ро хомӯш намекунад: ҳангоми фаъол будани пайгирӣ натиҷаи амалҳо метавонад градиент талаб кунад. torch.no_grad() сабти амалҳои навро алоҳида хомӯш мекунад. Барои санҷиши модел ҳардуро истифода баред. BatchNorm низ рафторашро иваз мекунад: дар eval омори ҷамъшударо истифода мебарад.

5. Гузариш ба санҷиш ва бозгашт

Ҳолат дар model.training нигоҳ дошта мешавад; даъвати train() ё eval() ба модулҳои дохилӣ низ таъсир мекунад. Дар санҷиш одатан ҳосилаҳо лозим нестанд. Агар баъд омӯзиш идома ёбад, ҳолати омӯзишро боз фаъол кунед.

import torch
from torch import nn
model = nn.Linear(2, 3)
print(model.training)
model.eval()
with torch.no_grad():
    scores = model(torch.zeros(2, 2))
print(model.training, scores.requires_grad)
model.train()
print(model.training)

Натиҷа:

True
False False
True

eval() вазнҳоро ях намекунад ва дақиқиро ҳисоб намекунад. Барои арзёбӣ маълумоти санҷишӣ ва меъёр лозиманд. Баъди санҷиш ҳолатеро барқарор кунед, ки коди даъваткунанда талаб мекунад.

Дар дохил чӣ рӯй медиҳад

zero_grad() градиентҳои захирашударо тоза мекунад; дар танзимоти муосир ин метавонад ба ҷойи сифрнависӣ гузоштани .grad ба None бошад. Гузариши мустақим графи нав месозад. Гузариши баръакс градиентҳои параметрҳои баргиро пур мекунад. Оптимизатор онҳоро хонда, вазнҳоро бе сабти навсозӣ дар граф тағйир медиҳад. Гузариши нав вазнҳои навро истифода мебарад.

CrossEntropyLoss log-softmax-и аз ҷиҳати ададӣ устуворро бо интихоби баҳои синфи дуруст мепайвандад. Ба он логитҳои аслӣ лозиманд. Softmax-и пешакӣ вурудро иваз карда, фарқи байни ҷавобҳои боэътимодро фишурда мекунад, чунон ки ин пешгӯии қасдан нодуруст нишон медиҳад:

import torch
from torch import nn
logits = torch.tensor([[8.0, -8.0]])
labels = torch.tensor([1])
loss_fn = nn.CrossEntropyLoss()
print(round(loss_fn(logits, labels).item(), 3))
print(round(loss_fn(torch.softmax(logits, dim=1), labels).item(), 3))

Натиҷа:

16.0
1.313

Хатоҳои маъмул ва ислоҳи онҳо

  1. Тозакунӣ пеш аз step, вале баъди backward. Градиентҳои нав гум мешаванд ва вазнҳо тағйир намеёбанд. Қиматҳои пешинаро пеш аз ҳисоби градиентҳои қадами нав тоза кунед; тартиб дар мисоли регрессия ҳаст.

  2. Softmax-и зиёдатӣ пеш аз CrossEntropyLoss. Хатои иштибоҳи боэътимод ба ҷойи 16 ба 1.313 табдил ёфт. Баҳоҳоро мустақим диҳед; эҳтимолҳо барои шарҳи пешгӯиҳо алоҳида лозиманд.

  3. Барчаспҳои нодуруст. Рақамҳои касрии синф ё шакли (N, 1) ба ҳолати одӣ бо индексҳои синф мувофиқ нестанд. Барчаспҳои long бо шакли (N,) омода кунед; дар ин тарз барои таснифи дуӣ ҳам ду логит лозим аст.

  4. Танҳо no_grad дар санҷиш. Агар модел дар train бошад, Dropout тасодуфӣ мемонад. Ҳолатро иваз карда, сабти амалҳоро хомӯш кунед; баъди санҷиш ҳолати заруриро барқарор намоед.

  5. Тозакунии фаромӯшшуда ё lr-и аз ҳад калон. Градиентҳои ҷамъшуда андозаи қадамро тағйир медиҳанд ва қадами калон хатогиро зиёд карда метавонад. Тозакуниро санҷед, ниҳоӣ будани loss-ро назорат кунед ва ҳангоми ноустувории навсозӣ lr-ро кам кунед.

Ёддошт

Амал Фармон ё қоида
Тасниф Логитҳои (N, C), барчаспҳои long (N,)
Хато CrossEntropyLoss барои синфҳо, MSELoss барои ададҳо
Оптимизатор SGD ё Adam, пеш аз давра сохта мешавад
Қадам zero_grad → forward ва loss → backward → step
Омӯзиш model.train()
Санҷиш model.eval() ва torch.no_grad()
Такрорпазирӣ torch.manual_seed(...) пеш аз амалҳои тасодуфӣ

Қимати ибтидоии генератор (seed) ба такрори мисолҳо дар як муҳит кумак мекунад; натиҷаҳо байни версияҳо ва дастгоҳҳо метавонанд фарқ кунанд.