iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
📷

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:

  1. Clone facebookresearch/dinov3
  2. From the model list, request access for the desired model and obtain the dinov3_xxxx.pth file
  3. 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