PyTorch image models, evolved — encoder/head architecture split layered on timm
Project description
timme — timm, evolved
timme is an experimental refactor of timm that splits every image model into a reusable encoder and a separate head. It's a thin layer on top of timm — for now it reuses timm's blocks, layers, hub integration, and pretrained-weight infrastructure, while exposing a cleaner API for feature extraction, head swapping, and weight remapping.
Status: alpha / proof-of-concept. 9 model families wired (~109 variants). The shape of the public API is settling but not stable. Not production-ready.
Why
timm models are wonderful but each one is a monolithic nn.Module with forward_features + forward_head baked together. That makes a few things awkward:
- using a backbone for downstream tasks (detection, segmentation, dense prediction) requires hand-rolling head removal,
- swapping a head (token-pool vs avg-pool vs attention-pool, distillation, MAP) requires reaching into model internals,
- intermediate features (
features_only=True) go through a separateFeatureListNetwrapper rather than the model itself.
timme says: every model is ImageClassifier(encoder, head) where encoder IS the features (no forward_features indirection) and head is a swappable, well-typed module. Pretrained weights load via a small per-family WeightLayout that splits old monolithic state dicts into encoder.* / head.*.
Install
pip install timme # not yet on PyPI; for now:
pip install -e . # from a clone
Runtime dependency: timm>=1.0, torch>=2.0.
Usage
Drop-in replacement for timm.create_model:
import timme
# Pretrained classifier — same names as timm
model = timme.create_model('resnet50.a1_in1k', pretrained=True)
model.eval()
# Logits match timm bit-for-bit
import torch, timm
x = torch.randn(1, 3, 224, 224)
y2 = model(x)
y1 = timm.create_model('resnet50.a1_in1k', pretrained=True).eval()(x)
assert torch.equal(y1, y2)
Encoder-only (replaces features_only=True):
encoder = timme.create_encoder('vit_base_patch16_224.augreg2_in21k_ft_in1k', pretrained=True)
features = encoder(x) # (B, 197, 768) — NLC
encoder = timme.create_encoder('resnet50', pretrained=True, out_indices=(0, 1, 2, 3, 4))
stages = encoder(x) # list of stage tensors
Swap heads or change num_classes / in_chans:
model = timme.create_model('resnet50.a1_in1k', pretrained=True, num_classes=10)
model = timme.create_model('resnet50.a1_in1k', pretrained=True, in_chans=1)
validate.py from the timm repo works unchanged if you swap the create_model import:
# in validate.py
from timme import create_model
What's implemented
109 variants across 9 families, all exact-matching timm pretrained weights:
| family | example variants |
|---|---|
| ResNet | resnet18, resnet50, resnet101, resnet50d, seresnet50 |
| ViT | vit_tiny/small/base/large_patch16_224/384, CLIP/DINOv2 variants |
| ConvNeXt | convnext_tiny/small/base/large, convnextv2_base |
| MobileNetV3 | mobilenetv3_large_100, mobilenetv3_small_100 |
| ByobNet | ~70 variants — gernet, resnet51q, regnetz, eca_resnet, etc. |
| DeiT | deit_*, deit3_*, distilled deit_*_distilled_* |
| LeViT | levit_128/192/256/384, conv-mode variants |
| NaFlexViT | naflexvit_base/so150m2/so400m_patch16_* (gap, par_gap, map, siglip) |
| EVA / EVA02 | eva_giant_patch14_*, eva02_tiny/small/base/large_patch14_*, CLIP |
9 canonical heads cover the head-side variability (5 spatial for CNNs, 4 token for transformers). See ARCHITECTURE.md.
What's not implemented yet
- The remaining ~80 timm families. Each one needs the same wiring: encoder class +
WeightLayout+ builder +register_family(...). - Custom training / validation scripts. Use timm's
train.py/validate.pywithfrom timme import create_model. - Standalone hub story. timme reuses
timm.models._registryfor pretrained_cfg metadata andtimm.models._builder.load_pretrainedfor downloads, so it depends on timm's hub integration today. - Standalone layer primitives.
timme.layersis a placeholder; blocks/norms/activations/attention pools are imported fromtimm.layers.
Roadmap
The plan is for timme to grow into a fully standalone replacement for timm. Near-term priorities:
- More families — work through the rest of timm's model zoo, prioritizing actively-developed ones.
- Vendor / fork shared layers as needed — the runtime dep on timm is fine for v0 but limits independent evolution.
- Training/validation scripts native to timme (currently we ride on timm's).
- Hub integration — read pretrained metadata from timme's own registry instead of borrowing timm's.
License
Apache-2.0. Built on timm (also Apache-2.0). See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file timme-0.0.1.tar.gz.
File metadata
- Download URL: timme-0.0.1.tar.gz
- Upload date:
- Size: 57.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
57f8c0b2d5d2e6a1ccca9579fbf462ae1442cd12855f3dbc27690c5d9d74c9a4
|
|
| MD5 |
1a209cd2a0f0276580eade6b728bd8f2
|
|
| BLAKE2b-256 |
b81d7aa5c8829654d05a619da538075566a5ebd33982521f8a3a61c4859ee3fc
|
File details
Details for the file timme-0.0.1-py3-none-any.whl.
File metadata
- Download URL: timme-0.0.1-py3-none-any.whl
- Upload date:
- Size: 73.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd0b26b2657c1ad38724d937dbc0be9517e0372c9a7f6e6a60ee68e8eb79f677
|
|
| MD5 |
307c132550f0497a0fcfd69e88487cad
|
|
| BLAKE2b-256 |
3da4a1843a6d50238228d33baa3a072b74144704070fbe7c92643887c10d6f42
|