Semua teknik pada bab-bab sebelumnya mengasumsikan training sudah berjalan — namun sebelum epoch pertama, ada satu keputusan yang menentukan apakah sinyal belajar sanggup menembus jaringan: nilai awal bobot. Inisialisasi yang buruk membuat aktivasi menyusut tiap layer hingga gradien praktis nol, atau sebaliknya membengkak hingga nilai melimpah — dua wajah dari masalah vanishing dan exploding gradient yang dibahas pada chapter Backpropagation . Chapter ini menunjukkan mengapa memulai dari nol adalah pilihan terburuk, lalu membedakan dua keluarga inisialisasi modern — Xavier untuk aktivasi simetris dan Kaiming untuk ReLU — dengan pengukuran variansi aktual pada jaringan delapan layer.
Mengapa Nol Itu Pilihan Terburuk #
Ada dua alasan terpisah. Pertama, masalah simetri: bila seluruh bobot sebuah layer bernilai sama, seluruh neuron pada layer itu menerima input yang sama dan menghasilkan gradien yang sama pula — sepanjang training, neuron-neuron tersebut bergerak serentak dan tidak pernah menjadi berbeda; jaringan berlebar 256 efektifnya hanya berlebar 1. Kedua, masalah skala: bobot nol menghasilkan aktivasi nol di seluruh layer berikutnya, sehingga sinyal dan gradien mati sejak layer pertama — terlihat pada baris pertama keluaran pengujian kita nanti, yang mencatat variansi 0,000 di kedelapan layer.
Solusinya adalah memulai dari nilai acak kecil — namun seberapa kecil? Terlalu kecil, variansi menyusut tiap layer (vanishing); terlalu besar, variansi membengkak tiap layer (exploding). Analisis Glorot dan Bengio (2010) menemukan titik tengahnya: pertahankan variansi aktivasi agar tetap sama antar layer dengan menskala bobot sesuai jumlah koneksi masuk dan keluarnya.
Xavier dan Kaiming #
Dua keluarga inisialisasi yang menjadi standar industri hari ini lahir dari analisis tersebut. Xavier (sebutan lain: Glorot) menyetel sebaran bobot berdasarkan rata-rata jumlah koneksi masuk-keluar fan_avg = (fan_in + fan_out) / 2 — pasangan alami untuk aktivasi simetris seperti tanh dan sigmoid yang memetakan ke rentang berimbang. Kaiming (sebutan lain: He) menyesuaikan untuk ReLU: karena ReLU memotong separuh nilai menjadi nol, variansi keluarannya tinggal setengah, sehingga bobot perlu lebih besar dengan skala berdasarkan fan_in saja. Modul torch.nn.init menyediakan keduanya dalam beberapa sebaran:
| Inisialisasi | Aktivasi pasangan | Rumus skala | Fungsi torch |
|---|---|---|---|
| Xavier uniform | tanh, sigmoid | batas ±√(6/(fan_in+fan_out)) | nn.init.xavier_uniform_ |
| Xavier normal | tanh, sigmoid | std √(2/(fan_in+fan_out)) | nn.init.xavier_normal_ |
| Kaiming uniform | ReLU | batas ±√(6/fan_in) | nn.init.kaiming_uniform_ |
| Kaiming normal | ReLU | std √(2/fan_in) | nn.init.kaiming_normal_ |
Variansi Aktivasi yang Terukur #
Percakapan tentang “sinyal sehat” menjadi beralasan begitu diukur. Berkas varians_aktivasi.py menyusun jaringan uji delapan layer Linear lebar 256, mengalirkan masukan 256 sampel ber-variansi 1, lalu mencatat variansi aktivasi setelah tiap layer untuk empat kombinasi inisialisasi-aktivasi — termasuk dua kombinasi yang sengaja dipasangkan salah:
"""Variansi aktivasi per layer untuk empat strategi inisialisasi.
Jaringan uji: 8 hidden layer Linear lebar 256 tanpa bias acak
(bias di-nol-kan). Masukan: 256 sampel x 256 fitur dari N(0, 1).
Variansi aktivasi dicatat setelah tiap layer. Inisialisasi yang
cocok dengan aktivasinya menjaga variansi tetap pada rentang sehat;
inisialisasi nol membuat semua aktivasi mati sejak layer pertama.
"""
import torch
import torch.nn as nn
torch.manual_seed(42)
DALAM = 8 # jumlah hidden layer
LEBAR = 256 # lebar tiap layer
x = torch.randn(256, LEBAR) # variansi = 1
GAIN_TANH = nn.init.calculate_gain("tanh") # 5/3
KONFIGURASI = [
("nol + Tanh",
lambda w: nn.init.zeros_(w), torch.tanh),
("Xavier + Tanh",
lambda w: nn.init.xavier_uniform_(w, gain=GAIN_TANH), torch.tanh),
("Kaiming + ReLU",
lambda w: nn.init.kaiming_normal_(w, nonlinearity="relu"), torch.relu),
("Xavier-tanh + ReLU",
lambda w: nn.init.xavier_uniform_(w, gain=GAIN_TANH), torch.relu),
]
def jalankan(nama, init_fn, aktivasi):
torch.manual_seed(7) # bobot awal identik
layers = [nn.Linear(LEBAR, LEBAR) for _ in range(DALAM)]
for lin in layers:
init_fn(lin.weight)
nn.init.zeros_(lin.bias) # bias nol agar adil
a = x
variasi = []
for lin in layers:
a = aktivasi(lin(a))
variasi.append(a.var().item())
print(f"{nama:20s} " + " ".join(f"{v:6.3f}" for v in variasi))
print(f"variansi aktivasi setelah layer 1..{DALAM} "
f"(variansi input = {x.var().item():.3f})")
print(f"{'konfigurasi':20s} " + " ".join(f"{'L' + str(i):>6s}" for i in range(1, DALAM + 1)))
print("-" * 76)
for nama, init_fn, aktivasi in KONFIGURASI:
jalankan(nama, init_fn, aktivasi)Output yang Dihasilkan:
variansi aktivasi setelah layer 1..8 (variansi input = 1.012)
konfigurasi L1 L2 L3 L4 L5 L6 L7 L8
----------------------------------------------------------------------------
nol + Tanh 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
Xavier + Tanh 0.575 0.477 0.444 0.434 0.428 0.424 0.426 0.424
Kaiming + ReLU 0.690 0.697 0.752 0.922 0.937 0.761 0.708 0.569
Xavier-tanh + ReLU 0.945 1.309 1.557 2.277 2.778 3.589 5.391 7.699Mari kita telaah kode di atas baris per baris:
- Baris 18-19 (masukan dan gain): masukan uji diambil dari
randnsehingga variansinya 1;calculate_gain("tanh")mengembalikan 5/3 — faktor penguat yang dianjurkan Glorot agar tanh (yang menekan amplitudo di wilayah jenuhnya) tetap menjaga variansi. - Baris 21-30 (empat kombinasi): tiap entri memasangkan fungsi inisialisasi dengan fungsi aktivasi. Dua entri pertama adalah pasangan benar, entri keempat sengaja memakai Xavier-untuk-tanh bersama ReLU sebagai pembanding yang salah pasangan.
- Baris 34-38 (isolasi variabel): seed di-reset dan bias di-nol-kan di dalam
jalankanagar keempat baris keluaran hanya berbeda karena strategi inisialisasi, bukan karena keberuntungan acak atau kontribusi bias. - Baris 40-44 (pengukuran): aktivasi mengalir layer demi layer; setelah tiap layer,
a.var().item()mencatat variansi seluruh elemen — angka inilah yang menjadi kolom L1 sampai L8.
Empat baris keluaran menceritakan empat nasib. Baris “nol + Tanh” mati seketika: variansi 0,000 di semua layer — bukti langsung bahwa tanpa komponen acak, sinyal tidak pernah lewat dari layer pertama. Baris “Xavier + Tanh” stabil: variansi turun dari 0,575 lalu bertahan di sekitar 0,42-0,43 hingga layer kedelapan — inilah perilaku yang dirancang Glorot. Baris “Kaiming + ReLU” bergerak di rentang 0,57-0,94, cukup sehat untuk ReLU yang memang membiarkan separuh neuron bernilai nol. Baris “Xavier-tanh + ReLU” menanjak terus 0,945 → 1,309 → … → 7,699 — hampir delapan kali variansi input hanya dalam delapan layer; pada jaringan 50 layer, pembengkakan eksponensial semacam ini membuat nilai melimpah dan training gagal.
Katalog lengkap fungsi-fungsi torch.nn.init — termasuk constant_, orthogonal_, dan calculate_gain — terdokumentasi di docs.pytorch.org/docs/stable/nn.init.html
. Inisialisasi menjaga kesehatan sinyal sekali di awal; bab berikutnya memperkenalkan mekanisme yang menjaganya terus-menerus sepanjang training dengan menormalkan aktivasi di dalam jaringan itu sendiri: Batch Normalization.