Semua arsitektur jaringan saraf di PyTorch, dari yang terdiri atas dua layer sampai model berskala besar, dibangun di atas kelas yang sama, yaitu nn.Module. Topik ini membahas pola kelas yang digunakan untuk mendefinisikan model: layer yang dideklarasikan di __init__, aliran data yang dirangkai di method forward(), dan cara objek model dipanggil seperti fungsi. Sebagai contoh, sebuah model klasifikasi kecil dengan dua layer ditulis lengkap, dijalankan, lalu aliran bentuk (shape) tensornya ditelusuri pada setiap tahap.
Pola kelas model#
Model di PyTorch didefinisikan sebagai subclass dari nn.Module, dan pola kelasnya terdiri atas tiga bagian yang selalu sama. Pertama, method __init__ memanggil super().__init__(), kemudian mendefinisikan layer-layer sebagai atribut. Kedua, method forward() merangkai aliran data dari masukan sampai keluaran. Ketiga, objek model dipanggil seperti fungsi biasa, tanpa perlu mendefinisikan __call__ sendiri.
Definisi layer di __init__ bukan sekadar kerapian. Ketika sebuah layer ditetapkan sebagai atribut, nn.Module mendaftarkannya bersama seluruh parameternya. Berkat pendaftaran itu, parameter dapat ditemukan oleh model.parameters(), ikut dipindahkan ketika model.to(device) dipanggil, dan ikut tersimpan pada state_dict. Mekanisme pendaftaran ini ditelusuri lebih rinci pada topik Parameter.
Contoh yang digunakan adalah model klasifikasi untuk catatan sensor suhu. Setiap sampel memiliki empat fitur pengukuran dan dikelompokkan ke salah satu dari tiga kategori suhu. Modelnya terdiri atas dua layer Linear yang dipisahkan oleh satu ReLU, susunan yang lazim untuk data tabular. Pola yang sama berlaku untuk model yang lebih besar: sebuah kelas model juga boleh memiliki kelas model lain sebagai atribut, dan pendaftarannya bekerja bertingkat sampai submodule terdalam.
File berikut memuat definisi lengkapnya. Method forward() menerima tensor masukan x, meneruskannya ke fc1, mengaktifkan hasilnya dengan ReLU, lalu mengembalikan keluaran fc2.
import torch
import torch.nn as nn
torch.manual_seed(0)
class KlasifikasiSuhu(nn.Module):
"""Klasifikasi tiga kategori suhu dari empat fitur sensor."""
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(4, 8)
self.aktivasi = nn.ReLU()
self.fc2 = nn.Linear(8, 3)
def forward(self, x):
h = self.fc1(x)
h = self.aktivasi(h)
logits = self.fc2(h)
return logits
model = KlasifikasiSuhu()
x = torch.randn(5, 4) # (N, in_features) = (5, 4)
logits = model(x) # pemanggilan seperti fungsi: __call__ meneruskan ke forward
print(logits.shape) # (N, out_features) = (5, 3)torch.Size([5, 3])Keluaran torch.Size([5, 3]) menyatakan tensor berbentuk (5, 3), yaitu lima sampel yang masing-masing menghasilkan tiga nilai. Masukan dibuat dengan torch.randn(5, 4), sehingga bentuknya (5, 4) dan cocok dengan in_features layer pertama. Nilai keluaran semacam ini disebut logits, yaitu nilai mentah model sebelum diubah menjadi probabilitas.
Model dipanggil seperti fungsi#
Kelas KlasifikasiSuhu tidak pernah mendefinisikan method __call__, tetapi model(x) tetap berjalan. Penjelasannya ada pada nn.Module: kelas dasar itu mendefinisikan __call__ yang meneruskan pemanggilan ke forward(). Dengan demikian, model(x) dan model.forward(x) menghasilkan nilai yang sama persis, sebagaimana dibuktikan potongan kode berikut.
import torch
import torch.nn as nn
torch.manual_seed(0)
class KlasifikasiSuhu(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(4, 8)
self.aktivasi = nn.ReLU()
self.fc2 = nn.Linear(8, 3)
def forward(self, x):
return self.fc2(self.aktivasi(self.fc1(x)))
model = KlasifikasiSuhu()
x = torch.randn(5, 4)
lewat_call = model(x) # jalur normal: __call__ meneruskan ke forward
lewat_forward = model.forward(x) # pemanggilan forward secara langsung
print(torch.equal(lewat_call, lewat_forward))Truetorch.equal mengembalikan True, sehingga kedua jalur pemanggilan memberikan tensor yang identik. Meskipun begitu, konvensi PyTorch adalah memanggil model dengan model(x). Alasannya, __call__ juga menjalankan hook, yaitu fungsi yang dieksekusi otomatis pada titik tertentu, misalnya untuk mencatat nilai aktivasi saat debugging. Pemanggilan forward() secara langsung melewati hook tersebut.
Aliran data dan bentuk tensor#
Diagram berikut memperlihatkan aliran tensor di dalam model(x) beserta bentuknya pada setiap tahap.
Layer fc1 mengubah dimensi terakhir dari 4 menjadi 8, sehingga bentuknya berubah dari (N, 4) menjadi (N, 8). ReLU bekerja per elemen dan tidak mengubah bentuk sama sekali. Layer fc2 mengubah dimensi terakhir dari 8 menjadi 3, menghasilkan logits berbentuk (N, 3).
Kesalahan umum#
Kesalahan pertama adalah lupa memanggil super().__init__() di awal __init__. Pendaftaran layer membutuhkan bagian internal nn.Module, dan bagian itu baru ada setelah inisialisasi kelas dasar dijalankan. Akibatnya, penetapan layer pertama memicu error. Kode berikut menangkap errornya agar pesan aslinya terlihat.
import torch
import torch.nn as nn
class TanpaSuper(nn.Module):
def __init__(self):
self.fc = nn.Linear(4, 3) # lupa memanggil super().__init__()
try:
TanpaSuper()
except AttributeError as e:
print("AttributeError:", str(e).splitlines()[0])AttributeError: cannot assign module before Module.__init__() callKesalahan kedua adalah memanggil model.forward(x) secara langsung. Nilai keluarannya sama, tetapi hook yang terpasang tidak dijalankan. Gunakan model(x) pada seluruh kode, baik saat pelatihan maupun saat inferensi.
Kesalahan ketiga adalah membuat layer di dalam forward(). Setiap pemanggilan akan membuat layer baru dengan bobot baru yang diacak, sehingga model tidak pernah memiliki bobot yang konsisten. Layer selalu didefinisikan di __init__, sedangkan forward() hanya merangkai layer yang sudah ada.
Ringkasan#
- Model didefinisikan sebagai subclass
nn.Module: layer dideklarasikan sebagai atribut di__init__setelahsuper().__init__(), danforward()merangkai aliran datanya. model(x)berjalan karena__call__darinn.Modulemeneruskan pemanggilan keforward(), sekaligus menjalankan hook yang terpasang.Linearmengubah dimensi terakhir dariin_featureskeout_features, sedangkanReLUbekerja per elemen tanpa mengubah bentuk.
Referensi#
- Learn the Basics — PyTorch
— Tutorial resmi yang memperkenalkan pola kelas
nn.Modulepada bagian Build the Neural Network. - PyTorch Documentation — PyTorch
— Dokumentasi resmi modul
torch.nnbeserta kontrak kelasnn.Module.