Dua bahan proyek kini tersedia: backbone terlatih dari Bagian 1 dan 30 sampel tugas B dari Bagian 2. Bagian ini merangkainya lewat tiga langkah baku transfer learning — muat bobot, bekukan backbone, latih head baru — semuanya di dalam src/transfer.py. Mekanisme pembekuan adalah intinya: atribut requires_grad=False memberi tahu autograd agar tidak menghitung gradien bagi parameter backbone, sehingga optimizer hanya mengubah head dan fitur hasil pelatihan tugas A terjaga utuh.
Membekukan Backbone, Memasang Head Baru #
Dua fungsi pertama pada src/transfer.py melakukan persis alur tersebut:
def muat_backbone():
"""Muat backbone terlatih; latih tugas A dulu bila berkas belum ada."""
if not BERKAS_BACKBONE.exists():
latih_backbone(cetak=False)
backbone = CNNBackbone()
backbone.load_state_dict(
torch.load(BERKAS_BACKBONE, map_location="cpu", weights_only=True)
)
return backbone
def buat_model_transfer():
"""Bekukan backbone lalu pasang head baru; kembalikan model utuh."""
backbone = muat_backbone()
for p in backbone.parameters():
p.requires_grad_(False) # inti transfer learning: freeze
torch.manual_seed(SEED) # init head tetap sama apa pun
kepala_b = nn.Linear(512, 5) # keadaan RNG sebelumnya
return ModelGabung(backbone, kepala_b)Mari kita telaah fungsi di atas baris per baris:
if not BERKAS_BACKBONE.exists(): skrip bersifat mandiri — pembaca yang belum menjalankanpretrained.pytetap bisa menjalankantransfer.pykarena backbone dilatih otomatis saat diperlukan; bila berkas sudah ada, pemuatan hanya butuh sepersekian detik.backbone.load_state_dict(torch.load(..., weights_only=True)): bobot dari/tmp/backbone_digit.ptmengisi arsitekturCNNBackboneyang masih acak —weights_only=Truemembatasi checkpoint berisi tensor saja, mode aman bila checkpoint berasal dari sumber lain.p.requires_grad_(False): seluruh 4800 parameter backbone dibekukan dalam satu perulangan; setelah baris ini, autograd berhenti melacaknya dan.gradparameter backbone akan tetapNone.torch.manual_seed(SEED)sebelumnn.Linear(512, 5): inisialisasi head dibuat deterministik apa pun urutan pemanggilan sebelumnya, sehingga hasiltransfer.pyidentik baik dijalankan sendiri maupun lewatbandingkan.py.
Melatih Head Saja #
Fungsi latih_transfer menyaring parameter yang masih belajar sebelum membuat optimizer — blok pencetakan ringkas di antara kedua bagian ini dilewati agar fokus tetap pada logika:
model = buat_model_transfer()
param_dilatih = [p for p in model.parameters() if p.requires_grad]
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(param_dilatih, lr=1e-3)
gen = torch.Generator().manual_seed(SEED)
for _ in range(jumlah_epoch):
acakan = torch.randperm(len(X_latih), generator=gen)
latih_epoch(model, optimizer, criterion,
X_latih, y_latih, acakan, UKURAN_BATCH_B)Baris param_dilatih = [p for p in model.parameters() if p.requires_grad] adalah penjaga kejujuran eksperimen: optimizer hanya menerima 2565 parameter head. PyTorch memang melewatkan parameter tanpa gradien di dalam torch.optim.Adam, tetapi penyaringan eksplisit membuat kontrak “hanya head yang belajar” terlihat langsung di kode — dan angka 2565 parameter dilatih pada keluaran berasal dari daftar ini, bukan dari asumsi.
Menjalankan Transfer Learning #
python3 src/transfer.pyOutput yang Dihasilkan:
data tugas B : 30 latih + 200 uji (digit 5-9)
backbone : 4800 parameter terbekukan (requires_grad=False)
head baru : 2565 parameter dilatih
pelatihan : Adam lr=0.001, batch 15, 10 epoch (hanya head)
akurasi uji tugas B: 0.835Dari 30 sampel latih (enam gambar per kelas secara rata-rata), model mencapai akurasi 0.835 pada 200 sampel uji — 167 gambar digit 5-9 dikenali benar tanpa satu pun parameter backbone berubah. Keluaran juga mencatat pembagian peran secara eksplisit: 4800 parameter beku, 2565 parameter dilatih.
Angka 0.835 baru bermakna setelah ada pembanding. Bagian berikutnya melatih arsitektur yang sama dari bobot acak lalu menyandingkan keduanya dalam satu tabel.