Idenya
Neural network sebagian besar terdiri dari tiga operasi yang diulang berkali-kali: perkalian matriks, fungsi element-wise, dan reduksi (jumlah, rata-rata). Kamu sudah mengenal ketiganya dari NumPy. Modul ini memetakannya ke PyTorch dan menunjukkan segelintir perbedaan yang sering menjebak.
Perhitungan element-wise
Perhitungan tensor terlihat persis seperti NumPy. Harga dikali unit menghasilkan revenue per produk, dan mengalikan dengan 1,11 menambahkan PPN ke setiap harga sekaligus:
import torch
prices = torch.tensor([185.0, 320.0, 95.0])
units = torch.tensor([9.0, 10.0, 12.0])
print(prices * units)
print(prices * 1.11)
print(torch.sqrt(units), units.exp().round())
tensor([1665., 3200., 1140.])
tensor([205.3500, 355.2000, 105.4500])
tensor([3.0000, 3.1623, 3.4641]) tensor([ 8103., 22026., 162755.])
Operator bekerja elemen demi elemen, dan sebagian besar fungsi NumPy punya kembaran di PyTorch (torch.sqrt, torch.exp, torch.log, torch.abs, torch.clamp), biasanya juga tersedia sebagai method (units.exp()).
Perkalian matriks
Operasi yang menjadi dasar jaringan saraf adalah perkalian matriks. Kamu sudah melihatnya dengan data toko: setiap baris jumlah pesanan dikali daftar harga menghasilkan total pesanan itu. Cara kerjanya sama di PyTorch:
order_qty = torch.tensor([[2.0, 1.0, 3.0],
[0.0, 2.0, 0.0]])
price_vec = torch.tensor([95.0, 320.0, 55.0])
print(order_qty @ price_vec)
print(torch.matmul(order_qty, price_vec))
tensor([675., 640.])
tensor([675., 640.])
@ adalah operator yang sama seperti di modul aljabar linear NumPy, dengan aturan shape yang sama: (n, k) @ (k, m) → (n, m). Sebuah layer neural network persis X @ W.T + b, seperti yang akan kamu lihat di materi nn.Module.
Reduksi sepanjang dimensi
PyTorch menyebut axis sebagai dimensi (dim alih-alih axis), tetapi aturannya sama: dimensi yang kamu sebut akan hilang.
units = torch.tensor([[120.0, 135.0, 150.0],
[ 80.0, 85.0, 90.0]]) # stores × months
print(units.sum())
print(units.sum(dim=0)) # per month
print(units.mean(dim=1)) # per store
print(units.max(dim=1))
tensor(660.)
tensor([200., 220., 240.])
tensor([135., 85.])
torch.return_types.max(
values=tensor([150., 90.]),
indices=tensor([2, 2]))
Perhatikan max(dim=...): ia mengembalikan sekaligus nilai maksimum dan posisinya (indices), seperti max dan argmax NumPy dalam satu panggilan. Gunakan .values dan .indices, atau unpack: best, where = units.max(dim=1).
keepdim=True mempertahankan dimensi yang direduksi dengan ukuran 1, siap untuk broadcasting:
share = units / units.sum(dim=1, keepdim=True)
print(share.round(decimals=3))
tensor([[0.2960, 0.3330, 0.3700],
[0.3140, 0.3330, 0.3530]])
Broadcasting
Aturannya identik dengan NumPy: bandingkan shape dari kanan; ukurannya harus sama atau bernilai 1.
targets = torch.tensor([[130.0], [85.0]]) # one target per store: shape (2, 1)
print(units - targets)
monthly_price = torch.tensor([95.0, 100.0, 105.0]) # one price per month: shape (3,)
print(units * monthly_price)
tensor([[-10., 5., 20.],
[ -5., 0., 5.]])
tensor([[11400., 13500., 15750.],
[ 7600., 8500., 9450.]])
Operasi in-place
Method yang diakhiri garis bawah mengubah tensor in place (langsung di tempat):
w = torch.tensor([1.0, 2.0, 3.0])
w.add_(10)
print(w)
w.mul_(0.5)
print(w)
tensor([11., 12., 13.])
tensor([5.5000, 6.0000, 6.5000])
w.add_(10) mengubah w; w.add(10) (atau w + 10) mengembalikan tensor baru. Optimizer memperbarui bobot secara in-place dengan cara ini. Di kodemu sendiri, utamakan versi tanpa garis bawah kecuali ada alasannya: lebih aman (tidak ada perubahan mengejutkan pada tensor yang dipakai bersama) dan cocok dengan autograd.
Perbandingan dan mask
Memilih nilai berdasarkan kondisi, seperti hari-hari ramai dengan lebih dari 60 order, juga bekerja persis seperti di NumPy:
daily = torch.tensor([42, 38, 51, 47, 60, 75, 68])
busy = daily > 60
print(busy)
print(daily[busy], busy.sum().item(), busy.float().mean().item())
print(torch.where(busy, daily, torch.zeros_like(daily)))
tensor([False, False, False, False, False, True, True])
tensor([75, 68]) 2 0.2857142984867096
tensor([ 0, 0, 0, 0, 0, 75, 68])
Mask boolean, torch.where, dan .sum() dari sebuah mask semuanya berperilaku seperti versi NumPy-nya. Satu perbedaan: tensor boolean harus dikonversi (.float()) sebelum diambil rata-ratanya.
Kalau kamu bisa melakukannya di NumPy, hampir pasti kamu bisa melakukannya di PyTorch dengan logika shape yang sama. Perbedaannya ada di nama (dim vs axis), max yang mengembalikan nilai dan indeks, default float32, dan method bergaris bawah untuk perubahan in-place.
Mengapa ini penting untuk kode yang bersih
Menulis kode model sebagai operasi atas seluruh tensor, alih-alih loop Python atas setiap contoh, adalah yang membuatnya cepat di GPU, dan menjaga kodenya dekat dengan rumus matematika di atas kertas: logits = x @ W.T + b alih-alih tiga loop bersarang. Kebiasaan vektorisasi dari track NumPy berlaku langsung.
Rangkuman
- Operator dan fungsi element-wise (
torch.exp,clamp...) bekerja seperti di NumPy. @/torch.matmuluntuk perkalian matriks:(n, k) @ (k, m) → (n, m).- Reduksi menerima
dim=(axisdi NumPy);keepdim=Truemempertahankan dimensinya;max(dim)mengembalikan nilai dan indeks. - Aturan broadcasting identik dengan NumPy.
add_,mul_... mengubah in place; utamakan versi tanpa garis bawah di kodemu sendiri.- Mask dan
torch.wherebekerja seperti NumPy; konversi boolean dengan.float()sebelummean().