Idenya
Di modul autograd kamu mengelola w dan b secara manual. Network sungguhan punya banyak layer dan ribuan parameter, jadi PyTorch menyediakan blok-blok penyusun di torch.nn:
- layer (
nn.Linear,nn.Conv2d...) yang memiliki parameternya sendiri, - activation function (
nn.ReLU,nn.Sigmoid...), - dan
nn.Module, base class yang kamu turunkan untuk mendeskripsikan model-mu: layer apa saja yang dimilikinya (di__init__) dan bagaimana data mengalir melewatinya (diforward).
Ini modul class dari track Python, dipakai untuk bekerja.
Linear layer adalah X @ W.T + b
Blok penyusun dasar sebuah jaringan saraf adalah linear layer. Isinya "kalikan lalu jumlahkan" yang sama dengan regresi linear, hanya dengan beberapa output sekaligus. Ini satu layer yang menerima 3 fitur dan menghasilkan 2 angka:
import torch
from torch import nn
torch.manual_seed(0)
layer = nn.Linear(in_features=3, out_features=2)
print(layer.weight.shape, layer.bias.shape)
x = torch.tensor([[1.0, 0.0, 2.0]]) # a batch of 1 example with 3 features
print(layer(x))
print(x @ layer.weight.T + layer.bias) # the same calculation by hand
torch.Size([2, 3]) torch.Size([2])
tensor([[-0.9661, 0.3425]], grad_fn=<AddmmBackward0>)
tensor([[-0.9661, 0.3425]], grad_fn=<AddBackward0>)
grad_fn di output menunjukkan bahwa hasilnya bagian dari graph autograd, siap untuk backward(). nn.Linear(3, 2) menyimpan matriks bobot ber-shape (2, 3) dan bias ber-shape (2,), keduanya dibuat secara acak dan ditandai requires_grad=True. Memanggil layer pada sebuah batch menghitung x @ W.T + b: latihan "layer buatan tangan" dari modul operasi.
Activation: bagian yang non-linear
Menumpuk linear layer saja hanya menghasilkan fungsi linear lainnya (matriks kali matriks tetap matriks). Di antara layer kamu menaruh activation non-linear, yang membuat network bisa melengkung:
z = torch.tensor([-2.0, -0.5, 0.0, 1.5])
print(torch.relu(z)) # max(0, z): the default choice
print(torch.sigmoid(z)) # squashes to (0, 1): for probabilities
print(torch.tanh(z)) # squashes to (-1, 1)
tensor([0.0000, 0.0000, 0.0000, 1.5000])
tensor([0.1192, 0.3775, 0.5000, 0.8176])
tensor([-0.9640, -0.4621, 0.0000, 0.9051])
ReLU (rectified linear unit) adalah standar di antara hidden layer: sederhana, cepat, dan mudah dilatih.
Class model pertamamu
Model churn dengan 5 input, satu hidden layer berisi 16 unit, dan satu output:
class ChurnNet(nn.Module):
def __init__(self, n_features, hidden=16):
super().__init__()
self.hidden = nn.Linear(n_features, hidden)
self.output = nn.Linear(hidden, 1)
def forward(self, x):
x = torch.relu(self.hidden(x))
return self.output(x) # a raw score ("logit"); sigmoid turns it into a probability
torch.manual_seed(0)
model = ChurnNet(n_features=5)
batch = torch.randn(4, 5) # 4 customers, 5 features each
logits = model(batch)
print(logits.shape)
print(torch.sigmoid(logits).squeeze().detach().round(decimals=3))
torch.Size([4, 1])
tensor([0.3920, 0.4280, 0.3520, 0.4480])
__init__membuat layer-layernya dan wajib memanggilsuper().__init__()terlebih dulu.forward(x)mendeskripsikan perhitungannya. Kamu memanggilmodel(batch), bukanmodel.forward(batch); PyTorch membungkus panggilan itu dengan mesin tambahan (hook).- Output-nya adalah logit (skor mentah). Menjaga sigmoid di luar model dan di dalam fungsi loss lebih stabil secara numerik (modul berikutnya).
Probabilitas dari model yang belum dilatih berada di antara 0,35 dan 0,45: bobot acak, belum ada pengetahuan. (.detach() membuang catatan autograd sebelum dicetak.)
nn.Sequential untuk tumpukan sederhana
Saat data hanya mengalir melewati layer secara berurutan, nn.Sequential menghemat penulisan class:
torch.manual_seed(0)
model = nn.Sequential(
nn.Linear(5, 16),
nn.ReLU(),
nn.Linear(16, 1),
)
print(model)
print(model(batch).shape)
Sequential(
(0): Linear(in_features=5, out_features=16, bias=True)
(1): ReLU()
(2): Linear(in_features=16, out_features=1, bias=True)
)
torch.Size([4, 1])
Gunakan nn.Sequential untuk tumpukan lurus; tulis subclass nn.Module saat forward butuh logika (beberapa input, skip connection, percabangan).
Parameter
Setiap layer yang didaftarkan sebagai atribut dilacak secara otomatis:
for name, p in model.named_parameters():
print(name, tuple(p.shape))
print("total:", sum(p.numel() for p in model.parameters()))
0.weight (16, 5)
0.bias (16,)
2.weight (1, 16)
2.bias (1,)
total: 113
5×16 + 16 + 16×1 + 1 = 113 parameter. model.parameters() adalah yang kamu serahkan ke optimizer, supaya ia bisa memperbarui semuanya. Ini berfungsi karena layer-layernya di-assign ke self.something di __init__; layer yang disimpan di list Python biasa tidak akan ditemukan (gunakan nn.ModuleList untuk list berisi layer).
Sebuah nn.Module = layer yang dibuat di __init__ + aliran data di forward. Layer memiliki parameternya sendiri; model.parameters() mengumpulkan semuanya untuk optimizer.
Mengapa ini penting untuk kode yang bersih
Class model adalah tempat kode deep learning tetap mudah dibaca atau berubah menjadi spageti. Jaga __init__ tetap deklaratif (hanya layer-layer, dengan nama jelas seperti hidden dan output), jaga forward tetap pendek dan lurus, berikan ukuran sebagai argumen (n_features, hidden) alih-alih di-hard-code, dan kembalikan logit alih-alih mencampur logika probabilitas ke dalam model. Dengan begitu class yang sama bisa dites, dipakai ulang, dan dikonfigurasi ulang.
Rangkuman
nn.Linear(in, out)menghitungx @ W.T + bdengan bobot(out, in)dan bias(out,).- Activation non-linear (ReLU di antara layer; sigmoid untuk probabilitas) membuat network bisa mempelajari kurva.
- Turunkan
nn.Module: layer di__init__(setelahsuper().__init__()), perhitungan diforward; panggilmodel(x). nn.Sequentialuntuk tumpukan sederhana; class kustom saatforwardbutuh logika.model.parameters()/named_parameters()mendaftar setiap tensor yang bisa dipelajari.