- Neyronun və tam əlaqəli qatın riyazi modelini yazmaq
- ReLU, siqmoid, tanh və softmax funksiyalarını hesablamaq və harada işlədildiyini bilmək
nn.Modulevənn.Sequentialilə şəbəkə qurmaq və onun parametrlərini saymaq
Əl ilə yazılmış rəqəmi tanımaq istəyirik: şəkil 28 × 28 = 784 pikseldir, cavab isə 0-dan 9-a qədər on rəqəmdən biridir. Hansı funksiya 784 ədədi on ehtimala çevirə bilər? Neyron şəbəkə bu funksiyanı çoxlu sadə hissədən qurur: xətti çevirmələr və onların arasında qeyri-xətti «əyilmələr». Adı beyindən ilhamlanıb, amma əslində bu, parametrləri qradiyent enişi ilə seçilən riyazi funksiyadır — məhz əvvəlki dərslərdə gördüyümüz kimi.
Süni neyron
- xgiriş vektoru (n əlamət)
- wçəkilər — hər girişin əhəmiyyəti
- bsürüşmə (bias) — aktivləşmə həddini sürüşdürür
- φaktivasiya funksiyası (ReLU, siqmoid…)
- aneyronun çıxışı (aktivasiya)
Neyron girişlərin çəkili cəmini hesablayır, ona sürüşməni əlavə edir və nəticəni aktivasiya funksiyasından keçirir. Aşağıdakı nümunədə z = 0,4 · 0,5 + 0,3 · (−1) + (−0,2) · 2 + 0,1 = −0,4 alınır: siqmoid bunu 0,4013 ehtimalına, ReLU isə 0-a çevirir.
import torch
x = torch.tensor([0.5, -1.0, 2.0])
w = torch.tensor([0.4, 0.3, -0.2])
b = torch.tensor(0.1)
z = w @ x + b
print(round(z.item(), 4))
print(round(torch.sigmoid(z).item(), 4), torch.relu(z).item())-0.4 0.4013 0.0
Aktivasiya funksiyaları
Aktivasiyalar olmasa, neçə qat qoysaq da şəbəkə xətti qalardı. İsbatı qısadır: iki qat ardıcıl tətbiq olunanda W₂(W₁x + b₁) + b₂ = (W₂W₁)x + (W₂b₁ + b₂) alınır — bu, W = W₂W₁ matrisi və b = W₂b₁ + b₂ sürüşməsi olan bir xətti qatdır. Qeyri-xətti φ funksiyası qatları «bükür» və şəbəkəyə mürəkkəb, əyri sərhədləri təsvir etməyə imkan verir.
- ReLUmənfi qiymətləri sıfırlayır; törəməsi z > 0 üçün 1, z < 0 üçün 0
- σsiqmoid: qiymətlər (0; 1) aralığında, ehtimal kimi şərh olunur
- tanhhiperbolik tangens: qiymətlər (−1; 1) aralığında, sıfıra görə simmetrik
- zK sinif üçün xam ballar (logitlər)
- softmax(z)ᵢi sinfinin ehtimalı; hamısı müsbətdir və cəmi 1-dir
Softmax çoxsinifli təsnifatda son qatın logitlərini ehtimallar paylanmasına çevirir.
| Funksiya | Qiymətlər çoxluğu | Harada işlədilir |
|---|---|---|
| ReLU | [0; ∞) | gizli qatlarda standart seçim: sadə, sürətli, qradiyent itmir |
| Siqmoid | (0; 1) | ikili təsnifatda çıxış, «qapılar» (LSTM) |
| tanh | (−1; 1) | rekurrent şəbəkələr, sıfır ətrafında mərkəzləşmiş çıxış lazım olanda |
| softmax | (0; 1), cəmi 1 | çoxsinifli təsnifatda son qat |
ReLU-nun bir zəif cəhəti var: neyronun girişi bütün nümunələr üçün mənfi olarsa, onun qradiyenti həmişə sıfırdır və neyron bir daha öyrənmir («ölü ReLU»). Buna qarşı LeakyReLU mənfi tərəfdə kiçik meyl saxlayır (məsələn, 0,01z). Transformerlərdə isə ReLU-nun hamar variantı olan GELU geniş işlədilir. PyTorch-da hamısı hazırdır: nn.LeakyReLU(), nn.GELU(), nn.Tanh(), nn.Sigmoid().
import torch
z = torch.tensor([-2.0, 0.0, 1.0, 3.0])
print(torch.relu(z))
print(torch.sigmoid(z).round(decimals=4))
print(torch.tanh(z).round(decimals=4))
p = torch.softmax(z, dim=0)
print(p.round(decimals=4), round(p.sum().item(), 4))tensor([0., 0., 1., 3.]) tensor([0.1192, 0.5000, 0.7311, 0.9526]) tensor([-0.9640, 0.0000, 0.7616, 0.9951]) tensor([0.0057, 0.0418, 0.1135, 0.8390]) 1.0
Şəbəkə üç sinif üçün z = (2; 1; 0) logitlərini verib. Ehtimalları tap.
Həllini göstərHəllini gizlət
p ≈ (7,389 / 11,107; 2,718 / 11,107; 1 / 11,107) ≈ (0,665; 0,245; 0,090).
Logitlər arasındakı fərq cəmi 1 olsa da, ehtimallar təxminən e ≈ 2,72 dəfə fərqlənir: softmax ən böyük balı «gücləndirir».
import torch
print(torch.softmax(torch.tensor([2.0, 1.0, 0.0]), dim=0).round(decimals=3))tensor([0.6650, 0.2450, 0.0900])
Qatlar: nn.Linear
Bir neçə neyron eyni girişə baxanda onların çəki vektorları bir W matrisinin sətirləri olur və qatın bütün çıxışları bir matris hasili ilə hesablanır. Paket şəklində gələn girişlər (N, nin) formasındadır, çıxışlar isə (N, nout).
- Xgirişlər paketi, forma (N, nin)
- Wçəkilər, forma (nout, nin) —
layer.weight - bsürüşmələr, forma (nout,) —
layer.bias - Yçıxışlar, forma (N, nout)
Hər çıxış neyronunun nin çəkisi və bir sürüşməsi var, buna görə tam əlaqəli qatda (nin + 1) · nout parametr olur.
import torch
from torch import nn
torch.manual_seed(42)
layer = nn.Linear(in_features=3, out_features=2)
print(layer.weight.shape, layer.bias.shape)
x = torch.randn(4, 3)
print(layer(x).shape)
print(sum(p.numel() for p in layer.parameters()))torch.Size([2, 3]) torch.Size([2]) torch.Size([4, 2]) 8
Çəkilərə başlanğıcda təsadüfi kiçik qiymətlər verilir: nn.Linear onları susmaya görə (−1/√nin; 1/√nin) aralığından bərabər paylanma ilə seçir. Təsadüfilik vacibdir — bütün çəkilər eyni olsaydı, qatdakı bütün neyronlar eyni qradiyenti alar və eyni şeyi öyrənərdi (simmetriya problemi).
nn.Module və nn.Sequential ilə şəbəkə
PyTorch-da hər model nn.Module-un varisidir. __init__ metodunda qatlar yaradılır — onların parametrləri avtomatik qeydə alınır; forward metodu isə girişdən çıxışa hesablamanı təsvir edir. Modeli model(x) kimi çağırırıq: PyTorch özü forward-u işə salır.
import torch
from torch import nn
class MLP(nn.Module):
def __init__(self, n_in, n_hidden, n_out):
super().__init__()
self.fc1 = nn.Linear(n_in, n_hidden)
self.fc2 = nn.Linear(n_hidden, n_out)
def forward(self, x):
h = torch.relu(self.fc1(x))
return self.fc2(h)
torch.manual_seed(42)
model = MLP(784, 128, 10)
print(model)
x = torch.randn(32, 784)
print(model(x).shape)
print(sum(p.numel() for p in model.parameters()))MLP( (fc1): Linear(in_features=784, out_features=128, bias=True) (fc2): Linear(in_features=128, out_features=10, bias=True) ) torch.Size([32, 10]) 101770
model.parameters()— bütün öyrədilən parametrlər; onları optimallaşdırıcıya veririk.model.to(device)— bütün parametrləri bir əmrlə CPU-dan GPU-ya (və ya əksinə) köçürür.model.train()vəmodel.eval()— öyrətmə və qiymətləndirmə rejimləri (Dropout və BatchNorm qatları üçün vacibdir).model.state_dict()— parametrlərin lüğəti; modeli fayla yazmaq üçün növbəti dərsdə işlədəcəyik.
Tam əlaqəli qatlardan və onların arasındakı aktivasiyalardan ibarət şəbəkəyə çoxqatlı perseptron deyilir. Onun son qatının normallaşdırılmamış çıxışları — logitlər — istənilən həqiqi ədəd ola bilər. Proqnoz üçün ən böyük logitin indeksi (logits.argmax(dim=1)), ehtimallar üçün isə torch.softmax(logits, dim=1) götürülür.
Arxitekturanı necə seçmək olar? Cədvəl verilənləri üçün 1–3 gizli qat və 32–256 neyron adətən kifayətdir; kiçik modeldən başla, validasiya itkisi imkan verdikcə böyüt. Şəkillər üçün isə tam əlaqəli qatlar çox bahalıdır — 224 × 224 rəngli şəkildən 1000 neyronlu qata keçid artıq 150 milyondan çox parametr tələb edir. Bu problemi konvolyusiya şəbəkələri həll edir.
Qatlar sadəcə ardıcıl düzülürsə, sinif yazmağa ehtiyac yoxdur: nn.Sequential onları sıra ilə tətbiq edir. Aktivasiya burada nn.ReLU() qatı kimi yazılır. named_parameters() hər parametrin adını və formasını göstərir — sazlama üçün çox faydalıdır:
import torch
from torch import nn
model = nn.Sequential(
nn.Linear(784, 128), nn.ReLU(),
nn.Linear(128, 64), nn.ReLU(),
nn.Linear(64, 10),
)
for name, p in model.named_parameters():
print(name, tuple(p.shape))
print(sum(p.numel() for p in model.parameters()))0.weight (128, 784) 0.bias (128,) 2.weight (64, 128) 2.bias (64,) 4.weight (10, 64) 4.bias (10,) 109386
Sequential daxilindəki nömrəsidir; 1 və 3 nömrəli ReLU qatlarının parametri yoxdur.784 → 128 → 64 → 10 şəbəkəsində neçə parametr var? Onlar float32-də nə qədər yaddaş tutur?
Həllini göstərHəllini gizlət
2-ci qat: (128 + 1) · 64 = 8256.
3-cü qat: (64 + 1) · 10 = 650.
Cəmi: 109 386 — kodun nəticəsi ilə eynidir.
Yaddaş: 109 386 · 4 bayt ≈ 0,44 MB. Parametrlərin 92%-i birinci qatdadır: böyük girişlər bahalıdır.
2 → 2 → 1 şəbəkəsi: W₁ = [[1; −1]; [0,5; 0,5]], b₁ = (0; −1), gizli qatda ReLU, W₂ = [[2; −3]], b₂ = 1. x = (1; 2) üçün çıxışı tap.
Həllini göstərHəllini gizlət
ReLU: h = (0; 0,5) — birinci neyron «söndü».
y = 2 · 0 + (−3) · 0,5 + 1 = −0,5.
Diqqət et: bu x üçün birinci neyron çıxışa heç bir təsir etmir, ona görə geri keçiddə onun çəkilərinin qradiyenti də sıfır olacaq — ReLU qradiyenti yalnız aktiv neyronlardan keçirir.
import torch
x = torch.tensor([1.0, 2.0])
W1 = torch.tensor([[1.0, -1.0], [0.5, 0.5]])
b1 = torch.tensor([0.0, -1.0])
W2 = torch.tensor([[2.0, -3.0]])
b2 = torch.tensor([1.0])
h = torch.relu(W1 @ x + b1)
y = W2 @ h + b2
print(h, y)tensor([0.0000, 0.5000]) tensor([-0.5000])
Əsas fikirlər
- Neyron: z = w · x + b, sonra aktivasiya a = φ(z); qat bunu matris şəklində edir: Y = X · Wᵀ + b.
- Aktivasiyasız çoxqatlı şəbəkə bir xətti qata bərabərdir; gizli qatlarda adətən ReLU işlədilir.
- Softmax logitləri cəmi 1 olan ehtimallara çevirir;
nn.CrossEntropyLoss-a isə xam logitlər verilir. - Model
nn.Module-dan törəyir: qatlar__init__-də, hesablamaforward-da; sadə zəncir üçünnn.Sequentialkifayətdir. - Tam əlaqəli qatda (nin + 1) · nout parametr var;
nn.Linear(n_in, n_out).weight-in forması (nout, nin)-dir.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.
nn.Linear(10, 5) qatında neçə parametr var?