Melatih CNN dari nol membutuhkan data yang banyak — pada bagian sebelumnya 72 gambar masih cukup, tetapi bagaimana bila hanya 24 gambar tersedia? Transfer learning menjawabnya dengan memisahkan dua kebutuhan: fitur visual umum dipelajari dari data domain lain, sedangkan keputusan klasifikasi akhir dipelajari dari data yang sedikit. Skrip src/latih_transfer.py mensimulasikan pola tersebut di atas dataset hewan kita, meniru alur pemakaian model pretrained yang dibahas di chapter Transfer Learning untuk Gambar
.
Merancang Skenario Domain Sumber dan Target #
Data latih 72 gambar dipecah menjadi dua domain melalui bagi_sumber_target() di src/dataset.py: domain sumber A berisi 48 gambar (16 per kelas) berperan sebagai “model pretrained” kita, dan domain target B berisi 24 gambar (8 per kelas) sebagai data miskin yang tersedia untuk tugas akhir. Data uji 24 gambar tetap terpisah dan tidak pernah dilatih.
Dua model kemudian diadu pada data uji yang sama:
- Dari nol: CNN baru dilatih penuh hanya pada 24 gambar domain B.
- Transfer: CNN pra-dilatih pada 48 gambar domain A, ekstraktor cirinya dibekukan, kepala klasifikasi diganti baru, dan hanya kepala itulah yang dilatih pada domain B.
Tiga Langkah Inti Transfer #
Seluruh keunggulan transfer learning di src/latih_transfer.py sesungguhnya hanya tiga langkah. Dua langkah pertama berurutan dalam satu fungsi:
# Bekukan ekstraktor ciri: gradien tidak lagi mengubah layer convolution.
for parameter in model.ciri.parameters():
parameter.requires_grad_(False)
# Ganti kepala klasifikasi dengan kepala baru yang belum terlatih.
model.kepala = nn.Sequential(
nn.Flatten(),
nn.Linear(16 * 4 * 4, 32),
nn.ReLU(),
nn.Linear(32, 3),
)Langkah ketiga berada pada penyusunan optimizer — hanya parameter kepala yang boleh masuk:
optimizer = torch.optim.Adam(
[p for p in model.parameters() if p.requires_grad], lr=LR_KEPALA
)Mari kita telaah ketiga langkah tersebut:
requires_grad_(False): mematikan pelacakan gradien seluruh parametermodel.ciri; setelahbackward(), atribut.gradlayer convolution tetapNone— perilaku yang sudah kita uji di Bagian 2.model.kepala = nn.Sequential(...): menimpa kepala lama (yang terlatih untuk domain A) dengan kepala baru berbobot acak; fitur convolution tetap utuh.- Penyaringan optimizer:
[p for p in model.parameters() if p.requires_grad]memastikan Adam hanya menyentuh 8.323 parameter kepala — tanpa penyaringan ini, parameter beku tetap di-update lewat momentum Adam dan pembekuan menjadi sia-sia.
Learning rate kepala sengaja lebih tinggi (LR_KEPALA = 3e-3, tiga kali lipat pelatihan penuh) karena ruang cari parameter jauh lebih kecil: hanya kepala yang bergeser, sehingga langkah yang lebih besar justru mempercepat penyesuaian tanpa risiko tinggi.
Hasil Nyata Kedua Skenario #
python3 src/latih_transfer.pyOutput yang Dihasilkan:
data : sumber A 48 gambar | target B 24 gambar | uji 24 gambar
pelatihan : Adam, batch 16, 20 epoch per tahap (kepala transfer: lr 0.003)
skenario 1: DARI NOL (latih penuh pada 24 gambar B)
epoch 1 | loss latih 1.1022 | akurasi uji 0.333
epoch 5 | loss latih 1.0598 | akurasi uji 0.542
epoch 10 | loss latih 1.0183 | akurasi uji 0.542
epoch 15 | loss latih 0.9108 | akurasi uji 0.583
epoch 20 | loss latih 0.7526 | akurasi uji 0.667
skenario 2: TRANSFER (pra-latih 48 gambar A -> bekukan ciri -> kepala baru)
tahap pra-latih pada domain sumber A:
epoch 1 | loss latih 1.0995 | akurasi uji 0.333
epoch 5 | loss latih 1.0519 | akurasi uji 0.625
epoch 10 | loss latih 0.9194 | akurasi uji 0.708
epoch 15 | loss latih 0.6947 | akurasi uji 0.833
epoch 20 | loss latih 0.4299 | akurasi uji 0.958
ciri dibekukan (1248 parameter), kepala baru dilatih (8323 parameter)
tahap adaptasi kepala pada domain target B:
epoch 1 | loss latih 1.1138 | akurasi uji 0.333
epoch 5 | loss latih 0.9564 | akurasi uji 0.625
epoch 10 | loss latih 0.7933 | akurasi uji 0.583
epoch 15 | loss latih 0.6029 | akurasi uji 0.750
epoch 20 | loss latih 0.4540 | akurasi uji 0.875
perbandingan akurasi uji (data sama, 24 gambar):
dari nol (hanya 24 gambar B) : 0.667
transfer (pra-latih A + kepala B): 0.875Angka-angka di atas layak dibaca pelan-pelan. Model dari nol menemui kesulitan yang wajar untuk 24 gambar: loss turun lambat dan akurasi berhenti di 0.667. Pra-latih pada domain A mencapai 0.958 — ekstraktor cirinya sudah mengenali tepi, bentuk memanjang, dan pola telinga. Setelah dibekukan dan dipasangkan kepala baru, kepala itu belajar jauh lebih cepat pada data B yang sama persis dengan skenario satu: akurasi akhirnya 0.875, unggul 0.208.
Pada dataset nyata, “domain A” digantikan model pretrained seperti ResNet yang dilatih pada jutaan gambar ImageNet — fiturnya jauh lebih kaya, tetapi tiga langkah intinya persis sama: muat bobot, bekukan ciri, latih kepala. Bagian terakhir proyek ini menutup dengan hasil lengkap CNN dari nol dan inferensi sampel nyata.