iTranslated by AI
Extracting Features from Images with DINOv3
Hello, I'm Kurogane.
This time we will extract features from images using DINOv3.
If you know what you're doing, just read this:
facebookresearch/dinov3
Also, this article mainly references the following notebook:
https://colab.research.google.com/github/facebookresearch/dinov3/blob/main/notebooks/foreground_segmentation.ipynb
The official page mentions that it supports transformers, but as of writing (2025/09/25), it did not work in my environment (transformers 4.57.0.dev0) (why?)
pipeline
ValueError: The checkpoint you are trying to load has model type `dinov3_convnext` but Transformers does not recognize this architecture. This could be because of an issue with the checkpoint, or because your version of Transformers is out of date.
AutoImageProcessor
ValueError: Unrecognized image processor in facebook/dinov3-vitb16-pretrain-lvd1689m. Should have a `image_processor_type` key in its preprocessor_config.json of config.json, or one of the following `model_type` keys in its config.json: align, aria, beit, bit, blip, blip-2, bridgetower, chameleon, chinese_clip, clip, clipseg, conditional_detr, convnext, convnextv2, cvt, data2vec-vision, deformable_detr, deit, depth_anything, depth_pro, deta, detr, dinat, dinov2, donut-swin, dpt, efficientformer, efficientnet, flava, focalnet, fuyu, gemma3, git, glpn, got_ocr2, grounding-dino, groupvit, hiera, idefics, idefics2, idefics3, ijepa, imagegpt, instructblip, instructblipvideo, janus, kosmos-2, layoutlmv2, layoutlmv3, levit, llama4, llava, llava_next, llava_next_video, llava_onevision, mask2former, maskformer, mgp-str, mistral3, mlcd, mllama, mobilenet_v1, mobilenet_v2, mobilevit, mobilevitv2, nat, nougat, oneformer, owlv2, owlvit, paligemma, perceiver, phi4_multimodal, pix2struct, pixtral, poolformer, prompt_depth_anything, pvt, pvt_v2, qwen2_5_vl, qwen2_vl, regnet, resnet, rt_detr, sam, sam_hq, segformer, seggpt, shieldgemma2, siglip, siglip2, superglue, swiftformer, swin, swin2sr, swinv2, table-transformer, timesformer, timm_wrapper, tvlt, tvp, udop, upernet, van, videomae, vilt, vipllava, vit, vit_hybrid, vit_mae, vit_msn, vitmatte, xclip, yolos, zoedepth
So I'll leave a note on how to load using torch.hub.load() and extract features.
Procedure
The method is simple as follows:
- Clone facebookresearch/dinov3
- From the model list, request access for the desired model and obtain the
dinov3_xxxx.pthfile - Load the model using
torch.hub.load()
Below is the code:
import torch
import torchvision
from torchvision.transforms import v2
from PIL import Image
import requests
from IPython.display import display
# Preprocessing from the above github repository
def make_transform(resize_size: int = 256):
to_tensor = v2.ToImage()
resize = v2.Resize((resize_size, resize_size), antialias=True)
to_float = v2.ToDtype(torch.float32, scale=True)
normalize = v2.Normalize(
mean=(0.485, 0.456, 0.406),
std=(0.229, 0.224, 0.225),
)
return v2.Compose([to_tensor, resize, to_float, normalize])
# Model loading
REPO_DIR = r"F:\devs\vision\dinov3"
WEIGHT_DIR = r"F:\devs\vision\dinov3_convnext_tiny_pretrain_lvd1689m-21b726bb.pth"
model = torch.hub.load(
REPO_DIR, # Root directory of the cloned dinov3 repository
'dinov3_convnext_tiny', # Name of the model to use
source='local',
weights=WEIGHT_DIR, # Directory of the model file to use
).cuda()
# Load image
url = "http://images.cocodataset.org/val2017/000000039769.jpg"
image = Image.open(requests.get(url, stream=True).raw).convert('RGB')
# Preprocess image
img_size = 224
transform = make_transform(img_size)
img_tensor = transform(image).unsqueeze(0).cuda() # Since model is sent to cuda, .cuda is needed
# Get features
with torch.no_grad():
feats = model.forward_features(img_tensor)
The extracted feats is a dictionary containing the following keys:
- x_norm_clstoken: Normalized CLS token, equivalent to one used for BERT classification tasks? Use when global features are desired.
- x_storage_tokens: ??
- x_norm_patchtokens: Normalized patch tokens before normalization. Since these are per-patch features, use this depending on the case?
- x_prenorm: Per-patch tokens before normalization.
- masks: Probably not None if a mask is given.
When I checked the shapes, they were as follows:
print(feats['x_norm_clstoken'].shape) # >> torch.Size([1, 768])
print(feats['x_storage_tokens'].shape) # >> torch.Size([1, 0, 768])
print(feats['x_norm_patchtokens'].shape) # >> torch.Size([1, 49, 768])
print(feats['x_prenorm'].shape) # >> torch.Size([1, 49, 768])
print(feats['masks']) # >> None
That's it.
I hope this helps you when doing various things with the features.
Discussion