timm Backbones for Vision
One call that builds hundreds of named image models with matching weights, so backbone swaps are config changes instead of rewrites.
Why Does This Exist?
Trying a new backbone used to mean new code, new weight URLs, and new preprocessing guesses. timm collapses that to a name: hundreds of ResNet, EfficientNet and ViT variants behind create_model, each with matching pretrained weights and its data config. Pretrained models become an argument, and transfer learning starts from a verified checkpoint instead of a download hunt.
This page covers the builder contract, one head-swap fixture, and appropriate use. Series 1.0.29 was the current release verified in-session.
Think of It Like This
A rental fleet with one key form
A depot holds hundreds of cars behind one counter. One form names the car, the mileage, and the fuel, and every car leaves with the right manual in the glovebox.
timm is the counter. The model name is the form, weights are the car, and the data config is the manual. The analogy stops at damage: renting the wrong car wastes an afternoon, while training on mismatched preprocessing wastes a budget.
How It Actually Works
Input is a model name plus flags: pretrained=True, num_classes, and feature-only versus full-head mode. Output is a PyTorch module with the right stem, stages, pooling and head, plus the input size and normalization its weights expect. Purpose is comparable backbone experiments with zero glue code. Appropriate use is classification, retrieval and transfer starts at standard sizes like 224. Read the paired data config for every swap, because input size and normalization travel with the name.
Head-swap fixture
Take a backbone whose features are 512 numbers per image. A 10-class head is a matrix plus 10 biases, so new numbers. Loading pretrained features and resetting only those 5130 keeps everything else trained. Logits then pick class 0 by argmax, the same selection the diagram draws.
Code
Argmax selection in plain Python, the decision every head ends with:
def argmax(xs: list[float]) -> int: best: int = 0 for i in range(1, len(xs)): if xs[i] > xs[best]: best = i return best # index of the largest logit
print(argmax([2.0, 1.0, 0.0])) # -> 0print(512 * 10 + 10) # -> 5130Class 0 wins, and the fresh head holds exactly 5130 numbers.
Watch Out For
Swapping the backbone but keeping old preprocessing
Each timm name ships its own size and normalization. The symptom is a stronger backbone scoring worse than the weaker one it replaced. Fix it by reading the model data config on every swap and rebuilding the transform chain from it.
The Quick Version
- timm maps one model name to a built model with matching weights and config.
- A 512-feature backbone with a 10-way head trains 5130 fresh numbers.
- Logits 2, 1, 0 select class 0 by argmax.
- Use it for comparable backbone and transfer experiments.
- Rebuild preprocessing from the data config on every swap.