timm: Gudang 1000+ Model Computer Vision Siap Pakai di PyTorch
Halo temen-temen, di tutorial kali ini aku mau ngajak kalian kenalan sama library yang menurutku wajib ada di toolbox siapa pun yang ngerjain computer vision pakai PyTorch, namanya timm, kependekan dari PyTorch Image Models. Kalau kalian pernah bingung mau pakai backbone apa buat proyek klasifikasi gambar, atau pernah copy-paste kode ResNet dari blog orang terus bingung kenapa akurasinya jelek, timm ini jawabannya.
Singkatnya, timm itu koleksi lebih dari seribu arsitektur model vision yang udah dilatih (pretrained), lengkap sama preprocessing yang benar, augmentasi modern, optimizer, scheduler, dan utilitas training. Semuanya dengan API yang konsisten. Ganti dari ResNet ke ConvNeXt ke EfficientNet ke Vision Transformer cuma ganti satu string nama model. Serius, satu string.
Di tutorial ini kita bakal bahas instalasi, cara nyari dan milih model, inference sederhana, ambil fitur buat transfer learning, fine-tuning model buat dataset sendiri, sampai tips memilih model yang pas antara akurasi dan kecepatan. Yuk mulai.
Introduction
Sebelum ngoding aku mau jelasin dulu kenapa timm beda dari sekadar torchvision.models.
Apa Itu timm
timm dibuat oleh Ross Wightman dan sekarang jadi bagian dari ekosistem HuggingFace. Isinya implementasi arsitektur vision paling lengkap yang pernah ada dalam satu library: ResNet dan semua variannya, EfficientNet, RegNet, ConvNeXt, Vision Transformer (ViT), Swin Transformer, DeiT, BEiT, MaxViT, EVA, MobileNet, dan masih banyak lagi.
Yang bikin dia spesial bukan cuma jumlah modelnya, tapi tiga hal ini.
Pertama, bobot pretrained-nya berkualitas tinggi dan sering kali lebih bagus dari bobot resmi paper aslinya, karena Ross melatih ulang banyak model dengan resep training modern.
Kedua, setiap model bawa konfigurasi preprocessing sendiri. Ini penting banget dan sering diremehkan orang. ViT dilatih dengan normalisasi berbeda dari ResNet. Kalau kalian pakai mean dan std yang salah, akurasi bisa anjlok belasan persen tanpa kalian sadari. timm ngurus ini otomatis.
Ketiga, API-nya konsisten. Semua model dibuat lewat timm.createmodel(), semua punya method forwardfeatures(), dan semua punya cara yang sama buat ganti jumlah kelas output.
Kapan Pakai timm
Pakai timm kalau kalian butuh backbone kuat untuk klasifikasi gambar, butuh feature extractor untuk task lain (deteksi, segmentasi, retrieval, similarity search), atau lagi benchmarking beberapa arsitektur untuk dataset kalian dan pengen ganti-ganti model tanpa nulis ulang kode.
Kalau kalian butuh model deteksi objek siap pakai, itu ranahnya Ultralytics atau Detectron2. timm fokus di backbone dan klasifikasi, tapi backbone-nya sering dipakai di dalam library-library itu juga.
Instalasi
Butuh Python 3.8 ke atas dan PyTorch. Bikin virtual environment dulu ya.
python -m venv venv
source venv/bin/activate # Linux / Mac
venv\Scripts\activate # Windows
pip install torch torchvision
pip install timm pillow matplotlib
Cek versinya:
import timm
import torch
print("timm:", timm.version)
print("torch:", torch.version)
print("cuda tersedia:", torch.cuda.isavailable())
Mencari Model yang Tersedia
Karena modelnya ribuan, hal pertama yang perlu kalian bisa adalah nyari.
import timm
Berapa banyak model dengan bobot pretrained?
semua = timm.listmodels(pretrained=True)
print("total model pretrained:", len(semua))
Cari model ConvNeXt
print(timm.listmodels("convnext", pretrained=True)[:10])
Cari model efficientnet ukuran kecil
print(timm.listmodels("efficientnetb0", pretrained=True))
Cari ViT
print(timm.listmodels("vitbase", pretrained=True)[:10])
Pola penamaan timm biasanya arsitekturukuran.resepdataset. Contohnya convnexttiny.fbin22kftin1k artinya ConvNeXt ukuran tiny, bobot dari Facebook, dilatih di ImageNet-22k lalu di-fine-tune ke ImageNet-1k. Semakin banyak kalian baca nama model, semakin gampang nebak kualitasnya.
Inference Pertama
Ayo langsung coba klasifikasi satu gambar.
import timm
import torch
from PIL import Image
import urllib.request
1. Buat model dengan bobot pretrained
model = timm.createmodel("convnexttiny.fbin1k", pretrained=True)
model.eval()
2. Ambil transform yang BENAR untuk model ini
config = timm.data.resolvemodeldataconfig(model)
transform = timm.data.createtransform(config, istraining=False)
print(config)
3. Siapkan gambar
urllib.request.urlretrieve(
"https://raw.githubusercontent.com/pytorch/hub/master/images/dog.jpg", "dog.jpg"
)
img = Image.open("dog.jpg").convert("RGB")
4. Prediksi
x = transform(img).unsqueeze(0) # tambah dimensi batch
with torch.nograd():
logits = model(x)
probs = logits.softmax(dim=-1)[0]
top5 = probs.topk(5)
5. Ambil nama kelas ImageNet
url = "https://raw.githubusercontent.com/pytorch/hub/master/imagenetclasses.txt"
urllib.request.urlretrieve(url, "imagenetclasses.txt")
labels = open("imagenetclasses.txt").read().splitlines()
for skor, idx in zip(top5.values, top5.indices):
print(f"{labels[idx]:30s} {skor.item():.4f}")
Perhatikan langkah nomor dua. resolvemodeldataconfig itu kunci yang sering dilewatin orang. Dia ngasih tau ukuran input, mean, std, dan metode interpolasi yang dipakai waktu model ini dilatih. Jangan pernah asal pakai normalisasi ImageNet standar buat semua model.
Mengganti Jumlah Kelas
Buat dataset sendiri, kalian pasti butuh output layer yang beda. Di timm ini cuma satu argumen.
# Dataset saya punya 7 kelas
model = timm.createmodel("resnet50.a1in1k", pretrained=True, numclasses=7)
x = torch.randn(2, 3, 224, 224)
print(model(x).shape) # torch.Size([2, 7])
Kalau kalian set numclasses=0, timm bakal ngilangin classifier head-nya dan langsung ngeluarin fitur. Ini berguna banget buat feature extraction.
backbone = timm.createmodel("resnet50.a1in1k", pretrained=True, numclasses=0)
fitur = backbone(torch.randn(2, 3, 224, 224))
print(fitur.shape) # torch.Size([2, 2048])
Vektor 2048 dimensi itu bisa kalian pakai buat image similarity search, clustering, atau input ke classifier klasik kayak SVM.
Mengambil Feature Map Multi-Skala
Untuk task seperti segmentasi atau deteksi, kalian butuh feature map dari beberapa level kedalaman, bukan cuma vektor akhir.
import timm
import torch
model = timm.createmodel(
"resnet50.a1in1k",
pretrained=True,
featuresonly=True,
outindices=(1, 2, 3, 4),
)
out = model(torch.randn(1, 3, 224, 224))
for i, f in enumerate(out):
print(i, f.shape)
print(model.featureinfo.channels()) # jumlah channel tiap level
print(model.featureinfo.reduction()) # faktor downsampling tiap level
Ini yang bikin timm sering dipakai sebagai encoder di library segmentasi seperti segmentationmodelspytorch. Kalian bisa tukar backbone-nya semudah ganti string.
Fine-Tuning untuk Dataset Sendiri
Sekarang bagian utamanya. Aku bakal tunjukin loop training sederhana tapi lengkap, pakai struktur folder standar ImageFolder.
Struktur datasetnya begini:
data/
train/
kucing/ gambar1.jpg ...
anjing/ gambar1.jpg ...
val/
kucing/ ...
anjing/ ...
Kodenya:
import timm
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision.datasets import ImageFolder
DEVICE = "cuda" if torch.cuda.isavailable() else "cpu"
NAMAMODEL = "convnexttiny.fbin1k"
1. Model
model = timm.createmodel(NAMAMODEL, pretrained=True, numclasses=2)
model.to(DEVICE)
2. Transform sesuai model, versi train dan eval
cfg = timm.data.resolvemodeldataconfig(model)
tftrain = timm.data.createtransform(cfg, istraining=True, autoaugment="rand-m9-mstd0.5")
tfval = timm.data.createtransform(*cfg, istraining=False)
3. Dataset dan loader
dstrain = ImageFolder("data/train", transform=tftrain)
dsval = ImageFolder("data/val", transform=tfval)
dltrain = DataLoader(dstrain, batchsize=32, shuffle=True, numworkers=4, pinmemory=True)
dlval = DataLoader(dsval, batchsize=64, shuffle=False, numworkers=4)
print("kelas:", dstrain.classes)
4. Optimizer, scheduler, loss
optimizer = timm.optim.createoptimizerv2(model, opt="adamw", lr=3e-4, weightdecay=0.05)
criterion = nn.CrossEntropyLoss(labelsmoothing=0.1)
EPOCHS = 10
scheduler = torch.optim.lrscheduler.CosineAnnealingLR(optimizer, Tmax=EPOCHS)
5. Loop training
for epoch in range(EPOCHS):
model.train()
totalloss = 0.0
for x, y in dltrain:
x, y = x.to(DEVICE), y.to(DEVICE)
optimizer.zerograd()
loss = criterion(model(x), y)
loss.backward()
optimizer.step()
totalloss += loss.item() x.size(0)
scheduler.step()
model.eval()
benar = 0
total = 0
with torch.nograd():
for x, y in dlval:
x, y = x.to(DEVICE), y.to(DEVICE)
pred = model(x).argmax(dim=1)
benar += (pred == y).sum().item()
total += y.size(0)
print(f"epoch {epoch+1}/{EPOCHS} "
f"loss {totalloss/len(dstrain):.4f} "
f"valacc {benar/total:.4f}")
torch.save(model.statedict(), "modelfinetuned.pth")
Beberapa hal yang perlu kalian catat dari kode di atas.
autoaugment="rand-m9-mstd0.5" mengaktifkan RandAugment, augmentasi modern yang biasanya ngasih kenaikan akurasi gratis di dataset kecil sampai menengah.
labelsmoothing=0.1 bikin model nggak terlalu pede berlebihan dan biasanya sedikit meningkatkan generalisasi.
AdamW dengan weight decay 0.05 adalah resep standar buat model modern seperti ConvNeXt dan ViT. Untuk ResNet klasik, SGD dengan momentum kadang masih lebih bagus.
Membekukan Backbone
Kalau dataset kalian kecil banget (di bawah beberapa ratus gambar per kelas), sering lebih aman melatih head-nya saja dulu.
model = timm.createmodel("convnexttiny.fbin1k", pretrained=True, numclasses=2)
for p in model.parameters():
p.requires
grad = False
Buka hanya classifier head
for p in model.getclassifier().parameters():
p.requiresgrad = True
optimizer = torch.optim.AdamW(
[p for p in model.parameters() if p.requiresgrad], lr=1e-3
)
Setelah beberapa epoch dan loss-nya stabil, buka semua parameter dan lanjutkan training dengan learning rate kecil, misalnya 1e-5 sampai 5e-5. Teknik ini namanya gradual unfreezing dan sering menyelamatkan dataset kecil dari overfitting.
Memuat Kembali Model
import timm
import torch
model = timm.createmodel("convnexttiny.fbin1k", pretrained=False, numclasses=2)
model.loadstatedict(torch.load("modelfinetuned.pth", maplocation="cpu"))
model.eval()
Perhatikan pretrained=False di sini, karena bobotnya kita ambil dari file kita sendiri, bukan dari internet.
Memilih Model yang Tepat
Ini pertanyaan yang paling sering aku terima, jadi aku kasih panduan praktis.
Kalau kalian butuh cepat dan ringan buat deploy di CPU atau perangkat mobile, coba mobilenetv3large100, efficientnetb0, atau efficientvitb0. Ukurannya kecil, inferensinya cepat, akurasinya masih respectable.
Kalau kalian butuh keseimbangan bagus antara akurasi dan biaya di GPU, convnexttiny, resnet50, dan efficientnetb3 adalah titik manis yang jarang mengecewakan.
Kalau kalian mengejar akurasi maksimal dan punya GPU besar plus data banyak, lihat convnextbase, swinbasepatch4window7224, atau model keluarga eva02 yang sering menempati posisi teratas benchmark.
Kalau data kalian sedikit sekali, pilih model yang dilatih di dataset besar seperti ImageNet-22k (perhatikan in22k di nama modelnya), karena fiturnya lebih general dan transfer learning-nya lebih kuat.
Satu tips terakhir: selalu benchmark dua sampai tiga kandidat di data kalian sendiri. Peringkat di ImageNet nggak selalu berlaku di dataset spesifik kalian, apalagi kalau domainnya jauh seperti citra medis atau citra satelit.
Tips dan Best Practice
Selalu pakai resolvemodeldataconfig dan createtransform, jangan hardcode normalisasi. Ini kesalahan nomor satu yang aku lihat di kode orang.
Perhatikan ukuran input. Beberapa model dilatih di 224x224, ada yang 288, 384, bahkan 512. Kalau kalian paksa ukuran yang salah ke ViT, kadang error atau akurasinya turun karena posisi embedding-nya nggak cocok.
Gunakan mixed precision buat hemat memori dan mempercepat training di GPU modern, cukup bungkus forward pass dengan torch.autocast.
Simpan nama model dan versi timm di file konfigurasi eksperimen kalian. Nama bobot di timm kadang berubah antar versi, dan ini bisa bikin hasil kalian nggak reproducible.
Manfaatkan timm.utils.ModelEmaV2 kalau kalian training lama. Exponential moving average dari bobot sering ngasih akurasi validasi lebih stabil dan sedikit lebih tinggi secara gratis.
Kesimpulan
timm adalah salah satu library yang paling meningkatkan produktivitas kalau kalian kerja di computer vision. Yang perlu kalian ingat:
timm.createmodel() adalah satu pintu masuk ke lebih dari seribu arsitektur dengan bobot pretrained berkualitas.
Selalu ambil transform lewat resolvemodeldataconfig supaya preprocessing kalian persis sama dengan waktu model dilatih.
numclasses mengganti head untuk dataset sendiri, numclasses=0 mengubah model jadi feature extractor, dan features_only=True memberi feature map multi-skala untuk deteksi dan segmentasi.
Fine-tuning cukup dengan loop PyTorch biasa, ditambah augmentasi modern dan optimizer AdamW dari timm.
Pemilihan model harus mempertimbangkan target deployment, ukuran data, dan domain, bukan cuma peringkat akurasi ImageNet.
Coba ambil dataset kecil kalian sendiri, misalnya klasifikasi produk atau kualitas hasil produksi, lalu bandingkan tiga arsitektur berbeda cuma dengan mengganti satu string. Kalian bakal langsung ngerasain kenapa library ini jadi standar de facto di dunia computer vision PyTorch. Selamat mencoba.