marigold-v2 README

The project's README from github.com/huawei-bayerlab/marigold-v2. As one markdown file: README.md.

Marigold V2

Revisiting Diffusion Transformers for Monocular Depth Estimation

ACM Transactions on Graphics (SIGGRAPH Asia 2026)

Igor Pavlovic1,2,*,†, Thiemo Wandel2,*, Anton Obukhov2,§
Luca Bartolomei3, Andrey Davydov2, Fabio Tosi3, Matteo Poggi3, Sabine Süsstrunk1, Dengxin Dai2

1EPFL · 2HUAWEI Bayer Lab · 3University of Bologna · *Equal contribution · †Internship · §Project lead

Project website  Paper  Demo  Weights  Follow


Marigold V2 is a family of models and a cost-effective fine-tuning protocol that repurposes a pretrained diffusion transformer into single-step dense predictors: depth, see-through depth, surface normals, albedo, and other dense modalities. Fine-tuning takes less than a week on a single consumer GPU, within reach of individual practitioners and small labs, and the results are state of the art, faithfully reproducing sharp edges, fur, and hair-thin details. The same models also unlock applications such as metric depth completion.

Marigold V2 depth predictions compared to prior work

This repository contains inference, evaluation, and training code, plus the configs of every released checkpoint.

News

2026-12: To appear in ACM Transactions on Graphics 45(6) and to be presented at SIGGRAPH Asia 2026.
2026-09: Initial release: inference, evaluation, and training code, the released checkpoints, and the demo.

Quick start

Requirements: Linux, Python 3.10, a CUDA GPU. Inference at 1024² needs about 17 GB of GPU memory and 2048² about 29 GB; the DiT is quantized to 4 bit when it is first loaded, which takes a few minutes.

git clone https://github.com/huawei-bayerlab/marigold-v2.git
cd marigold-v2
bash setup/setup_env.sh            # conda env "marigold-v2", CUDA 12.8 wheels; pass cu126 etc. to change
conda activate marigold-v2

python scripts/download_assets.py --skip-datasets   # Qwen-Image-Edit-2509 + all Marigold V2 checkpoints
python scripts/infer.py --image_dir assets/examples --output_dir output/examples

Depth predictions land in output/examples/images/predictions_npy/ as float32 .npy files and in visualizations/depth_spectral/ as PNGs. Everything the repository downloads goes to assets/ (or $DEPTH_ASSETS_DIR).

Checkpoints

All checkpoints share the frozen Qwen-Image-Edit-2509 backbone and are stored as trainables.safetensors (LoRA adapters and, where trained, the VAE decoder) in huawei-bayerlab/marigold-v2-0. The depth checkpoints differ in how depth is parameterized before it enters the VAE and in the training stage.

Checkpoint Output Training Config
depth/Log-stage2 (default) affine-invariant log depth Stage 1 → Stage 2 (SinkLoss, VAE decoder fine-tuned). The paper model. training_relative_log_depth_config_stage2.yaml
depth/Log-stage1 affine-invariant log depth Stage 1 only: latent MSE + L1 + gradient + iREPA, 160k steps. Initialization for Stage 2 and layered fine-tuning. training_relative_log_depth_config.yaml
depth/Log-layered see-through log depth Log-stage1 fine-tuned with SinkLoss on layer 8 of LayeredDepth-Syn: predicts geometry behind glass. training_relative_log_depth_layered_config.yaml
depth/Uniform-base affine-invariant linear depth (Marigold V1 style) Stage 1 recipe, 30k steps. Parameterization ablation. training_relative_config.yaml
depth/Disparity-base affine-invariant inverse depth Stage 1 recipe with VAE decoder fine-tuning, 30k steps. Parameterization ablation. training_relative_disp_config.yaml
depth/Disparity-layered see-through inverse depth Stage 1 recipe on layer 8 of LayeredDepth-Syn. training_relative_disp_layered_config.yaml
depth/Uniform-layered see-through linear depth LayeredDepth-Syn variant of Uniform-base. not included
normals camera-space unit normals angular loss + iREPA + SinkLoss, VAE decoder fine-tuned, 30k steps training_normals.yaml
albedo linear RGB albedo in [0, 1] L1 + iREPA, VAE decoder fine-tuned, 30k steps training_albedo.yaml

Depth configs live in marigoldv2/experiments/20260316_qwen_depth/, the normals and albedo configs in marigoldv2/experiments/20260728_qwen_normals/ and marigoldv2/experiments/20260803_qwen_albedo/. Log and linear depth increase with distance, disparity decreases; the values are affine-invariant, i.e. up to an unknown scale and shift per image.

The precomputed Qwen text-prompt embeddings under Marigold-V2/qwen_text_embeddings/ replace the text encoder at inference and training time, so the 7B text encoder is never loaded.

Inference

