Sebuah model deep learning, betapapun besarnya, tersusun dari operasi tensor yang jenisnya bisa dihitung dengan jari: operasi elementwise untuk aktivasi, reduksi untuk menghitung loss dan statistik, matmul untuk mengalikan input dengan bobot, serta penggabungan untuk merakit hasil antar layer. Kita sudah mengenal keempat keluarga ini pada NumPy; chapter ini menjalankannya di PyTorch dengan tambahan dua hal yang khas: matmul versi batch yang memproses lusinan matriks sekaligus, dan argumen dim/keepdim yang bentuk hasilnya sering menjadi sumber kebingungan. Seluruh contoh memakai angka kecil yang bisa dihitung ulang dengan mata.
Operasi Elementwise #
Operasi elementwise memasangkan elemen yang seposisi; syaratnya shape kedua operand sama (atau kompatibel lewat broadcasting yang dibahas pada chapter berikutnya). Berkas operasi_dasar.py memuat keluarga ini sekaligus reduksi:
"""Operasi elementwise dan reduksi dengan dim serta keepdim."""
import torch
A = torch.tensor([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
B = torch.tensor([[10.0, 20.0, 30.0],
[40.0, 50.0, 60.0]])
print("A + B:")
print(A + B)
print("A * B:")
print(A * B)
print("A ** 2:")
print(A ** 2)
print("torch.relu(A - 3.5):")
print(torch.relu(A - 3.5))
print()
print("A.sum() :", A.sum().item())
print("A.mean() :", A.mean().item())
print("A.sum(dim=0) per kolom :", A.sum(dim=0).tolist())
print("A.sum(dim=1) per baris :", A.sum(dim=1).tolist())
print("A.sum(dim=1, keepdim=True):")
print(A.sum(dim=1, keepdim=True))
nilai, posisi = A.max(dim=1)
print("A.max(dim=1) values :", nilai.tolist())
print("A.max(dim=1) indices :", posisi.tolist())Output yang Dihasilkan:
A + B:
tensor([[11., 22., 33.],
[44., 55., 66.]])
A * B:
tensor([[ 10., 40., 90.],
[160., 250., 360.]])
A ** 2:
tensor([[ 1., 4., 9.],
[16., 25., 36.]])
torch.relu(A - 3.5):
tensor([[0.0000, 0.0000, 0.0000],
[0.5000, 1.5000, 2.5000]])
A.sum() : 21.0
A.mean() : 3.5
A.sum(dim=0) per kolom : [5.0, 7.0, 9.0]
A.sum(dim=1) per baris : [6.0, 15.0]
A.sum(dim=1, keepdim=True):
tensor([[ 6.],
[15.]])
A.max(dim=1) values : [3.0, 6.0]
A.max(dim=1) indices : [2, 2]Mari kita telaah kode di atas baris per baris:
- Baris 10-17 (empat operasi elementwise):
+,*, dan**bekerja per elemen dan shape hasil selalu mengikuti operand;torch.relu(A - 3.5)menunjukkan komposisi khas model — pengurangan elementwise diikuti fungsi aktivasi yang memangkas nilai negatif menjadi nol. - Baris 20-21 (reduksi penuh): tanpa
dim,sumdanmeanmenggabungkan seluruh tensor menjadi satu angka: total21.0dan rata-rata3.5. - Baris 22-23 (
dim=0versusdim=1): sumbu yang disebutkan adalah sumbu yang dihapus.dim=0menggabungkan sepanjang baris sehingga hasilnya per kolom[5, 7, 9];dim=1menggabungkan sepanjang kolom sehingga hasilnya per baris[6, 15]. - Baris 24-25 (
keepdim=True): sumbu yang digabungkan dipertahankan dengan panjang 1 — hasil(2, 1)bukan(2,). Bentuk ini penting supaya hasil reduksi bisa langsung dikurangkan kembali keAlewat broadcasting. - Baris 26-28 (
maxdengandim):maxmengembalikan dua keluaran sekaligus —valuesberisi nilai terbesar tiap baris danindicesposisinya; indeks inilah yang dipakai saat menghitung akurasi klasifikasi.
Matmul: 2D, Vektor, dan Batch 3D #
Operator @ menjalankan perkalian matriks dengan aturan shape yang ketat: (n, k) @ (k, m) menghasilkan (n, m). Kekuatan khusus PyTorch ada pada matmul berbatch — bila operand berdimensi lebih tinggi, dua sumbu terakhir diperlakukan sebagai matriks dan sumbu di depannya menunjuk batch. Berkas matmul_batch.py membuktikannya:
"""Perkalian matriks 2D, batch 3D, dan penggabungan cat/stack."""
import torch
A = torch.tensor([[1.0, 2.0],
[3.0, 4.0]])
B = torch.tensor([[10.0, 20.0, 30.0],
[40.0, 50.0, 60.0]])
C = A @ B
print("2D (2,2) @ (2,3) ->", tuple(C.shape))
print(C)
v = torch.tensor([1.0, 2.0])
print("1D (2,) @ (2,3) ->", tuple((v @ B).shape), "=", (v @ B).tolist())
b1 = torch.ones(2, 3, 4)
b2 = torch.ones(2, 4, 5)
print("3D (2,3,4) @ (2,4,5) ->", tuple((b1 @ b2).shape))
print("3D (2,3,4) @ (4,5) ->", tuple((b1 @ torch.ones(4, 5)).shape))
P = torch.ones(2, 3)
Q = torch.zeros(2, 3)
print("cat dim=0 ->", tuple(torch.cat([P, Q], dim=0).shape))
print("cat dim=1 ->", tuple(torch.cat([P, Q], dim=1).shape))
print("stack dim=0 ->", tuple(torch.stack([P, Q], dim=0).shape))Output yang Dihasilkan:
2D (2,2) @ (2,3) -> (2, 3)
tensor([[ 90., 120., 150.],
[190., 260., 330.]])
1D (2,) @ (2,3) -> (3,) = [90.0, 120.0, 150.0]
3D (2,3,4) @ (2,4,5) -> (2, 3, 5)
3D (2,3,4) @ (4,5) -> (2, 3, 5)
cat dim=0 -> (4, 3)
cat dim=1 -> (2, 6)
stack dim=0 -> (2, 2, 3)Mari kita telaah kode di atas baris per baris:
- Baris 10-12 (matmul 2D):
(2,2) @ (2,3)menghasilkan(2,3); elemenC[0, 0]=1×10 + 2×40 = 90bisa diverifikasi manual. - Baris 14-15 (vektor @ matriks): vektor
(2,)dipromosikan otomatis — hasilnya vektor(3,), bukan matriks baris; nilai[90, 120, 150]sama dengan baris pertamaCkarena isinya memang identik. - Baris 17-20 (batch 3D):
(2,3,4) @ (2,4,5)menjalankan dua matmul(3,4)@(4,5)secara paralel dan menghasilkan(2,3,5); operand 2D biasa juga diterima dan disiarkan ke seluruh batch. - Baris 22-26 (
catversusstack):catmemperpanjang sumbu yang sudah ada — dua tensor(2,3)menjadi(4,3)atau(2,6)— sedangkanstackmenyisipkan sumbu baru sehingga hasilnya(2,2,3): tensor pertama dan kedua menjadi dua elemen batch.
Tabel Rumus Shape #
| Operasi | Syarat operand | Shape hasil |
|---|---|---|
A + B, A * B | sama, atau kompatibel broadcasting | bentuk setelah broadcasting |
A @ B (2D) | (n, k) dan (k, m) | (n, m) |
v @ B | (k,) dan (k, m) | (m,) |
A @ B (batch) | (..., n, k) dan (..., k, m) | (..., n, m) |
A.sum(dim=d) | d valid | sumbu d dihapus |
A.sum(dim=d, keepdim=True) | idem | sumbu d jadi panjang 1 |
A.max(dim=d) | idem | dua hasil: values dan indices |
torch.cat(list, dim=d) | shape sama kecuali sumbu d | panjang sumbu d dijumlah |
torch.stack(list, dim=d) | semua shape sama | sumbu d baru sepanjang jumlah tensor |
Katalog operasi tensor lengkap tersedia di docs.pytorch.org/docs/stable/torch.html
. Dua keluarga tadi mensyaratkan shape yang sama; kenyataannya model sering menjumlahkan tensor dengan bentuk berbeda — bias (C,) ke aktivasi (N, C). Aturan yang mengizinkannya, broadcasting versi PyTorch, adalah topik chapter berikutnya.