timm: A Warehouse of 1000+ Ready-to-Use Computer Vision Models in PyTorch

# 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 n...

By Ruby Abdullah · · tutorial
timmpytorchcomputer-visiontransfer-learningimage-classification

timm: A Warehouse of 1000+ Ready-to-Use Computer Vision Models in PyTorch

Hey everyone, in this tutorial I want to introduce a library that in my opinion belongs in the toolbox of anyone doing computer vision with PyTorch. It is called timm, short for PyTorch Image Models. If you have ever been stuck choosing a backbone for an image classification project, or copy-pasted a ResNet implementation from someone's blog and wondered why your accuracy was mediocre, timm is the answer.

In short, timm is a collection of more than a thousand pretrained vision architectures, complete with the correct preprocessing, modern augmentation, optimizers, schedulers, and training utilities. All of it behind a consistent API. Switching from ResNet to ConvNeXt to EfficientNet to a Vision Transformer is a single string change. Seriously, one string.

In this tutorial we cover installation, how to search for and choose models, simple inference, feature extraction for transfer learning, fine-tuning on your own dataset, and finally practical guidance on picking a model that balances accuracy and speed. Let us get started.

Introduction

Before the code, let me explain why timm is more than just torchvision.models.

What Is timm

timm was created by Ross Wightman and is now part of the HuggingFace ecosystem. It contains the most complete set of vision architecture implementations ever assembled in one library: ResNet and all its variants, EfficientNet, RegNet, ConvNeXt, Vision Transformer (ViT), Swin Transformer, DeiT, BEiT, MaxViT, EVA, MobileNet, and many more.

What makes it special is not just the count, but three things.

First, the pretrained weights are high quality and frequently better than the original paper's official weights, because Ross retrained many models with modern training recipes.

Second, every model carries its own preprocessing configuration. This matters enormously and is often underestimated. ViT was trained with different normalization than ResNet. If you use the wrong mean and standard deviation, accuracy can drop by double digits without you noticing. timm handles this for you.

Third, the API is consistent. Every model is built through timm.createmodel(), every model exposes forwardfeatures(), and every model changes its output class count the same way.

When to Use timm

Use timm when you need a strong backbone for image classification, when you need a feature extractor for another task (detection, segmentation, retrieval, similarity search), or when you are benchmarking several architectures on your dataset and want to swap models without rewriting code.

If you need a ready-made object detection model, that is Ultralytics or Detectron2 territory. timm focuses on backbones and classification, though its backbones are often used inside those libraries too.

Installation

You need Python 3.8 or newer plus PyTorch. Create a virtual environment first.

python -m venv venv

source venv/bin/activate # Linux / Mac

venv\Scripts\activate # Windows

pip install torch torchvision

pip install timm pillow matplotlib

Check the versions:

import timm

import torch

print("timm:", timm.version)

print("torch:", torch.version)

print("cuda available:", torch.cuda.isavailable())

Finding Available Models

With thousands of models, the first skill you need is searching.

import timm

How many models ship with pretrained weights?

allmodels = timm.listmodels(pretrained=True)

print("total pretrained models:", len(allmodels))

Find ConvNeXt models

print(timm.listmodels("convnext", pretrained=True)[:10])

Find small EfficientNet models

print(timm.listmodels("efficientnetb0", pretrained=True))

Find ViT models

print(timm.listmodels("vitbase", pretrained=True)[:10])

The timm naming pattern is usually architecturesize.recipedataset. For example convnexttiny.fbin22kftin1k means ConvNeXt tiny, weights from Facebook, trained on ImageNet-22k then fine-tuned on ImageNet-1k. The more model names you read, the easier it becomes to guess their quality.

First Inference

Let us classify a single image.

import timm

import torch

from PIL import Image

import urllib.request

1. Create the model with pretrained weights

model = timm.createmodel("convnexttiny.fbin1k", pretrained=True)

model.eval()

