Yohaï-Eliel Berreby1,2 ·
Sabrina Du1,2 ·
Audrey Durand2,3 ·
B. Suresh Krishna1
1McGill University · 2Mila – Quebec AI Institute · 3Université Laval
This repository holds the reference PyTorch implementation of CanViT, with pretraining, task specialization and
evaluation; the package is canvit-pytorch on PyPI.
- 2026-09-26: canvit-pytorch 0.2, a refactoring release; updated checkpoints pushed to the Hub. Code written for 0.1: see Troubleshooting.
- 2026-09-24: 🎉 Accepted at NeurIPS 2026!
- 2026-05-16: Preprint v2 (arXiv:2603.22570v2), adding the 84.5% ImageNet-1k fine-tuning result and the effect of canvas resolution.
- 2026-04-06: First finetuned IN1k checkpoint:
canvitb16-add-vpe-finetune-g128px-s512px-in1k-2026-04-06, with newCanViTForImageClassificationAPI.- 🎉 CanViT sets a new SOTA on active-vision IN1k classification, with 84.5% top-1 accuracy, up from AdaptiveNN's previous best of 82.2%.
- 2026-03-23: Preprint v1 (arXiv:2603.22570v1).
- 🎉 CanViT sets a new SOTA on active ADE20K segmentation, with 45.9% ADE20K mIoU, obtained using linear probing from frozen weights.
- 2026-02-18: Initial code and first pretrained checkpoint release.
Active computer vision promises efficient, biologically plausible perception through sequential, localized glimpses, but lacks scalable general-purpose architectures and pretraining pipelines, leaving Active-Vision Foundation Models (AVFMs) underexplored. We introduce CanViT, the first task- and policy-agnostic AVFM. CanViT uses scene-relative RoPE to bind a retinotopic Vision Transformer backbone and a spatiotopic scene-wide latent workspace, the canvas. Efficient interaction with this high-capacity working memory is supported by Canvas Attention, a novel asymmetric cross-attention mechanism. We decouple thinking (backbone-level) and memory (canvas-level), eliminating canvas-side self-attention and fully-connected layers to achieve fast sequential inference and scalability to high output resolutions. We propose a label-free active vision pretraining scheme, policy-agnostic passive-to-active dense latent distillation: reconstructing scene-wide DINOv3 embeddings from sequences of low-resolution glimpses with randomized locations, zoom levels, and lengths. We pretrain CanViT-B from a random initialization on 13.2 million ImageNet-21k scenes—an order of magnitude more than previous active models—and 1 billion random glimpses, in 166 hours on a single H100. On ADE20K segmentation, a frozen CanViT-B achieves 38.5% mIoU in a single low-resolution glimpse, outperforming the best active model's 27.6% with 20x fewer inference FLOPs as well as its FLOP- or input-matched DINOv3 teacher. Given additional glimpses, CanViT-B reaches 45.9% ADE20K mIoU. On ImageNet-1k classification, CanViT-B also sets a new active-vision state of the art, with 84.5% top-1 accuracy after fine-tuning. CanViT generalizes to longer rollouts, larger scenes, and new policies. Our work narrows the wide gap between passive and active computer vision, demonstrating the potential of task- and policy-agnostic AVFM pretraining.
The checkpoints are on Hugging Face under canvit; from_pretrained loads the
PyTorch ones.
| Checkpoint | Description |
|---|---|
canvitb16-add-vpe-pretrain-g128px-s512px-in21k-dv3b16-2026-02-02 |
CanViT-B pretrained on ImageNet-21k by policy-agnostic passive-to-active dense latent distillation from DINOv3 ViT-B: the paper's model |
canvitb16-add-vpe-pretrain-g128px-s512px-in1k-dv3b16-2026-06-22 |
CanViT-B pretrained the same way on ImageNet-1k only |
canvitb16-add-vpe-finetune-g128px-s512px-in1k-2026-04-06 |
The ImageNet-21k model fine-tuned for ImageNet-1k classification, 84.5% top-1 (trained on TPU v6e via torch_xla) |
canvitb16-add-vpe-finetune-g128px-s512px-in1k-2026-07-24 |
The ImageNet-21k model fine-tuned again with the same recipe, by a JAX/Flax NNX trainer |
canvitb16-add-vpe-finetune-g128px-s512px-in1k-from-in1k-2026-07-24 |
The ImageNet-1k model fine-tuned with the same recipe, by the same trainer |
Collections:
- CanViT ADE20K segmentation probes and DINOv3 ADE20K segmentation probes
- DINOv3 ImageNet-1k probes, which the frozen classification path uses
- CanViT pretraining ablations, the paper's ablation backbones
- JAX / Flax NNX and MLX copies, for the ports under Repository layout
We recommend uv for dependency management.
uv add canvit-pytorch # or: pip install canvit-pytorchfrom canvit_pytorch import CanViTForPretraining, Viewpoint, sample_at_viewpoint
from canvit_pytorch.preprocess import preprocess
from PIL import Image
import torch
# CanViT is integrated with the HuggingFace Hub.
model = CanViTForPretraining.from_pretrained(
"canvit/canvitb16-add-vpe-pretrain-g128px-s512px-in21k-dv3b16-2026-02-02"
).eval()
# Replace with the image of your choice
image = Image.open("canvit-pytorch/test_data/Cat03.jpg").convert("RGB")
image = preprocess(512)(image)
image = image.unsqueeze(0) # [1, 3, 512, 512]
# CanViT is a recurrent model.
state = model.init_state(batch_size=1, canvas_grid_size=32)
# Let's process a first glimpse: centered, zoomed-out.
# You can use any viewpoint you like, as long as it is within bounds.
# CanViT was trained on viewpoints covering 0.25% to 100%
# of a scene's surface area.
with torch.inference_mode():
vp = Viewpoint.full_scene(batch_size=1, device=image.device)
glimpse = sample_at_viewpoint(spatial=image, viewpoint=vp, glimpse_size_px=128)
out = model(glimpse=glimpse, state=state, viewpoint=vp)
# Let's inspect the structure of what we get back.
# The canvas contains the model's working understanding of
# the scene at any given time, and is linearly decodable
# into dense predictions upon token-wise LayerNorm.
# See `demos/basic.py` for how to visualize the canvas.
canvas_spatial = model.canvit.canvas_patch_grid(out.state.canvas) # [1, 32, 32, 1024] — spatial feature map
out.state.recurrent_cls # [1, 1, 768] — global CLS token
out.glimpse_patches # [1, 64, 768] — glimpse patch features
# Now let's do a second glimpse: zoom into the top-left quadrant
# You can do this repeatedly: CanViT is recurrent with a large but constant-size canvas.
with torch.inference_mode():
vp2 = Viewpoint(centers=torch.tensor([[-.5, -.5]]), scales=torch.tensor([.5]))
glimpse2 = sample_at_viewpoint(spatial=image, viewpoint=vp2, glimpse_size_px=128)
out2 = model(glimpse=glimpse2, state=out.state, viewpoint=vp2)
# You can use CanViT with frozen weights, fine-tune it, learn a policy on top...
# Or pretrain your own; it's fast.
# Start building!CanViTForImageClassification provides a unified interface for classification. Two construction paths, same forward pass:
From a finetuned checkpoint (CanViT + head trained on IN1k):
from canvit_pytorch import CanViTForImageClassification, Viewpoint, sample_at_viewpoint
from canvit_pytorch.preprocess import preprocess
from PIL import Image
import torch
clf = CanViTForImageClassification.from_pretrained(
"canvit/canvitb16-add-vpe-finetune-g128px-s512px-in1k-2026-04-06"
).eval()From the frozen pretrained CanViT checkpoint + a DINOv3 linear probe:
clf = CanViTForImageClassification.from_pretrained_with_probe(
pretrained_repo="canvit/canvitb16-add-vpe-pretrain-g128px-s512px-in21k-dv3b16-2026-02-02",
probe_repo="canvit/dinov3-vitb16-lvd1689m-in1k-512x512-linear-clf-probe",
).eval()Both have the same forward pass:
image = preprocess(512)(Image.open("canvit-pytorch/test_data/Cat03.jpg").convert("RGB")).unsqueeze(0)
state = clf.init_state(batch_size=1, canvas_grid_size=32)
with torch.inference_mode():
vp = Viewpoint.full_scene(batch_size=1, device=image.device)
glimpse = sample_at_viewpoint(spatial=image, viewpoint=vp, glimpse_size_px=128)
logits, state = clf(glimpse=glimpse, state=state, viewpoint=vp)
print(logits.argmax(dim=-1)) # ImageNet-1k class indexCanViTForSemanticSegmentation bundles a CanViT and a SegmentationProbe head into one model. forward returns per-pixel logits at canvas-grid resolution; predict adds bilinear upsampling.
from canvit_pytorch import CanViTForSemanticSegmentation
# Frozen CanViT + the flagship ADE20K probe (45.9% mIoU, 512px / 64x64 canvas):
seg = CanViTForSemanticSegmentation.from_pretrained_with_probe(
pretrained_repo="canvit/canvitb16-add-vpe-pretrain-g128px-s512px-in21k-dv3b16-2026-02-02",
probe_repo="canvit/probe-ade20k-40k-s512-c64-in21k",
).eval()
state = seg.init_state(batch_size=1, canvas_grid_size=64)
with torch.inference_mode():
logits, state = seg(glimpse=glimpse, state=state, viewpoint=vp) # [B, n_cls, 64, 64]
upsampled, state = seg.predict(glimpse=glimpse, state=state, viewpoint=vp,
target_size=(1024, 1024)) # [B, n_cls, 1024, 1024]The standalone SegmentationProbe head is also exported from canvit_pytorch for use on any spatial feature map. The published probes are listed under Checkpoints.
git clone https://github.com/m2b3/CanViT.git
cd CanViT/canvit-pytorch
# Classification with sequential glimpses
uv run --extra demo python demos/classify.py # finetuned checkpoint
uv run --extra demo python demos/classify.py --classifier frozen # frozen CanViT + fused probe
# Canvas PCA visualization with two viewing strategies
uv run --extra demo python demos/basic.py- CPU
- CUDA (tested on RTX 4090, H100 SXM 80GB)
- Apple Silicon via MPS (inference, tested with torch 2.14)
- TPU via torch_xla 2.9.0 (tested on TPU v6e)
We aim to maintain compatibility with torch.export and ONNX Runtime. Please file an issue if you encounter problems.
canvit-pytorch/ holds the package:
| Module | Contents | Docs |
|---|---|---|
canvit_pytorch |
The model: architecture, checkpoint loading, viewpoints and policies, task heads | this README |
canvit_pytorch.flops |
Analytic forward FLOPs of CanViT and DINOv3 | docs/flops.md |
canvit_pytorch.pretrain |
Pretraining: passive-to-active dense distillation from DINOv3 | docs/pretrain.md |
canvit_pytorch.specialize |
Downstream training: ADE20K segmentation probes, ImageNet-1k fine-tuning | docs/specialize.md |
canvit_pytorch.evaluate |
Evaluation and benchmarking: ADE20K mIoU, ImageNet-1k top-k, DINOv3 reconstruction | docs/evaluate.md |
canvit_pytorch.viz |
Recorded rollouts and smooth viewpoint paths for the project page and slides | docs/viz.md |
site/ is the project page.
Pretraining, probe training and evaluation lived in separate repositories (CanViT-pretrain, CanViT-specialize, CanViT-eval), now archived; their histories are merged here.
Related repositories:
- dinov3-in1k-probes — ImageNet-1k linear probes for the DINOv3 ViTs, used by CanViT's classification path
- CanViT-MLX — MLX implementation for Apple Silicon (experimental)
- CanViT-NNX — JAX/Flax NNX implementation (experimental)
If you encounter errors loading pretrained checkpoints, ensure you are using the latest version of the package:
uv lock --upgrade-package canvit-pytorch && uv syncCode written for canvit-pytorch 0.1 needs canvit-pytorch<0.2 and the checkpoints' earlier files:
from_pretrained(..., revision="canvit-pytorch-0.1").
If you use this work, please cite our paper:
@article{berreby2026canvit,
title={CanViT: Toward Active-Vision Foundation Models},
author={Berreby, Yoha{\"i}-Eliel and Du, Sabrina and Durand, Audrey and Krishna, B. Suresh},
year={2026},
eprint={2603.22570},
archivePrefix={arXiv},
primaryClass={cs.CV},
url={https://arxiv.org/abs/2603.22570}
}Open an issue in this repository or email me@yberreby.com.
MIT. See LICENSE for details.
