Sebuah layer pada neural network pada dasarnya adalah perkalian matriks ditambah bias dan fungsi aktivasi. Karena itu, kesalahan kecil memilih operator — @ alih-alih * — dapat membuat model diam-diam menghasilkan keluaran yang salah tanpa pesan galat. Chapter ini membedah perbedaan perkalian matriks (matmul) dan perkalian elemen per elemen, lalu merangkum operasi aljabar linear lain: transpose, matriks identitas, dan invers. Seluruh konsep ditutup dengan contoh forward pass satu layer yang benar-benar dijalankan.
Dua Jenis Perkalian yang Sering Tertukar #
Operator @ pada NumPy menjalankan perkalian matriks: sel di baris i kolom j berisi jumlah perkalian baris i dari matriks kiri dengan kolom j dari matriks kanan. Operator * menjalankan perkalian elemen per elemen (Hadamard product): sel di posisi yang sama dikalikan langsung. Keduanya menghasilkan nilai yang berbeda pada matriks yang sama, seperti akan kita lihat pada contoh berikut.
Aturan bentuknya juga berbeda. Perkalian matriks mensyaratkan jumlah kolom matriks kiri sama dengan jumlah baris matriks kanan — (m, n) @ (n, p) menghasilkan (m, p). Perkalian elemen per elemen mensyaratkan kedua bentuk sama (atau kompatibel lewat broadcasting).
Matmul, Elementwise, Transpose, dan Invers #
Berkas matmul-vs-elementwise.py membandingkan kedua operator pada pasangan matriks yang sama, lalu melanjutkan ke transpose, matriks identitas, dan invers dari submodul np.linalg.
import numpy as np
A = np.array([[1.0, 2.0],
[3.0, 4.0]])
B = np.array([[5.0, 6.0],
[7.0, 8.0]])
# Perkalian matriks: tiap sel = baris A . kolom B
print("A @ B =\n", A @ B)
# Perkalian elemen per elemen (Hadamard product)
print("A * B =\n", A * B)
# Transpose menukar baris dengan kolom
print("A.T =\n", A.T)
print("bentuk A.T:", A.T.shape)
# Matriks identitas: elemen netral perkalian matriks
I = np.eye(2)
print("A @ I =\n", A @ I)
# Invers: matriks yang membatalkan C pada perkalian matriks
C = np.array([[4.0, 2.0],
[7.0, 6.0]])
inv_C = np.linalg.inv(C)
print("inv(C) =\n", inv_C)
print("C @ inv(C) =\n", C @ inv_C)
print("dekat identitas:", np.allclose(C @ inv_C, np.eye(2)))
print("determinan C :", np.linalg.det(C))Output yang Dihasilkan:
A @ B =
[[19. 22.]
[43. 50.]]
A * B =
[[ 5. 12.]
[21. 32.]]
A.T =
[[1. 3.]
[2. 4.]]
bentuk A.T: (2, 2)
A @ I =
[[1. 2.]
[3. 4.]]
inv(C) =
[[ 0.6 -0.2]
[-0.7 0.4]]
C @ inv(C) =
[[ 1.00000000e+00 0.00000000e+00]
[-2.22044605e-16 1.00000000e+00]]
dekat identitas: True
determinan C : 9.999999999999998Mari kita telaah kode di atas baris per baris:
- Baris 10 (
A @ B): perkalian matriks menghasilkan[[19, 22], [43, 50]]. Sel kiri atas dihitung sebagai1*5 + 2*7 = 19— baris pertamaAdikalikan kolom pertamaB, lalu dijumlahkan. - Baris 14 (
A * B): perkalian elemen menghasilkan[[5, 12], [21, 32]]karena sel-sel pada posisi yang sama dikalikan langsung (1*5,2*6,3*7,4*8). Bandingkan sel kiri atas kedua hasil:19pada matmul kontras dengan5pada perkalian elemen. - Baris 18-19 (
A.T): transpose menukar baris dengan kolom, sehingga matriks(2, 2)ini tampak “bercermin” pada diagonal utama. Untuk matriks non-persegi,shapeikut bertukar. - Baris 23 (
A @ I): matriks identitas darinp.eye(2)berperan seperti angka1pada perkalian skalar — hasilnya kembali menjadiAsendiri. - Baris 27-29 (
np.linalg.inv(C)): invers matriks berperan seperti kebalikan perkalian. PerkalianC @ inv(C)menghasilkan matriks identitas, terbukti dari pemeriksaannp.allcloseyang mengembalikanTrue. - Baris 30 (
np.linalg.det(C)): determinan bernilai 10 (nilai9.999999999999998adalah pembulatan titik mengambang). Determinan nol menandakan matriks tidak punya invers, dannp.linalg.invakan mengeluarkanLinAlgErrorpada kasus tersebut.
Mengapa Matmul Menjadi Inti Forward Pass #
Sebuah layer berpadat (dense layer) menghitung keluaran h = W @ x + b, dengan W menyimpan bobot koneksi antar neuron dan x menyimpan nilai masukan. Setiap neuron menjumlahkan seluruh masukan yang diberi bobot — persis seperti perkalian baris demi kolom pada @. Ketika model tersusun dari banyak layer, forward pass menjadi rangkaian perkalian matriks beruntun, dan GPU menghitung perkalian matriks jauh lebih cepat daripada operasi apa pun yang ditulis sebagai perulangan Python.
Berkas forward-pass-kecil.py membangun satu layer dengan 2 masukan dan 3 neuron, memproses satu contoh data, lalu memproses 4 contoh sekaligus dalam bentuk batch.
import numpy as np
np.random.seed(42)
# Layer kecil: 2 masukan -> 3 neuron
W = np.random.randn(3, 2) # bobot, bentuk (neuron, masukan)
b = np.array([0.1, -0.2, 0.05]) # bias, satu per neuron
x = np.array([0.5, -1.5]) # satu contoh data, 2 fitur
# Forward pass satu layer: h = W @ x + b
z = W @ x
h = z + b
print("z = W @ x :", z)
print("h = z + b :", h)
# Fungsi aktivasi ReLU: nilai negatif menjadi nol
keluaran = np.maximum(h, 0.0)
print("ReLU(h) :", keluaran)
# Versi batch: 4 contoh diproses sekaligus
X = np.array([[0.5, -1.5],
[1.0, 2.0],
[-0.7, 0.3],
[0.0, 1.0]])
Z = X @ W.T # (4, 2) @ (2, 3) -> (4, 3)
H = np.maximum(Z + b, 0.0)
print("Z =\n", Z)
print("H =\n", H)Output yang Dihasilkan:
z = W @ x : [ 0.45575353 -1.96070052 0.23412875]
h = z + b : [ 0.55575353 -2.16070052 0.28412875]
ReLU(h) : [0.55575353 0. 0.28412875]
Z =
[[ 4.55753528e-01 -1.96070052e+00 2.34128748e-01]
[ 2.20185551e-01 3.69374825e+00 -7.02427289e-01]
[-3.89179197e-01 3.52698025e-03 9.36662752e-02]
[-1.38264301e-01 1.52302986e+00 -2.34136957e-01]]
H =
[[0.55575353 0. 0.28412875]
[0.32018555 3.49374825 0. ]
[0. 0. 0.14366628]
[0. 1.32302986 0. ]]Mari kita telaah kode di atas baris per baris:
- Baris 7 (
W = np.random.randn(3, 2)): bobot disusun dengan baris = neuron dan kolom = masukan, sehingga bentuknya(3, 2)untuk 3 neuron yang menerima 2 masukan. Seed 42 membuat nilai bobot tetap sama setiap eksekusi. - Baris 11 (
x = np.array([0.5, -1.5])): satu contoh data berbentuk vektor(2,). NumPy memperlakukan vektor ini sebagai kolom saat berhadapan dengan@. - Baris 14-15 (
z = W @ x,h = z + b):W @ xmenghasilkan vektor(3,)— satu nilai per neuron. Penjumlahanz + bmenambahkan bias per neuron lewat aturan broadcasting dari Chapter sebelumnya. - Baris 19 (
np.maximum(h, 0.0)): fungsi aktivasi ReLU mengubah nilai negatif menjadi nol. Skalar0.0disiarkan ke seluruh elemenh, dan neuron kedua yang bernilai-2.16menjadi0.pada keluaran. - Baris 28 (
Z = X @ W.T): batchXberbentuk(4, 2)— barisnya contoh data, sesuai konvensi deep learning. Agar perkalian valid, bobot ditranspose menjadi(2, 3), sehingga hasilnya(4, 3): satu baris keluaran untuk setiap contoh. Baris pertamaZsama persis denganzversi satu contoh — bukti kedua jalur menghitung hal yang sama. - Baris 29 (
H = np.maximum(Z + b, 0.0)): bias disiarkan ke 4 baris sekaligus dan ReLU diterapkan elemen per elemen, memperlihatkan bagaimana broadcasting dan matmul bekerja sama dalam satu baris kode.
Peta Operasi untuk Neural Network #
Tabel berikut merangkum operasi yang telah kita uji beserta perannya di kode model:
| Operasi | Operator / fungsi NumPy | Peran pada neural network |
|---|---|---|
| Perkalian matriks | A @ B atau np.matmul | Inti perhitungan layer pada forward pass |
| Perkalian elemen | A * B | Mask dan gate pada arsitektur tertentu, misalnya attention |
| Transpose | A.T | Menyesuaikan konvensi bentuk bobot dan batch |
| Identitas | np.eye(n) | Uji kebenaran invers, matriks netral |
| Invers | np.linalg.inv(A) | Solusi sistem linear, uji kondisionalitas |
| Determinan | np.linalg.det(A) | Deteksi matriks singular (tanpa invers) |
| Norma vektor | np.linalg.norm(x) | Regularisasi, pengukuran besar gradien |
Dokumentasi lengkap submodul aljabar linear tersedia di numpy.org/doc/stable/reference/routines.linalg dan aturan perkalian matriks NumPy di numpy.org/doc/stable/reference/generated/numpy.matmul .
Kode model yang kita tulis sejauh ini memakai angka yang sudah tersusun rapi dalam array. Data nyata jarang datang dalam bentuk demikian — data biasanya datang sebagai tabel CSV dengan kolom teks dan angka campuran. Chapter berikutnya memperkenalkan pandas sebagai jembatan dari tabel mentah menjadi array siap latih.