2. Get the CORRECT transform for this model

config = timm.data.resolvemodeldataconfig(model)

transform = timm.data.createtransform(config, istraining=False)

print(config)

3. Prepare an image

urllib.request.urlretrieve(

"https://raw.githubusercontent.com/pytorch/hub/master/images/dog.jpg", "dog.jpg"

)

img = Image.open("dog.jpg").convert("RGB")

4. Predict

x = transform(img).unsqueeze(0) # add the batch dimension

with torch.nograd():

logits = model(x)

probs = logits.softmax(dim=-1)[0]

top5 = probs.topk(5)

5. Load ImageNet class names

url = "https://raw.githubusercontent.com/pytorch/hub/master/imagenetclasses.txt"

urllib.request.urlretrieve(url, "imagenetclasses.txt")

labels = open("imagenetclasses.txt").read().splitlines()

for score, idx in zip(top5.values, top5.indices):

print(f"{labels[idx]:30s} {score.item():.4f}")

Pay attention to step two. resolvemodeldataconfig is the key that people skip. It tells you the input size, mean, standard deviation, and interpolation method used when the model was trained. Never blindly apply standard ImageNet normalization to every model.

Changing the Number of Classes

For your own dataset you need a different output layer. In timm that is one argument.

# My dataset has 7 classes

model = timm.createmodel("resnet50.a1in1k", pretrained=True, numclasses=7)

x = torch.randn(2, 3, 224, 224)

print(model(x).shape) # torch.Size([2, 7])

If you set numclasses=0, timm removes the classifier head and returns features directly. This is very handy for feature extraction.

backbone = timm.createmodel("resnet50.a1in1k", pretrained=True, numclasses=0)

features = backbone(torch.randn(2, 3, 224, 224))

print(features.shape) # torch.Size([2, 2048])

That 2048 dimensional vector is what you feed into image similarity search, clustering, or a classic classifier such as an SVM.

Extracting Multi-Scale Feature Maps

For tasks like segmentation or detection you need feature maps from several depths, not just the final vector.

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()) # channels per level

print(model.featureinfo.reduction()) # downsampling factor per level

This is exactly why timm is used as the encoder inside segmentation libraries such as segmentationmodelspytorch. Swapping the backbone is as easy as changing a string.

Fine-Tuning on Your Own Dataset

Now the main event. Here is a simple but complete training loop using the standard ImageFolder layout.

The dataset structure looks like this:

data/

train/

cat/ image1.jpg ...

dog/ image1.jpg ...

val/

cat/ ...

dog/ ...

And the code:

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"

MODELNAME = "convnexttiny.fbin1k"

1. Model

model = timm.createmodel(MODELNAME, pretrained=True, numclasses=2)

model.to(DEVICE)

2. Model-specific transforms, train and eval variants

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. Datasets and loaders

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("classes:", 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. Training loop

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()

correct = 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)

correct += (pred == y).sum().item()

total += y.size(0)

print(f"epoch {epoch+1}/{EPOCHS} "

f"loss {totalloss/len(dstrain):.4f} "

f"valacc {correct/total:.4f}")

torch.save(model.statedict(), "modelfinetuned.pth")

A few things worth noting in that code.

auto
augment="rand-m9-mstd0.5" turns on RandAugment, a modern augmentation policy that usually gives free accuracy on small to medium datasets. labelsmoothing=0.1 keeps the model from becoming overconfident and typically improves generalization a little.

AdamW with weight decay 0.05 is the standard recipe for modern models like ConvNeXt and ViT. For classic ResNets, SGD with momentum is sometimes still better.

Freezing the Backbone

If your dataset is genuinely small (under a few hundred images per class), it is often safer to train only the head first.

model = timm.createmodel("convnexttiny.fbin1k", pretrained=True, numclasses=2)

for p in model.parameters():

p.requiresgrad = False

Unfreeze only the 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

)