python scripts/infer.py --modality depth   --image_dir /path/to/images --output_dir output/depth
python scripts/infer.py --modality normals --image_dir /path/to/images --output_dir output/normals
python scripts/infer.py --modality albedo  --image_dir /path/to/images --output_dir output/albedo
Flag Meaning
--modality depth (default), normals, or albedo; selects the default checkpoint and prompt embedding
--checkpoint checkpoint directory or Hugging Face repo[/subfolder], e.g. assets/checkpoints/Marigold-V2/depth/Log-layered
--width, --height run at a fixed resolution instead of the native one (rounded up to a multiple of 16)
--seed seed for the VAE encoder sampling (default 2025)

Outputs mirror the input folder structure under <output_dir>/images/: predictions_npy/*.npy (depth: [H, W]; normals and albedo: [3, H, W]) and visualizations/<modality>/*.png. Predictions are resized back to the input resolution.

Evaluation

Download the depth and surface-normal benchmarks separately using the instructions below; scripts/download_assets.py does not download these evaluation datasets. Run these commands from the repository root. They use assets/ by default, or $DEPTH_ASSETS_DIR when set, matching the evaluation launchers.

For depth estimation, download the Marigold evaluation datasets and extract each tar archive into its containing directory:

(
  set -e
  mkdir -p "${DEPTH_ASSETS_DIR:-assets}/datasets/marigold_depth_eval"
  cd "${DEPTH_ASSETS_DIR:-assets}/datasets/marigold_depth_eval"
  wget -r -np -nH --cut-dirs=4 -R "index.html*" -P . https://share.phys.ethz.ch/~pf/bingkedata/marigold/evaluation_dataset/
  find . -type f -name '*.tar' -print0 | while IFS= read -r -d '' archive; do
    tar -xf "$archive" -C "$(dirname "$archive")"
  done
)

For normal estimation, create the destination directory and download the official Marigold evaluation archive:

NORMALS_ROOT="${DEPTH_ASSETS_DIR:-assets}/datasets/marigold_normals_eval"
mkdir -p "$NORMALS_ROOT"
(
  set -e
  cd "$NORMALS_ROOT"
  wget -O evaluation_dataset.zip \
    https://share.phys.ethz.ch/~pf/bingkedata/marigold/marigold_normals/evaluation_dataset.zip
  unzip -n evaluation_dataset.zip
)

Download the preprocessed Sintel benchmark separately into the same directory, then extract it:

(
  set -e
  cd "$NORMALS_ROOT"
  wget -O sintel.zip \
    https://share.phys.ethz.ch/~pf/bingkedata/marigold/marigold_normals/sintel.zip
  unzip -n sintel.zip
)

Both archives should extract directly under marigold_normals_eval/; do not add another enclosing directory. The dataset directories must sit directly under the benchmark root as shown below (downloaded archives can remain):

assets/                         # or $DEPTH_ASSETS_DIR
└── datasets/
    ├── marigold_depth_eval/
    │   ├── diode/
    │   ├── eth3d/
    │   ├── kitti/
    │   ├── nyuv2/
    │   └── scannet/
    └── marigold_normals_eval/
        ├── ibims/ibims/
        ├── nyuv2/test/
        ├── scannet/
        └── sintel/

Each launcher below writes predictions and metrics under output/eval_runs/ and prints where. Add MAX_SAMPLES as the second argument to any launcher for a quick partial run.

Zero-shot depth on NYUv2, KITTI, ETH3D, ScanNet, and DIODE with the Pixel-Perfect Depth protocol (RANSAC alignment in log space, native resolution; ETH3D is upsampled to 2048×1360 before scoring):

bash evaluation/depth/run_infer_and_eval.sh                       # Log-stage2, all datasets
bash evaluation/depth/run_infer_and_eval.sh <checkpoint> "" 1 evaluation/config/inference_depth.yaml kitti,eth3d
bash evaluation/depth/run_eval_from_preds.sh output/eval_runs/depth_<stamp>/predictions   # rescore existing predictions
NYUv2 KITTI ETH3D ScanNet DIODE
AbsRel ↓ / δ1 ↑ 3.6 / 98.0 5.4 / 97.4 2.8 / 99.2 3.7 / 97.9 5.2 / 97.1

Soft Edge Error on the Hypersim test split at native resolution. Needs the Hypersim training data:

python scripts/download_assets.py
bash evaluation/depth_see/run_hypersim_origres_edge_eval.sh        # SEE_1,3,5,7; paper: 0.352 / 0.333 / 0.320 for k = 3, 5, 7

Surface normals on NYUv2, ScanNet, iBims-1, and Sintel:

bash evaluation/normals/run_qwen_normals_infer_and_eval.sh        # mean angular error / % within 11.25°
NYUv2 ScanNet iBims-1 Sintel
mean err ↓ / 11.25° ↑ 16.6 / 61.2 14.1 / 67.4 15.9 / 70.9 28.7 / 27.6

The Hypersim normals edge metric (SAEE) needs the Hypersim normals dataset:

python scripts/download_assets.py
bash scripts/hypersim_normals/download_and_preprocess_hypersim_normals.sh
bash evaluation/normals_saee/run_hypersim_normals_origres_edge_eval.sh

Albedo on the Hypersim IID test split needs the Hypersim albedo dataset; expected PSNR 20.78, SSIM 0.811, LPIPS 0.195:

python scripts/download_assets.py
bash scripts/hypersim_albedo/download_and_preprocess_hypersim_albedo.sh
bash evaluation/albedo/run_qwen_albedo_infer.sh assets/checkpoints/Marigold-V2/albedo output/eval_runs/albedo
bash evaluation/albedo/run_qwen_albedo_eval.sh output/eval_runs/albedo/hypersim_test_albedo_qwen_native output/eval_runs/albedo/metrics

Training

All released models were trained on a single 32 GB GPU with batch size 1. Stage 1 of the depth model (160k steps) takes about five days, every other config (30k steps) about one day.

Data. Depth trains on Hypersim and Virtual KITTI 2 as repackaged for Marigold V1; iREPA needs DINOv3, which is gated on Hugging Face (accept the terms on the model page, then hf auth login):

python scripts/download_assets.py --include-dinov3          # checkpoints, DINOv3, and training data
python scripts/download_assets.py --include-layereddepth-syn --skip-checkpoints   # optional; downloads and prepares LayeredDepth-Syn
bash scripts/hypersim_normals/download_and_preprocess_hypersim_normals.sh          # optional, ~1.2 TB, for normals
bash scripts/hypersim_albedo/download_and_preprocess_hypersim_albedo.sh            # optional, ~500 GB, for albedo

The two Hypersim scripts run the Marigold V1.1 preprocessors scene by scene and resume after interruption; see their READMEs under scripts/.

Reproducing the depth model.

# Stage 1: iREPA + pixel losses on Hypersim + vKITTI (160k steps)
python marigoldv2/script/train/train.py \
  --config marigoldv2/experiments/20260316_qwen_depth/training_relative_log_depth_config.yaml \
  --output_dir output/train_runs --no_wandb

# Stage 2: SinkLoss with VAE decoder fine-tuning, initialized from Stage 1 (30k steps)
python marigoldv2/script/train/train.py \
  --config marigoldv2/experiments/20260316_qwen_depth/training_relative_log_depth_config_stage2.yaml \
  --output_dir output/train_runs --no_wandb

The Stage 2 config initializes from assets/checkpoints/Marigold-V2/depth/Log-stage1; point paths.env_paths.checkpoint at your own Stage 1 run to chain them. Any other config in the table above trains the same way.

A run writes to <output_dir>/<config stem>/: config.yaml, a code snapshot, TensorBoard logs, validation visualizations, and checkpoint/checkpoint-{best,latest,<step>}/. Each checkpoint folder holds trainables.safetensors, which is exactly the format of the released checkpoints, so it can be passed to scripts/infer.py --checkpoint or to any evaluation launcher directly. Resume an interrupted run with --resume_run <run>/checkpoint/checkpoint-latest. Weights & Biases logging is on unless --no_wandb is given; add --add_datetime_prefix to keep several runs of one config apart.

Multi-GPU training uses accelerate launch --multi_gpu marigoldv2/script/train/train.py ...; each GPU keeps the configured per-process batch size, increasing the effective global batch size. optimization.gpu_scaling divides total and periodic step counts by the number of processes, keeping the number of seen samples approximately constant.

Extending to a new task

The training framework is a small registry of building blocks composed by YAML. A training config declares:

The surface-normal experiment is the smallest complete example of a new task, in marigoldv2/experiments/20260728_qwen_normals/: data.py adds a manifest loader and normal-aware transforms, network_graph.py adds one output step that turns the decoded RGB into unit normals, loss.py adds the angular loss, validation.py adds metrics and visualizations, and training_normals.yaml wires them together with the shared depth blocks. The albedo experiment follows the same pattern.

To add a task: copy a dataset YAML and adapt its manifest loader and transforms; write the output step, loss, and validation steps in a new experiment folder; list the new modules under register_modules; then run a short training with --output_dir output/debug. For inference on plain image folders, add an output adapter to marigoldv2/validation/folder_steps.py and a MODALITIES entry in scripts/infer.py.

Repository layout

setup/setup_env.sh       creates the conda environment and installs the package
scripts/                 infer.py (inference on image folders), download_assets.py, Hypersim dataset builders
marigoldv2/              training framework: core registry, datasets, losses, trainer, validation
  experiments/           one folder per released model family with its configs and task-specific modules
  config/datasets/       dataset definitions shared by the training configs
  script/train/train.py  training entry point
evaluation/              benchmark launchers (depth, depth_see, normals, normals_saee, albedo), their configs, data splits
evaluation/src/          Marigold V1 benchmark datasets and metrics
assets/                  downloads (git-ignored) plus tracked example images

Checklist

Troubleshooting

Problem Solution
CUDA out of memory Inference needs about 17 GB at 1024² and 29 GB at 2048². Reduce --width and --height; both must stay multiples of 16.
The same image gives slightly different predictions The VAE encoder samples its latent. Pass --seed to make runs reproducible.
A config cannot find a dataset or a checkpoint Point DEPTH_ASSETS_DIR at your assets folder. Download checkpoints and training data with python scripts/download_assets.py; for depth and normals benchmarks, follow Evaluation.

Contributing

Bug reports are welcome. Before sending a pull request, please open an issue to discuss the change with the maintainers.

AGENTS.md documents the repository layout, the registry the configs are built on, and the conventions to keep.

Citation

@article{pavlovic2026marigoldv2,
    author = {Pavlovic, Igor and Wandel, Thiemo and Obukhov, Anton and Bartolomei, Luca and Davydov, Andrey and Tosi, Fabio and Poggi, Matteo and S{\"u}sstrunk, Sabine and Dai, Dengxin},
    title = {Marigold V2: Revisiting Diffusion Transformers for Monocular Depth Estimation},
    year = {2026},
    issue_date = {December 2026},
    publisher = {Association for Computing Machinery},
    volume = {45},
    number = {6},
    url = {https://doi.org/10.1145/3842528},
    doi = {10.1145/3842528},
    journal = {ACM Trans. Graph.},
    month = dec,
    articleno = {204},
    numpages = {14}
}

Acknowledgements

Marigold V2 builds on Marigold V1, whose evaluation code and dataset preprocessing are reused here, and on Qwen-Image-Edit-2509. The depth evaluation protocol follows Pixel-Perfect Depth, the Sintel normals protocol follows Lotus-2, and see-through depth uses LayeredDepth-Syn.

License

Code and models are released under the Apache License, Version 2.0 (see LICENSE and NOTICE). Qwen-Image-Edit-2509 and the datasets keep their own licenses.

marigold-v2 (huawei-bayerlab/marigold-v2)

Searching Database…

这是什么?Marigold V2 是一组模型和一套高性价比的微调协议,它把预训练的扩散 transformer 改造为单步稠密预测器:深度、穿透深度、表面法线、反照率以及其他稠密模态。
这是现成的应用,还是论文的研究代码?它是 ACM TOG / SIGGRAPH Asia 2026 论文背后的官方研究代码库:包含推理、评估和训练脚本,以及每个已发布检查点所用的精确配置,而不是打包好的应用。
怎么对一张图像运行推理?运行 scripts/infer.py 并指定 --modality(默认 depth,也可选 normals/albedo),可选地用 --checkpoint 指向本地文件夹或 Hugging Face 仓库;深度预测会以 float32 的 .npy 文件和 PNG 可视化图输出。
我需要什么硬件和软件?你需要 Linux、Python 3.10 和一块 CUDA GPU;10242 分辨率下推理约需 17 GB 显存,20482 分辨率下约需 29 GB,因为 DiT 主干在首次加载时会被量化到 4-bit。
显存或可复现性方面有什么要注意的坑?出现 CUDA 显存不足就应该调低 --width/--height(必须保持为 16 的倍数);VAE 编码器会对潜在变量采样,因此除非传入固定的 --seed,同一张图可能得到略有不同的预测。
Apache-2.0 许可证覆盖仓库里的所有内容吗?代码和 Marigold V2 自身的检查点采用 Apache-2.0,但冻结的 Qwen-Image-Edit-2509 主干以及训练/评估数据集各自保留独立的许可证。
微调需要多长时间?微调在单张 32 GB 消费级 GPU 上以 batch size 1 运行;深度的 Stage 1 训练(16 万步)大约需要五天,其他所有配置(3 万步)大约需要一天。
这些检查点使用什么主干模型?所有检查点共享冻结的 Qwen-Image-Edit-2509 扩散 transformer 主干,只有 LoRA 适配器(有时还有 VAE 解码器)以 trainables.safetensors 的形式保存。
我能在新的稠密预测任务上训练它吗?可以——训练框架是一个由 YAML 驱动的注册表,管理数据集、网络图和损失图,仓库还包含一个完整的表面法线示例,清楚展示如何接入一个新任务。
还有哪些内容尚未发布?根据仓库的清单,深度补全代码、穿透深度评估、Diffusers 集成和 ComfyUI 插件仍未完成。
Size
12.6 MB
Stars
914
Updated
CommitOct 05
Age
1mo
Commits · 90 Days