Composition Helper evaluates photographic composition using the Composition Assessment DataBase (CADB). The project reproduces SAMP-Net and compares it against three DINOv3 architectures that predict the same five-bin quality-score distribution:
The quality target is the distribution of five professional ratings from 1 to 5. The repository also supports CADB's separate 14-label composition classification target, although the reported experiments focus on quality assessment.
This work uses the dataset released with the CADB paper.
Only metrics from the locked 950-image official_test split are reported here.
Each DINOv3 value is the mean ± sample standard deviation over seeds 2026,
2027, and 2028 after retraining from scratch on all 8,547 official_train
images.
| Model | MSE ↓ | EMD ↓ | SRCC ↑ | LCC ↑ |
|---|---|---|---|---|
| Local SAMP-Net baseline | 0.386416 | 0.179775 | 0.655027 | 0.671127 |
| Frozen DINOv3 + Spatial Pyramid Pooling (SPP) | 0.406144 ± 0.002733 | 0.188797 ± 0.001206 | 0.670914 ± 0.007041 | 0.671303 ± 0.007829 |
| Frozen DINOv3 + attention pooling | 0.424356 ± 0.021629 | 0.193089 ± 0.000918 | 0.650294 ± 0.015451 | 0.642055 ± 0.020260 |
| Partially unfrozen DINOv3 + SPP | 0.358441 ± 0.013640 | 0.181350 ± 0.003493 | 0.718372 ± 0.005962 | 0.724384 ± 0.009473 |
The partially unfrozen architecture improved MSE, SRCC, and LCC over SAMP-Net. Its EMD was statistically indistinguishable from SAMP-Net for every seed. The supported conclusion is therefore better ranking and absolute error with EMD parity—not across-the-board superiority.
See the experiment-specific reports for SAMP-Net, frozen spatial-pyramid DINOv3, frozen attention-pooling DINOv3, and partially unfrozen DINOv3 for final-test provenance. Training-loop and development-validation metrics are not reported as final results.
| Architecture | Package | Backbone | Pooling |
|---|---|---|---|
| Frozen spatial pyramid | dinov3/ | Frozen | Spatial pyramid at levels 1, 2, and 3 |
| Frozen attention pooling | dinov3_attn/ | Frozen | Four learned queries and two cross-attention blocks |
| Partially unfrozen spatial pyramid | dinov3_unfrozen/ | Last 8 of 12 blocks trainable | Spatial pyramid at levels 1, 2, and 3 |
The released samp_net/ checkpoint is the controlled baseline, not
a fourth experimental architecture.
The project uses uv for Python dependencies and Just for repeatable commands. On macOS:
brew install uv just
just setup
This initializes the CADB source submodule and installs the locked Python
environment from uv.lock.
Download CADB using the instructions in the upstream repository and place the release at:
data/cadb/
├── images/
├── split.json
└── ...annotation files
The checked-in manifests under manifests/cadb/v1 define
the exact development and official partitions. Do not create ad hoc splits.
samp_net/checkpoints/samp_net.pth. The link is maintained
in the official CADB/SAMP-Net repository.facebook/dinov3-vits16plus-pretrain-lvd1689m, accept its
license, and cache the model through Hugging Face.The experiment recipes run in offline mode, so missing weights or dependencies fail immediately rather than downloading during a run.
just test
just smoke-frozen
just smoke-attention
just smoke-unfrozen
Every smoke test loads a real CADB batch and performs an optimization step. The
unfrozen smoke test additionally verifies that gradients reach the selected
backbone blocks but not the frozen prefix. Pass a device explicitly when
needed, for example just smoke-unfrozen mps or just smoke-frozen cuda.
Run just --list at any time to see every command and its arguments.
Development training uses train.json, selects the best checkpoint using only
validation.json, and never reads official_test.json.
just train-frozen
just train-attention
just train-unfrozen
All three commands share the same positional interface:
just <recipe> [device] [batch_size] [workers] [output_dir]
For example:
just train-frozen cuda 32 8 outputs/dinov3-frozen
just train-attention mps 16 0 outputs/dinov3-attn
just train-unfrozen cpu 8 4 outputs/dinov3-unfrozen
Each run writes:
OUTPUT_DIR/
├── seed-2026/
│ ├── best.pt
│ ├── metadata.json
│ └── validation.jsonl
├── seed-2027/
├── seed-2028/
└── validation-summary.json
The trainers are unguarded and may be rerun into an existing directory. Frozen
spatial-pyramid runs can reuse completed seed checkpoints with
just resume-frozen.
Recompute all four metrics and mean ± sample SD directly from saved predictions:
just aggregate-frozen-validation
just aggregate-attention-validation
just aggregate-unfrozen-validation
For a custom directory:
just aggregate-validation outputs/my-experiment
Aggregation validates the prediction schema, exact manifest membership and order, file hashes, and seed layout. It does not load a model or run inference. Development aggregation is explicitly marked as non-reportable.
After freezing a configuration, every architecture follows the same two-step
workflow. Training uses all of official_train and writes checkpoints without
reading official_test. Evaluation loads those checkpoints and writes ordered
test predictions plus final-report.json.
just train-frozen-final cuda 8 outputs/dinov3-frozen-official-train
just evaluate-frozen-final cuda 8 outputs/dinov3-frozen-official-train outputs/dinov3-frozen-official-test
just train-attention-final mps 0 outputs/dinov3-attn-official-train
just evaluate-attention-final mps 0 outputs/dinov3-attn-official-train outputs/dinov3-attn-official-test
just train-unfrozen-final cpu 4 outputs/dinov3-unfrozen-official-train
just evaluate-unfrozen-final cpu 4 outputs/dinov3-unfrozen-official-train outputs/dinov3-unfrozen-official-test
Training arguments are [device] [workers] [output_dir]; evaluation arguments
are [device] [workers] [checkpoint_root] [output_dir]. Both commands support
CPU, MPS, and CUDA. Final-test results must never guide model selection.
These commands only recompute metrics from predictions already on disk; they do not access images or repeat locked-test inference:
just aggregate-frozen-final
just aggregate-attention-final
just aggregate-unfrozen-final
For a custom output directory:
just aggregate-final outputs/my-final-run
just evaluate-samp-net cpu 16 0
The local checkpoint reproduces the paper closely:
| Metric | Published | Local |
|---|---|---|
| MSE ↓ | 0.3867 | 0.386416 |
| EMD ↓ | 0.1798 | 0.179775 |
| SRCC ↑ | 0.6564 | 0.655027 |
| LCC ↑ | 0.6709 | 0.671127 |
| Manifest | Images | Purpose |
|---|---|---|
train.json | 6,838 | Development training |
validation.json | 1,709 | Architecture, hyperparameter, checkpoint, and threshold selection |
official_train.json | 8,547 | Retraining a fully frozen configuration |
official_test.json | 950 | One final evaluation after configuration freeze |
Quality models predict five probabilities for scores 1–5. The predicted mean
is the expectation of that distribution. Every reported run saves ordered
per-image predictions, and the shared evaluator computes MSE, normalized EMD
(r=2), SRCC, and LCC from the same prediction file.
The official test set must never be used for training, early stopping, checkpoint selection, threshold selection, debugging, or design decisions.
This project builds on the following research and software:
CADB images, the released SAMP-Net checkpoint, and DINOv3 weights are not
included in this repository. Users must obtain them from their official
sources and comply with their respective terms. See
THIRD_PARTY_NOTICES.md for license boundaries and
source-level attribution.
shared/: CADB loading, manifests, prediction schema, metrics, and
result aggregation.samp_net/: reproduced SAMP-Net model, preprocessing, and
inference.dinov3/: frozen spatial-pyramid architecture.dinov3_attn/: frozen attention-pooling architecture.dinov3_unfrozen/: partially unfrozen spatial-pyramid
architecture.tests/: unit, parity, ordering, caching, and checkpoint tests.manifests/: authoritative versioned CADB partitions.just train-frozen-cached # Faster frozen-feature development condition
just train-frozen-tuned # No-dropout frozen candidate
just mlflow # Start MLflow at http://127.0.0.1:50000
Cached-token training is valid only while the backbone is frozen. Cached and uncached runs are numerically distinct and must not be mixed in one comparison.
Original work in this repository is available under the MIT License.
Third-party software, datasets, papers, model weights, and derivative model
materials remain subject to their respective terms; see
THIRD_PARTY_NOTICES.md.
If you use Composition Helper in research, please cite it using
CITATION.cff and cite the underlying research listed in the
acknowledgments.
58 commits
15 commits
Python
96.6%
Just
3.4%
Composition Helper evaluates photographic composition using the Composition Assessment DataBase (CADB). The project reproduces SAMP-Net and compares it against three DINOv3 architectures that predict the same five-bin quality-score distribution:
The quality target is the distribution of five professional ratings from 1 to 5. The repository also supports CADB's separate 14-label composition classification target, although the reported experiments focus on quality assessment.
This work uses the dataset released with the CADB paper.
Only metrics from the locked 950-image official_test split are reported here.
Each DINOv3 value is the mean ± sample standard deviation over seeds 2026,
2027, and 2028 after retraining from scratch on all 8,547 official_train
images.
| Model | MSE ↓ | EMD ↓ | SRCC ↑ | LCC ↑ |
|---|---|---|---|---|
| Local SAMP-Net baseline | 0.386416 | 0.179775 | 0.655027 | 0.671127 |
| Frozen DINOv3 + Spatial Pyramid Pooling (SPP) | 0.406144 ± 0.002733 | 0.188797 ± 0.001206 | 0.670914 ± 0.007041 | 0.671303 ± 0.007829 |
| Frozen DINOv3 + attention pooling | 0.424356 ± 0.021629 | 0.193089 ± 0.000918 | 0.650294 ± 0.015451 | 0.642055 ± 0.020260 |
| Partially unfrozen DINOv3 + SPP | 0.358441 ± 0.013640 | 0.181350 ± 0.003493 | 0.718372 ± 0.005962 | 0.724384 ± 0.009473 |
The partially unfrozen architecture improved MSE, SRCC, and LCC over SAMP-Net. Its EMD was statistically indistinguishable from SAMP-Net for every seed. The supported conclusion is therefore better ranking and absolute error with EMD parity—not across-the-board superiority.
See the experiment-specific reports for SAMP-Net, frozen spatial-pyramid DINOv3, frozen attention-pooling DINOv3, and partially unfrozen DINOv3 for final-test provenance. Training-loop and development-validation metrics are not reported as final results.
| Architecture | Package | Backbone | Pooling |
|---|---|---|---|
| Frozen spatial pyramid | dinov3/ | Frozen | Spatial pyramid at levels 1, 2, and 3 |
| Frozen attention pooling | dinov3_attn/ | Frozen | Four learned queries and two cross-attention blocks |
| Partially unfrozen spatial pyramid | dinov3_unfrozen/ | Last 8 of 12 blocks trainable | Spatial pyramid at levels 1, 2, and 3 |
The released samp_net/ checkpoint is the controlled baseline, not
a fourth experimental architecture.
The project uses uv for Python dependencies and Just for repeatable commands. On macOS:
brew install uv just
just setup
This initializes the CADB source submodule and installs the locked Python
environment from uv.lock.
Download CADB using the instructions in the upstream repository and place the release at:
data/cadb/
├── images/
├── split.json
└── ...annotation files
The checked-in manifests under manifests/cadb/v1 define
the exact development and official partitions. Do not create ad hoc splits.
samp_net/checkpoints/samp_net.pth. The link is maintained
in the official CADB/SAMP-Net repository.facebook/dinov3-vits16plus-pretrain-lvd1689m, accept its
license, and cache the model through Hugging Face.The experiment recipes run in offline mode, so missing weights or dependencies fail immediately rather than downloading during a run.
just test
just smoke-frozen
just smoke-attention
just smoke-unfrozen
Every smoke test loads a real CADB batch and performs an optimization step. The
unfrozen smoke test additionally verifies that gradients reach the selected
backbone blocks but not the frozen prefix. Pass a device explicitly when
needed, for example just smoke-unfrozen mps or just smoke-frozen cuda.
Run just --list at any time to see every command and its arguments.
Development training uses train.json, selects the best checkpoint using only
validation.json, and never reads official_test.json.
just train-frozen
just train-attention
just train-unfrozen
All three commands share the same positional interface:
just <recipe> [device] [batch_size] [workers] [output_dir]
For example:
just train-frozen cuda 32 8 outputs/dinov3-frozen
just train-attention mps 16 0 outputs/dinov3-attn
just train-unfrozen cpu 8 4 outputs/dinov3-unfrozen
Each run writes:
OUTPUT_DIR/
├── seed-2026/
│ ├── best.pt
│ ├── metadata.json
│ └── validation.jsonl
├── seed-2027/
├── seed-2028/
└── validation-summary.json
The trainers are unguarded and may be rerun into an existing directory. Frozen
spatial-pyramid runs can reuse completed seed checkpoints with
just resume-frozen.
Recompute all four metrics and mean ± sample SD directly from saved predictions:
just aggregate-frozen-validation
just aggregate-attention-validation
just aggregate-unfrozen-validation
For a custom directory:
just aggregate-validation outputs/my-experiment
Aggregation validates the prediction schema, exact manifest membership and order, file hashes, and seed layout. It does not load a model or run inference. Development aggregation is explicitly marked as non-reportable.
After freezing a configuration, every architecture follows the same two-step
workflow. Training uses all of official_train and writes checkpoints without
reading official_test. Evaluation loads those checkpoints and writes ordered
test predictions plus final-report.json.
just train-frozen-final cuda 8 outputs/dinov3-frozen-official-train
just evaluate-frozen-final cuda 8 outputs/dinov3-frozen-official-train outputs/dinov3-frozen-official-test
just train-attention-final mps 0 outputs/dinov3-attn-official-train
just evaluate-attention-final mps 0 outputs/dinov3-attn-official-train outputs/dinov3-attn-official-test
just train-unfrozen-final cpu 4 outputs/dinov3-unfrozen-official-train
just evaluate-unfrozen-final cpu 4 outputs/dinov3-unfrozen-official-train outputs/dinov3-unfrozen-official-test
Training arguments are [device] [workers] [output_dir]; evaluation arguments
are [device] [workers] [checkpoint_root] [output_dir]. Both commands support
CPU, MPS, and CUDA. Final-test results must never guide model selection.
These commands only recompute metrics from predictions already on disk; they do not access images or repeat locked-test inference:
just aggregate-frozen-final
just aggregate-attention-final
just aggregate-unfrozen-final
For a custom output directory:
just aggregate-final outputs/my-final-run
just evaluate-samp-net cpu 16 0
The local checkpoint reproduces the paper closely:
| Metric | Published | Local |
|---|---|---|
| MSE ↓ | 0.3867 | 0.386416 |
| EMD ↓ | 0.1798 | 0.179775 |
| SRCC ↑ | 0.6564 | 0.655027 |
| LCC ↑ | 0.6709 | 0.671127 |
| Manifest | Images | Purpose |
|---|---|---|
train.json | 6,838 | Development training |
validation.json | 1,709 | Architecture, hyperparameter, checkpoint, and threshold selection |
official_train.json | 8,547 | Retraining a fully frozen configuration |
official_test.json | 950 | One final evaluation after configuration freeze |
Quality models predict five probabilities for scores 1–5. The predicted mean
is the expectation of that distribution. Every reported run saves ordered
per-image predictions, and the shared evaluator computes MSE, normalized EMD
(r=2), SRCC, and LCC from the same prediction file.
The official test set must never be used for training, early stopping, checkpoint selection, threshold selection, debugging, or design decisions.
This project builds on the following research and software:
CADB images, the released SAMP-Net checkpoint, and DINOv3 weights are not
included in this repository. Users must obtain them from their official
sources and comply with their respective terms. See
THIRD_PARTY_NOTICES.md for license boundaries and
source-level attribution.
shared/: CADB loading, manifests, prediction schema, metrics, and
result aggregation.samp_net/: reproduced SAMP-Net model, preprocessing, and
inference.dinov3/: frozen spatial-pyramid architecture.dinov3_attn/: frozen attention-pooling architecture.dinov3_unfrozen/: partially unfrozen spatial-pyramid
architecture.tests/: unit, parity, ordering, caching, and checkpoint tests.manifests/: authoritative versioned CADB partitions.just train-frozen-cached # Faster frozen-feature development condition
just train-frozen-tuned # No-dropout frozen candidate
just mlflow # Start MLflow at http://127.0.0.1:50000
Cached-token training is valid only while the backbone is frozen. Cached and uncached runs are numerically distinct and must not be mixed in one comparison.
Original work in this repository is available under the MIT License.
Third-party software, datasets, papers, model weights, and derivative model
materials remain subject to their respective terms; see
THIRD_PARTY_NOTICES.md.
If you use Composition Helper in research, please cite it using
CITATION.cff and cite the underlying research listed in the
acknowledgments.
58 commits
15 commits
Python
96.6%
Just
3.4%