After a few epochs and once the loss stabilizes, unfreeze everything and continue with a small learning rate, say 1e-5 to 5e-5. This technique is called gradual unfreezing and it regularly rescues small datasets from overfitting.

Loading the Model Back

import timm

import torch

model = timm.createmodel("convnexttiny.fbin1k", pretrained=False, numclasses=2)

model.loadstatedict(torch.load("modelfinetuned.pth", maplocation="cpu"))

model.eval()

Note pretrained=False here, because the weights come from our own file rather than the internet.

Choosing the Right Model

This is the question I get most often, so here is practical guidance.

If you need something fast and light for CPU or mobile deployment, try mobilenetv3large100, efficientnetb0, or efficientvitb0. Small footprint, fast inference, respectable accuracy.

If you want a good balance of accuracy and cost on a GPU, convnexttiny, resnet50, and efficientnetb3 are sweet spots that rarely disappoint.

If you are chasing maximum accuracy with a big GPU and plenty of data, look at convnextbase, swinbasepatch4window7224, or the eva02 family that frequently tops benchmarks.

If your data is very limited, prefer models trained on larger datasets such as ImageNet-22k (look for in22k in the name), because their features are more general and transfer better.

One last tip: always benchmark two or three candidates on your own data. ImageNet rankings do not always hold on your specific dataset, especially in distant domains like medical or satellite imagery.

Tips and Best Practices

Always use resolvemodeldataconfig and createtransform instead of hardcoding normalization. This is the number one mistake I see in other people's code.

Watch the input resolution. Some models were trained at 224x224, others at 288, 384, or even 512. Forcing the wrong size into a ViT can either error out or quietly hurt accuracy because the position embeddings do not match.

Use mixed precision to save memory and speed up training on modern GPUs, simply by wrapping the forward pass in torch.autocast.

Record the model name and the timm version in your experiment config. Weight names in timm occasionally change between releases, which can silently break reproducibility.

Consider timm.utils.ModelEmaV2 for long training runs. An exponential moving average of the weights often yields more stable and slightly higher validation accuracy for free.

Conclusion

timm is one of the biggest productivity multipliers available if you work in computer vision. The key takeaways: timm.createmodel() is a single door into more than a thousand architectures with high quality pretrained weights.

Always obtain transforms through resolvemodeldataconfig so preprocessing matches exactly how the model was trained.

numclasses swaps the head for your dataset, numclasses=0 turns the model into a feature extractor, and features_only=True gives multi-scale feature maps for detection and segmentation.

Fine-tuning is a plain PyTorch loop plus modern augmentation and the AdamW optimizer helper from timm.

Model selection should weigh deployment target, dataset size, and domain, not just ImageNet leaderboard position.

Take one of your own small datasets, maybe product classification or manufacturing quality inspection, and compare three architectures by changing a single string. You will feel immediately why this library became the de facto standard in PyTorch computer vision. Happy building.

Related Articles

Depth Anything V2: Predicting Depth from a Single Image with Python

Depth Anything V2: Prediksi Kedalaman dari Satu Gambar dengan Python Halo temen-temen, di tutorial kali ini aku mau ngaj...

DINOv2: A Complete Guide to Meta AI's Vision Foundation Model for Label-Free Image Embeddings

DINOv2: Panduan Lengkap Vision Foundation Model dari Meta AI untuk Embedding Gambar Tanpa Label Halo temen-temen, di tut...

PaddleOCR: High Accuracy Text Extraction from Images and Documents

PaddleOCR: Ekstraksi Teks dari Gambar dan Dokumen dengan Akurasi Tinggi Halo temen-temen, kali ini kita bahas salah satu...

DeepSpeed: Training Huge Models on Limited GPUs with ZeRO and Offload

DeepSpeed: Melatih Model Raksasa di GPU Terbatas dengan ZeRO dan Offload Halo temen-temen, kali ini kita masuk ke topik ...