Seluruh komponen sudah kita kuasai terpisah-pisah: neuron dengan weighted sum dan bias, matriks bobot per layer, serta fungsi aktivasi. Forward propagation adalah proses merakit komponen-komponen tersebut menjadi alur prediksi yang utuh: data mengalir satu arah dari input, melewati hidden layer demi hidden layer, hingga keluar sebagai prediksi di output. Inilah separuh dari siklus training yang kita gambar di chapter Cara Kerja Neural Network — separuh sisanya (mengukur galat dan memperbaiki bobot) menyusul pada chapter-chapter berikutnya. Pada chapter ini kita menulis forward pass dua layer dengan angka konkret yang kecil, memproses satu batch empat contoh sekaligus, dan memeriksa bentuk matriks di setiap tahap agar tidak ada yang tersisip secara tak terduga.
Alur Data dari Input ke Output #
Forward propagation tersusun atas pasangan tahap yang berulang: transformasi affine (Z = A @ W + b) diikuti fungsi aktivasi (A_baru = f(Z)). Notasi yang dipakai literatur dan framework konsisten: Z menyatakan skor mentah hasil perkalian matriks sebelum aktivasi (pre-activation), sedangkan A menyatakan keluaran layer setelah aktivasi. Untuk jaringan dua layer, alurnya:
Bentuk di tiap simpul diagram adalah bentuk matriks setelah tahap tersebut dijalankan. Perhatikan pola pentingnya: jumlah baris (empat contoh) dipertahankan dari awal hingga akhir, sedangkan jumlah kolom berganti mengikuti jumlah neuron tiap layer — dari 2 fitur masukan, menjadi 3 neuron hidden, menjadi 1 keluaran.
Konvensi Bentuk Matriks #
Dua kesepakatan bentuk membuat seluruh perhitungan rapi. Pertama, satu baris matriks data adalah satu contoh: X berbentuk (jumlah contoh, jumlah fitur). Kedua, matriks bobot berbentuk (jumlah masukan, jumlah neuron) sehingga perkalian X @ W langsung menghasilkan skor seluruh neuron untuk seluruh contoh. Tabel berikut merangkum perjalanan bentuk pada jaringan yang akan kita jalankan:
| Tahap | Operasi | Bentuk operasi | Bentuk hasil |
|---|---|---|---|
| Affine layer 1 | X @ W1 + b1 | (4, 2) @ (2, 3) | (4, 3) |
| Aktivasi hidden | sigmoid(Z1) | elemen per elemen | (4, 3) |
| Affine layer 2 | A1 @ W2 + b2 | (4, 3) @ (3, 1) | (4, 1) |
| Aktivasi output | sigmoid(Z2) | elemen per elemen | (4, 1) |
Penjumlahan bias bekerja lewat broadcasting: b1 berbentuk (3,) ditambahkan ke setiap baris hasil perkalian — mekanisme persis seperti yang dibahas pada chapter Broadcasting dan Vectorization
.
Forward Pass Dua Layer dengan Angka Konkret #
Kita pakai kembali empat pola XOR sebagai batch masukan, hidden layer tiga neuron dengan sigmoid, dan satu neuron keluaran bersistem sigmoid. Bobot ditulis manual dan belum dilatih — fokus kita adalah alur dan bentuk, bukan ketepatan prediksi. Berkas forward_pass.py mencetak bentuk serta isi matriks di tiap tahap:
"""Forward propagation dua layer dengan NumPy: masuk -> hidden -> keluar.
Satu batch berisi 4 contoh diproses sekaligus lewat dua layer.
Bobot ditulis manual dan belum dilatih; fokus kita adalah alur data
serta bentuk (shape) matriks pada tiap tahap.
"""
import numpy as np
def sigmoid(z):
"""Fungsi aktivasi sigmoid."""
return 1.0 / (1.0 + np.exp(-z))
# Batch masukan: 4 contoh, 2 fitur (pola XOR dari chapter sebelumnya)
X = np.array([
[0.0, 0.0],
[0.0, 1.0],
[1.0, 0.0],
[1.0, 1.0],
])
# Layer 1: 2 masukan -> 3 neuron hidden (kolom ke-j = bobot neuron ke-j)
W1 = np.array([
[0.15, -0.25, 0.20],
[0.40, 0.10, -0.30],
])
b1 = np.array([0.10, 0.00, -0.10])
# Layer 2: 3 hidden -> 1 keluaran
W2 = np.array([[0.50], [0.30], [-0.40]])
b2 = np.array([0.05])
# Tahap 1: transformasi affine layer hidden
Z1 = X @ W1 + b1
print(f"X shape {X.shape} (4 contoh, 2 fitur)")
print(f"W1 shape {W1.shape} b1 shape {b1.shape}")
print(f"Z1 shape {Z1.shape} = X @ W1 + b1")
print(np.round(Z1, 4))
print()
# Tahap 2: aktivasi hidden layer
A1 = sigmoid(Z1)
print(f"A1 shape {A1.shape} = sigmoid(Z1)")
print(np.round(A1, 4))
print()
# Tahap 3: transformasi affine layer keluaran
Z2 = A1 @ W2 + b2
print(f"W2 shape {W2.shape} b2 shape {b2.shape}")
print(f"Z2 shape {Z2.shape} = A1 @ W2 + b2")
print(np.round(Z2, 4))
print()
# Tahap 4: aktivasi keluaran
y = sigmoid(Z2)
print(f"y shape {y.shape} = sigmoid(Z2)")
print(np.round(y, 4))Output yang Dihasilkan:
X shape (4, 2) (4 contoh, 2 fitur)
W1 shape (2, 3) b1 shape (3,)
Z1 shape (4, 3) = X @ W1 + b1
[[ 0.1 0. -0.1 ]
[ 0.5 0.1 -0.4 ]
[ 0.25 -0.25 0.1 ]
[ 0.65 -0.15 -0.2 ]]
A1 shape (4, 3) = sigmoid(Z1)
[[0.525 0.5 0.475 ]
[0.6225 0.525 0.4013]
[0.5622 0.4378 0.525 ]
[0.657 0.4626 0.4502]]
W2 shape (3, 1) b2 shape (1,)
Z2 shape (4, 1) = A1 @ W2 + b2
[[0.2725]
[0.3582]
[0.2524]
[0.3372]]
y shape (4, 1) = sigmoid(Z2)
[[0.5677]
[0.5886]
[0.5628]
[0.5835]]Empat contoh diproses dalam satu kali jalan tanpa satu pun loop eksplisit. Mari kita telaah kode di atas baris per baris:
- Baris 11-13 (
def sigmoid): fungsi aktivasi dari chapter Fungsi Aktivasi , bekerja elemen per elemen sehingga satu panggilan memroses seluruh matriksZ1. - Baris 16-22 (
X): batch masukan(4, 2)— empat pola XOR; setiap baris satu contoh, setiap kolom satu fitur. - Baris 24-29 (
W1,b1): bobot layer hidden berbentuk(2, 3): dua masukan menuju tiga neuron. Kolom pertama[0.15, 0.40]adalah seluruh bobot milik neuron hidden pertama. - Baris 31-33 (
W2,b2): bobot layer keluaran berbentuk(3, 1): tiga masukan hidden menuju satu neuron keluaran. - Baris 35-41 (tahap 1):
X @ W1 + b1menghasilkanZ1berbentuk(4, 3)— skor mentah tiap neuron hidden untuk tiap contoh. Baris pertama[0.1, 0.0, -0.1]milik contoh(0, 0)yang bobotnya nyaris tak menggerakkan skor karena kedua inputnya nol; hanya bias yang berkontribusi. - Baris 43-47 (tahap 2): sigmoid menjepit seluruh nilai
Z1ke rentang(0, 1)tanpa mengubah bentuk; nilai0.1menjadi0.525, nilai-0.4menjadi0.4013. - Baris 49-54 (tahap 3):
A1 @ W2 + b2merangkum tiga nilai hidden tiap contoh menjadi satu skorZ2berbentuk(4, 1). - Baris 56-59 (tahap 4): sigmoid terakhir memetakan skor menjadi prediksi
y— satu angka probabilitas per contoh.
Batch dan Manfaat Vektorisasi #
Satu detail yang mudah terlewat: matriks bobot yang sama dipakai untuk seluruh contoh dalam batch. Contoh (0, 0) dan (1, 1) dihitung oleh W1 dan W2 yang identik — hanya nilainya yang berbeda sehingga hasilnya berbeda. Berkat bentuk matriks, memproses empat contoh atau empat juta contoh tetap ditulis sebagai dua perkalian matriks yang sama; yang berubah hanya jumlah baris X. Keunggulan inilah alasan NumPy, PyTorch, dan TensorFlow menempatkan operasi matriks — bukan loop Python — sebagai fondasi seluruh perhitungan, sebagaimana diukur langsung pada chapter Broadcasting dan Vectorization
. Rincian operator perkalinya terdokumentasi pada numpy.matmul
.
Forward propagation menghasilkan prediksi, tetapi belum ada yang memberi tahu seberapa jauh prediksi tersebut meleset dari target. Langkah berikutnya pada siklus training adalah mengubah jarak prediksi-target menjadi satu angka bernama loss — meteran yang akan memandu seluruh proses pembelajaran pada chapter berikutnya.