Perceptron tumbang di depan XOR karena satu garis lurus tidak cukup. Solusinya bukan mengganti aturan pembelajaran, melainkan menyusun neuron menjadi jaringan berlapis: multilayer perceptron (MLP). Layer tersembunyi pertama membaca input mentah dan membangun fitur antara, layer berikutnya membaca fitur tersebut dan menyusun representasi yang semakin abstrak — struktur berlapis inilah asal kata deep pada deep learning. Pada chapter ini kita pelajari susunan input–hidden–output beserta konvensi matriks bobotnya, lalu membuktikan lewat forward pass NumPy murni bahwa jaringan kecil 2-2-1 menyelesaikan XOR dengan sempurna.
Susunan Input–Hidden–Output #
MLP terdiri atas tiga jenis layer dengan tanggung jawab berbeda. Input layer hanya meneruskan data — tanpa bobot dan tanpa perhitungan. Hidden layer melakukan transformasi: tiap neuronnya menghitung weighted sum atas layer sebelumnya lalu menerapkan fungsi aktivasi. Output layer menghasilkan jawaban akhir — satu neuron untuk binary classification, beberapa neuron untuk multi-class. Sebutan “2-2-1” berarti 2 neuron input, 2 neuron hidden, dan 1 neuron output; jumlah neuron input ditentukan fitur data, sedangkan jumlah neuron hidden adalah pilihan desain kita.
Diagram di atas sekaligus merangkum solusi XOR yang akan kita jalankan: hidden layer berisi gerbang OR dan gerbang AND, output layer menggabungkan keduanya. Detail perhitungannya menyusul setelah kita pahami cara menyimpan bobot seluruh layer.
Matriks Bobot per Layer #
Setiap layer menyimpan bobot dalam satu matriks dan bias dalam satu vektor. Konvensi yang dipakai NumPy, PyTorch, dan TensorFlow seragam: matriks bobot berbentuk (jumlah masukan, jumlah neuron) — baris ke-i berisi bobot dari masukan ke-i, kolom ke-j berisi seluruh bobot milik neuron ke-j. Satu batch data X berbentuk (jumlah contoh, jumlah fitur), sehingga seluruh layer dihitung dengan satu perkalian matriks X @ W + b — pola yang sudah kita latih pada chapter Aljabar Linear
.
Tabel berikut merangkum seluruh objek jaringan 2-2-1 untuk data XOR:
| Objek | Bentuk | Arti |
|---|---|---|
X | (4, 2) | Batch 4 contoh, masing-masing 2 fitur |
W1 | (2, 2) | Bobot input → hidden; kolom j milik neuron hidden ke-j |
b1 | (2,) | Bias tiap neuron hidden |
H | (4, 2) | Keluaran hidden layer untuk seluruh batch |
W2 | (2, 1) | Bobot hidden → output |
b2 | (1,) | Bias neuron output |
y | (4, 1) | Prediksi jaringan untuk seluruh batch |
Aturan bentuknya konsisten: (n, d) @ (d, h) → (n, h). Jumlah kolom matriks kiri harus sama dengan jumlah baris matriks kanan; hasilnya mewarisi jumlah contoh dari kiri dan jumlah neuron dari kanan.
Membuktikan MLP Menyelesaikan XOR #
Bobot pada contoh ini kita tulis manual agar logikanya terbaca penuh; cara mesin menemukan bobot sendiri menyusul pada chapter backpropagation. Dua neuron hidden sengaja dibuat sebagai gerbang klasik: neuron pertama dengan bias -0.5 berperilaku sebagai OR (aktif bila minimal satu input bernilai 1), neuron kedua dengan bias -1.5 berperilaku sebagai AND (aktif hanya bila kedua input bernilai 1). Neuron output menghitung h1 - h2 - 0.5 — secara logika: OR yang bukan AND. Berkas mlp_xor.py menjalankan forward pass seluruh jaringan:
"""MLP 2-2-1 dengan bobot pilihan manual menyelesaikan gerbang XOR.
Hidden layer membangun dua fitur baru dari input: gerbang OR dan
gerbang AND. Output layer menggabungkan keduanya menjadi XOR.
Hanya forward pass — tanpa training, bobot ditulis langsung.
"""
import numpy as np
def aktivasi_step(z):
"""Fungsi step elementwise: 1 bila z >= 0, selain itu 0."""
return (z >= 0.0).astype(int)
# Data XOR: 4 contoh, 2 fitur masukan
X = np.array([
[0.0, 0.0],
[0.0, 1.0],
[1.0, 0.0],
[1.0, 1.0],
])
target = np.array([0, 1, 1, 0])
# Layer 1 (2 masukan -> 2 neuron hidden); kolom ke-j = bobot neuron ke-j
W1 = np.array([
[1.0, 1.0],
[1.0, 1.0],
])
b1 = np.array([-0.5, -1.5])
# Layer 2 (2 hidden -> 1 output)
W2 = np.array([
[1.0],
[-1.0],
])
b2 = np.array([-0.5])
# Forward pass per tahap, bentuk dicetak di tiap baris
Z1 = X @ W1 + b1
H = aktivasi_step(Z1)
Z2 = H @ W2 + b2
y = aktivasi_step(Z2)
print(f"X {X.shape} masukan XOR")
print(f"Z1 {Z1.shape} = X @ W1 + b1")
print(f"H {H.shape} = step(Z1) -> fitur baru tiap contoh")
print(f"Z2 {Z2.shape} = H @ W2 + b2")
print(f"y {y.shape} = step(Z2) -> prediksi jaringan")
print()
print("H (hidden layer, kolom 1 = OR, kolom 2 = AND):")
print(H)
print()
print("Evaluasi tiap contoh:")
benar = 0
for i in range(len(X)):
pred = int(y[i, 0])
status = "benar" if pred == target[i] else "salah"
benar += pred == target[i]
print(f" x={X[i].astype(int)} h={H[i]} z2={Z2[i, 0]:+.1f}"
f" y={pred} target={target[i]} -> {status}")
print(f"Akurasi: {benar}/{len(X)}")Output yang Dihasilkan:
X (4, 2) masukan XOR
Z1 (4, 2) = X @ W1 + b1
H (4, 2) = step(Z1) -> fitur baru tiap contoh
Z2 (4, 1) = H @ W2 + b2
y (4, 1) = step(Z2) -> prediksi jaringan
H (hidden layer, kolom 1 = OR, kolom 2 = AND):
[[0 0]
[1 0]
[1 0]
[1 1]]
Evaluasi tiap contoh:
x=[0 0] h=[0 0] z2=-0.5 y=0 target=0 -> benar
x=[0 1] h=[1 0] z2=+0.5 y=1 target=1 -> benar
x=[1 0] h=[1 0] z2=+0.5 y=1 target=1 -> benar
x=[1 1] h=[1 1] z2=-0.5 y=0 target=0 -> benar
Akurasi: 4/4Empat dari empat contoh benar — jaringan yang barusan kita susun menuntaskan masalah yang membuat perceptron berputar selamanya. Mari kita telaah kode di atas baris per baris:
- Baris 11-13 (
def aktivasi_step): versi elementwise dari fungsi step;(z >= 0.0)menghasilkan array boolean yang diubahastype(int)menjadi0/1, sehingga satu panggilan memroses seluruh matriks. - Baris 16-23 (
X,target): data XOR yang sama dengan chapter Perceptron — pembanding yang adil karena datanya identik. - Baris 25-30 (
W1,b1): bobot input → hidden. Kedua kolom sama-sama[1, 1]; pembeda perilaku kedua neuron justru biasnya:-0.5menghasilkan OR,-1.5menghasilkan AND. - Baris 32-37 (
W2,b2): bobot hidden → output. Nilai[1, -1]berarti output menjumlahkanh1lalu mengurangih2, dengan bias-0.5sebagai ambang. - Baris 39-43 (forward pass): empat baris = empat tahap: transformasi affine layer 1, aktivasi hidden, transformasi affine layer 2, aktivasi output.
- Baris 45-62 (pelaporan): mencetak bentuk tiap tahap, matriks hidden, dan evaluasi tiap contoh lengkap dengan hitungan akurasi.
Kenapa Hidden Layer Berhasil #
Rahasianya terlihat pada matriks H: hidden layer menulis ulang tiap contoh dalam koordinat baru. Titik (0, 1) dan (1, 0) yang semula berjauhan kini sama-sama dipetakan ke (1, 0); titik (0, 0) dipetakan ke (0, 0) dan (1, 1) ke (1, 1). Di ruang asli, kelas 1 menempati dua diagonal berseberangan sehingga tak terpisahkan garis. Di ruang hidden, seluruh kelas 1 berkumpul di satu titik dan kelas 0 tinggal di dua titik lain — garis h1 − h2 = 0.5 memisahkannya dengan mudah, dan persis garis itulah yang dihitung neuron output.
Pemetaan ulang inilah fungsi sebenarnya hidden layer: membangun representasi masalah yang membuat keputusan akhir menjadi linear. Jaringan yang lebih dalam mengulang strategi yang sama berlapis-lapis — fitur tepi dari piksel, bentuk dari tepi, objek dari bentuk — hierarki representasi yang kita bahas pada chapter Apa itu Deep Learning
. Detail operator perkalian matriksnya dapat dibaca pada dokumentasi resmi numpy.matmul
.
Satu persoalan masih menggantung: seluruh jaringan di chapter ini bertumpu pada fungsi step yang melompat tajam di titik nol. Lompatan tersebut justru menjadi penghambat utama ketika jaringan harus dilatih, karena turunannya nol di semua titik dan tak terdefinisi di titik lompatan. Chapter berikutnya memperkenalkan keluarga fungsi aktivasi mulus — sigmoid, tanh, ReLU, hingga softmax — beserta alasan memilih masing-masing.