Makine Öğrenmesi
Meydan okuma 3
CNN ile görüntü modeli kurarsın.
Meydan okuma 3: kendi optimize edicin
PyTorch optimize edicilerinin içinde ne olduğunu kanıtlamanın en iyi yolu birini kendin yazmaktır. torch.optim.Optimizer'dan türeyen bir sınıf, step içinde parametre gruplarını gezer:
class BenimSGD(torch.optim.Optimizer):
def __init__(self, params, lr):
super().__init__(params, {"lr": lr})
@torch.no_grad()
def step(self):
for grup in self.param_groups:
for p in grup["params"]:
if p.grad is not None:
p -= grup["lr"] * p.grad
zero_grad, parametre grupları ve state_dict temel sınıftan hazır gelir.
Uygulama BenimSGD
Karttaki BenimSGD sınıfını yaz. Aynı başlangıçtan iki kopya model oluştur (verildi); birini BenimSGD(lr=0.1), diğerini torch.optim.SGD(lr=0.1) ile 20 adım eğit. Son ağırlıkların aynı olduğunu torch.allclose ile yazdır.
Örnek çözümü göster
import copy
import torch
from torch import nn
torch.manual_seed(0)
X = torch.randn(64, 3)
y = X @ torch.tensor([[1.0], [-2.0], [0.5]])
a = nn.Linear(3, 1)
b = copy.deepcopy(a)
class BenimSGD(torch.optim.Optimizer):
def __init__(self, params, lr):
super().__init__(params, {"lr": lr})
@torch.no_grad()
def step(self):
for grup in self.param_groups:
for p in grup["params"]:
if p.grad is not None:
p -= grup["lr"] * p.grad
for model, opt in [(a, BenimSGD(a.parameters(), lr=0.1)), (b, torch.optim.SGD(b.parameters(), lr=0.1))]:
for _ in range(20):
opt.zero_grad()
nn.functional.mse_loss(model(X), y).backward()
opt.step()
print(torch.allclose(a.weight, b.weight))
Uygulama Momentumlu sürüm
BenimMomentum sınıfını yaz: her parametre için self.state[p]["buf"] tamponu tutsun; ilk adımda buf = g.clone(), sonra buf = m·buf + g; güncelleme p -= lr·buf. w = 0'dan (w - 3)² için lr = 0.1, m = 0.9 ile 2 adım at ve w'yi round(..., 3) ile yazdır (beklenen: 1.62).
Örnek çözümü göster
import torch
w = torch.tensor(0.0, requires_grad=True)
class BenimMomentum(torch.optim.Optimizer):
def __init__(self, params, lr, m):
super().__init__(params, {"lr": lr, "m": m})
@torch.no_grad()
def step(self):
for grup in self.param_groups:
for p in grup["params"]:
if p.grad is None:
continue
durum = self.state[p]
if "buf" not in durum:
durum["buf"] = p.grad.clone()
else:
durum["buf"] = grup["m"] * durum["buf"] + p.grad
p -= grup["lr"] * durum["buf"]
opt = BenimMomentum([w], lr=0.1, m=0.9)
for _ in range(2):
opt.zero_grad()
((w - 3) ** 2).backward()
opt.step()
print(round(w.item(), 3))
Kendini test et
-
<code>step</code> neden <code>@torch.no_grad()</code> ile işaretlenir?
- Zorunlu değildir
- Güncelleme hesap grafiğine kaydedilmesin diye
- Daha hızlı olsun diye
- Gradyanları sıfırlamak için
Cevabı göster
Güncelleme hesap grafiğine kaydedilmesin diye — Parametreler yerinde değiştirilir; bu bir türev alınacak işlem değildir.
-
Varsayılan ayarları üst sınıfa ver.
super().__init__(params, ____)
Cevabı göster
super().__init__(params, {"lr": lr})
-
Parçaları eşleştir.
- param_groups
- Ayarlı parametre grupları
- @torch.no_grad()
- İzlemesiz güncelleme
- p.grad is not None
- Donuk parametreleri atla
- self.state[p]
- Parametre başına durum
Sıradaki ders: Meydan okuma 4