From 651dcfc2a0a4c9e0ef232e07a2c4c80e38aae747 Mon Sep 17 00:00:00 2001 From: Joaquin Terrasa Date: Wed, 23 Sep 2026 01:00:34 +0200 Subject: [PATCH 1/3] feat(gguf): map backbone-only DINOv2 variants in publish script --- scripts/publish-gguf.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/publish-gguf.sh b/scripts/publish-gguf.sh index 0ff8499..33a9840 100755 --- a/scripts/publish-gguf.sh +++ b/scripts/publish-gguf.sh @@ -63,9 +63,18 @@ case "$VARIANT" in dinov2-with-registers-base) HF_ID="facebook/dinov2-with-registers-base-imagenet1k-1-layer" ;; dinov2-with-registers-large) HF_ID="facebook/dinov2-with-registers-large-imagenet1k-1-layer" ;; dinov2-with-registers-giant) HF_ID="facebook/dinov2-with-registers-giant-imagenet1k-1-layer" ;; + dinov2-backbone-small) HF_ID="facebook/dinov2-small" ;; + dinov2-backbone-base) HF_ID="facebook/dinov2-base" ;; + dinov2-backbone-large) HF_ID="facebook/dinov2-large" ;; + dinov2-backbone-giant) HF_ID="facebook/dinov2-giant" ;; + dinov2-backbone-with-registers-small) HF_ID="facebook/dinov2-with-registers-small" ;; + dinov2-backbone-with-registers-base) HF_ID="facebook/dinov2-with-registers-base" ;; + dinov2-backbone-with-registers-large) HF_ID="facebook/dinov2-with-registers-large" ;; + dinov2-backbone-with-registers-giant) HF_ID="facebook/dinov2-with-registers-giant" ;; *) echo "ERROR: unknown variant '$VARIANT'" >&2 echo " known variants: dinov2-{small,base,large,giant} dinov2-with-registers-{small,base,large,giant}" >&2 + echo " dinov2-backbone-{small,base,large,giant} dinov2-backbone-with-registers-{small,base,large,giant}" >&2 exit 2 ;; esac From 19bbed2c365b9fa407634e0a77b616e3cc38801d Mon Sep 17 00:00:00 2001 From: Joaquin Terrasa Date: Wed, 23 Sep 2026 01:00:34 +0200 Subject: [PATCH 2/3] ci(gguf): add backbone-only variants to publish matrix --- .github/workflows/convert-and-publish-gguf.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/convert-and-publish-gguf.yml b/.github/workflows/convert-and-publish-gguf.yml index 39d49db..5165480 100644 --- a/.github/workflows/convert-and-publish-gguf.yml +++ b/.github/workflows/convert-and-publish-gguf.yml @@ -35,7 +35,7 @@ jobs: # Output a JSON array of variant strings so `fromJson(...)` in the # publish job's matrix can parse it. A space-separated string would # make fromJson throw a workflow-level error. - ALL_JSON='["dinov2-small","dinov2-base","dinov2-large","dinov2-giant","dinov2-with-registers-small","dinov2-with-registers-base","dinov2-with-registers-large","dinov2-with-registers-giant"]' + ALL_JSON='["dinov2-small","dinov2-base","dinov2-large","dinov2-giant","dinov2-with-registers-small","dinov2-with-registers-base","dinov2-with-registers-large","dinov2-with-registers-giant","dinov2-backbone-small","dinov2-backbone-base","dinov2-backbone-large","dinov2-backbone-giant","dinov2-backbone-with-registers-small","dinov2-backbone-with-registers-base","dinov2-backbone-with-registers-large","dinov2-backbone-with-registers-giant"]' if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.variant }}" != "all" ]; then # Wrap the single variant name in a JSON array. ONE_JSON="[\"${{ inputs.variant }}\"]" From 19edc4a00d0a68e3c0dc436e448d5f50f83735e9 Mon Sep 17 00:00:00 2001 From: Joaquin Terrasa Date: Wed, 23 Sep 2026 01:00:34 +0200 Subject: [PATCH 3/3] docs: document published backbone-only GGUF weights --- ARCHITECTURE.md | 2 +- README.md | 15 +++++++++++++++ docs/cli.md | 19 ++++++++++++++----- docs/hf-publishing.md | 39 ++++++++++++++++++++++++++------------- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 20dc784..5666c90 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -412,7 +412,7 @@ Deliberately untracked by `.gitignore` and not in release archives: - [docs/benchmarks.md](docs/benchmarks.md): how to read the tables, methodology, reproducing locally. - [docs/hf-publishing.md](docs/hf-publishing.md): `HF_TOKEN` setup, the - `convert-and-publish-gguf` workflow, the 8 published HF repos. + `convert-and-publish-gguf` workflow, the 16 published HF repos. - [README.md](README.md): quickstart, downloads, why this fork exists. - [GitHub releases](https://github.com/espetro/dinov2.cpp/releases): per-tag release notes, breaking changes, and upgrade notes. diff --git a/README.md b/README.md index b8de8b1..3da6034 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,21 @@ Ready-to-download f16 GGUF weights, published by CI to the [`dinov2-cpp-core`](h | large (registers) | [`dinov2-cpp-core/dinov2-with-registers-large-gguf`](https://huggingface.co/dinov2-cpp-core/dinov2-with-registers-large-gguf) | ~620 MB | **Recommended for patch/dense features** | | giant (registers) | [`dinov2-cpp-core/dinov2-with-registers-giant-gguf`](https://huggingface.co/dinov2-cpp-core/dinov2-with-registers-giant-gguf) | ~2.2 GB | **Recommended for patch/dense features** | +Backbone-only checkpoints carry the same encoder weights without the ImageNet +classifier head. They run the feature modes (`--print-embeddings`, +`--print-patch-tokens`, `-o` PCA, `--bench`) and reject `-c` cleanly: + +| Model | GGUF download | Size | Recommendation | +|:-----:|:--------------|-----:|:---------------| +| small (backbone, no registers) | [`dinov2-cpp-core/dinov2-backbone-small-gguf`](https://huggingface.co/dinov2-cpp-core/dinov2-backbone-small-gguf) | ~50 MB | Feature mode only; no classifier head | +| base (backbone, no registers) | [`dinov2-cpp-core/dinov2-backbone-base-gguf`](https://huggingface.co/dinov2-cpp-core/dinov2-backbone-base-gguf) | ~180 MB | Feature mode only; no classifier head | +| large (backbone, no registers) | [`dinov2-cpp-core/dinov2-backbone-large-gguf`](https://huggingface.co/dinov2-cpp-core/dinov2-backbone-large-gguf) | ~620 MB | Feature mode only; no classifier head | +| giant (backbone, no registers) | [`dinov2-cpp-core/dinov2-backbone-giant-gguf`](https://huggingface.co/dinov2-cpp-core/dinov2-backbone-giant-gguf) | ~2.2 GB | Feature mode only; no classifier head | +| small (backbone, registers) | [`dinov2-cpp-core/dinov2-backbone-with-registers-small-gguf`](https://huggingface.co/dinov2-cpp-core/dinov2-backbone-with-registers-small-gguf) | ~50 MB | Feature mode only; no classifier head | +| base (backbone, registers) | [`dinov2-cpp-core/dinov2-backbone-with-registers-base-gguf`](https://huggingface.co/dinov2-cpp-core/dinov2-backbone-with-registers-base-gguf) | ~180 MB | Feature mode only; no classifier head | +| large (backbone, registers) | [`dinov2-cpp-core/dinov2-backbone-with-registers-large-gguf`](https://huggingface.co/dinov2-cpp-core/dinov2-backbone-with-registers-large-gguf) | ~620 MB | Feature mode only; no classifier head | +| giant (backbone, registers) | [`dinov2-cpp-core/dinov2-backbone-with-registers-giant-gguf`](https://huggingface.co/dinov2-cpp-core/dinov2-backbone-with-registers-giant-gguf) | ~2.2 GB | Feature mode only; no classifier head | + For patch and dense feature workflows, the register-token variants are the recommended starting point. In the settings studied in [Vision Transformers Need Registers](https://arxiv.org/abs/2309.16588), register tokens reduce high-norm patch-token artifacts and produce smoother local feature and attention maps. Use them with `--print-patch-tokens`, PCA, dense features, and object discovery. This is not a universal accuracy claim: the official [DINOv2 results](https://github.com/facebookresearch/dinov2/blob/main/README.md) show classification and retrieval results that depend on the task and model size. Choose the no-register variant for exact baseline reproduction or task-specific classification and retrieval comparisons. ## Documentation diff --git a/docs/cli.md b/docs/cli.md index 66c2a97..59913a5 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -132,11 +132,20 @@ cleanly with a message that classification requires a classifier GGUF rather than attempting to access missing tensors. A missing `num_register_tokens` metadata key is treated as zero registers for feature mode. -The conversion and publishing workflows currently map the eight -`imagenet1k-1-layer` checkpoints and their register-token counterparts. They do -not publish backbone-only weights. Conversion and publishing of those weights -remains a follow-up, and this documentation does not claim that published -backbone-only files exist. +The publishing workflow converts the backbone checkpoints alongside the eight +`imagenet1k-1-layer` classifier variants and ships them as +`dinov2-cpp-core/dinov2-backbone-{size}-gguf` (from `facebook/dinov2-{size}`) +and `dinov2-cpp-core/dinov2-backbone-with-registers-{size}-gguf` (from +`facebook/dinov2-with-registers-{size}`), where `{size}` is `small`, `base`, +`large`, or `giant`: + +```bash +hf download dinov2-cpp-core/dinov2-backbone-small-gguf --local-dir models +dinov2-cli -m models/model.gguf -i assets/tench.jpg --print-embeddings +``` + +Use a backbone weight when you want the feature extractor without the +classifier head; for `-c` pick one of the classifier repos above. DINOv2 task heads other than the existing ImageNet classifier, including depth and segmentation, are outside this interface. DINOv3 is a separate diff --git a/docs/hf-publishing.md b/docs/hf-publishing.md index cf1f243..2d1beef 100644 --- a/docs/hf-publishing.md +++ b/docs/hf-publishing.md @@ -1,7 +1,7 @@ # HF publishing setup The [`convert-and-publish-gguf`](../.github/workflows/convert-and-publish-gguf.yml) -workflow converts the 8 DINOv2 variants to f16 GGUF and uploads them to the +workflow converts the 16 DINOv2 variants to f16 GGUF and uploads them to the `dinov2-cpp-core/-gguf` repos on Hugging Face. It runs monthly (cron `0 6 1 * *`) and on demand via `workflow_dispatch`. @@ -29,15 +29,28 @@ and on demand via `workflow_dispatch`. - The `giant` variants need ~12-13 GB transient disk, so those jobs free runner disk space first. -## The 8 published repos - -| Variant | HF repo | -|---|---| -| small | `dinov2-cpp-core/dinov2-small-gguf` | -| base | `dinov2-cpp-core/dinov2-base-gguf` | -| large | `dinov2-cpp-core/dinov2-large-gguf` | -| giant | `dinov2-cpp-core/dinov2-giant-gguf` | -| small (registers) | `dinov2-cpp-core/dinov2-with-registers-small-gguf` | -| base (registers) | `dinov2-cpp-core/dinov2-with-registers-base-gguf` | -| large (registers) | `dinov2-cpp-core/dinov2-with-registers-large-gguf` | -| giant (registers) | `dinov2-cpp-core/dinov2-with-registers-giant-gguf` | +## The 16 published repos + +| Variant | Source checkpoint | HF repo | +|---|---|---| +| small | `facebook/dinov2-small-imagenet1k-1-layer` | `dinov2-cpp-core/dinov2-small-gguf` | +| base | `facebook/dinov2-base-imagenet1k-1-layer` | `dinov2-cpp-core/dinov2-base-gguf` | +| large | `facebook/dinov2-large-imagenet1k-1-layer` | `dinov2-cpp-core/dinov2-large-gguf` | +| giant | `facebook/dinov2-giant-imagenet1k-1-layer` | `dinov2-cpp-core/dinov2-giant-gguf` | +| small (registers) | `facebook/dinov2-with-registers-small-imagenet1k-1-layer` | `dinov2-cpp-core/dinov2-with-registers-small-gguf` | +| base (registers) | `facebook/dinov2-with-registers-base-imagenet1k-1-layer` | `dinov2-cpp-core/dinov2-with-registers-base-gguf` | +| large (registers) | `facebook/dinov2-with-registers-large-imagenet1k-1-layer` | `dinov2-cpp-core/dinov2-with-registers-large-gguf` | +| giant (registers) | `facebook/dinov2-with-registers-giant-imagenet1k-1-layer` | `dinov2-cpp-core/dinov2-with-registers-giant-gguf` | +| small (backbone) | `facebook/dinov2-small` | `dinov2-cpp-core/dinov2-backbone-small-gguf` | +| base (backbone) | `facebook/dinov2-base` | `dinov2-cpp-core/dinov2-backbone-base-gguf` | +| large (backbone) | `facebook/dinov2-large` | `dinov2-cpp-core/dinov2-backbone-large-gguf` | +| giant (backbone) | `facebook/dinov2-giant` | `dinov2-cpp-core/dinov2-backbone-giant-gguf` | +| small (backbone, registers) | `facebook/dinov2-with-registers-small` | `dinov2-cpp-core/dinov2-backbone-with-registers-small-gguf` | +| base (backbone, registers) | `facebook/dinov2-with-registers-base` | `dinov2-cpp-core/dinov2-backbone-with-registers-base-gguf` | +| large (backbone, registers) | `facebook/dinov2-with-registers-large` | `dinov2-cpp-core/dinov2-backbone-with-registers-large-gguf` | +| giant (backbone, registers) | `facebook/dinov2-with-registers-giant` | `dinov2-cpp-core/dinov2-backbone-with-registers-giant-gguf` | + +The `dinov2-backbone-*` variants convert the backbone-only checkpoints, so +their GGUFs support feature modes only (`--print-embeddings`, +`--print-patch-tokens`, `-o` PCA, `--bench`) and reject `-c`. See +[cli.md](cli.md#backbone-only-checkpoints).