📷

DINOv3を用いて画像から特徴量を抽出する

に公開

こんにちは、クロガネです。
今回はDINOv3を用いて画像から特徴量を抽出します。

わかる人はここを読めばいいと思います。
facebookresearch/dinov3
また、この記事は主に以下のノートブックを参考にしました。
https://colab.research.google.com/github/facebookresearch/dinov3/blob/main/notebooks/foreground_segmentation.ipynb

公式ではtransformersに対応しているようなことを書いていますが、2025/09/25の執筆時点で自環境(transformers 4.57.0.dev0)で動いてくれませんでした(なぜ?

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

なので、torch.hub.load()を用いてロード、特徴量を抽出するところのメモを残しておきます。

手順

やり方は単純で以下の通りです・

  1. facebookresearch/dinov3をクローン
  2. モデル一覧のリンクから、欲しいモデルの利用申請をして、dinov3_xxxx.pthファイルを取得
  3. リポジトリモデルをtorch.hub.load()を用いてロード

コードは以下の通りです。

import torch
import torchvision
from torchvision.transforms import v2
from PIL import Image
import requests
from IPython.display import display

# 上記githubリポジトリ内の前処理
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])

# モデルロード
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, # githubからクローンしたdinov3のリポジトリのルートディレクトリ
    'dinov3_convnext_tiny', # 使用するモデルの名前
    source='local', 
    weights=WEIGHT_DIR,# 使用するモデルファイルのディレクトリ
    ).cuda()

# 画像ロード
url = "http://images.cocodataset.org/val2017/000000039769.jpg"
image = Image.open(requests.get(url, stream=True).raw).convert('RGB')

# 画像の前処理
img_size = 224
transform = make_transform(img_size)
img_tensor = transform(image).unsqueeze(0).cuda() # モデルをcudaに送っているので.cudaが必要

# 特徴量を取得
with torch.no_grad():
    feats = model.forward_features(img_tensor)

取り出したfeatsはdict型で、以下のキーを含みます。

  • x_norm_clstoken: 正規化済みのCLSトークン、BERTの分類問題に転用するやつに相当?グローバルな特徴量が欲しい時に。
  • x_storage_tokens: ??
  • x_norm_patchtokens: 正規化前のパッチごとのトークン。各パッチの特徴量なので、場合によってはこれを使う?
  • x_prenorm: 正規化前のパッチごとのトークン。
  • masks: 多分、マスクを与えたらNoneじゃないはず

形状を確認したところ、以下のようになりました。

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

以上です。
特徴量を使っていろいろやるときの一助になれば幸いです。

Discussion