DepthPro 深度指南:用 Transformers 实现零样本公制单目深度估计
DepthPro 是 2024 年 10 月发表于 Hugging Face 论文页、由社区贡献者 geetu040 移植进 🤗 Transformers 的深度估计基础模型(模型文档)。它无需任何元数据(如相机内参)即可从单张 RGB 图像输出带绝对尺度的公制深度图,同时保持边界锐利与高频细节。本文将以该文档为主体,结合 depth_pro 模型源码 与配置实现,讲解其多尺度 ViT + DPT 融合架构、DepthProConfig 全量配置项、FOV(视场角)预测开关、图像预处理/后处理管线,并给出可直接运行的推理脚本与 SDPA 加速建议,帮助你快速把 DepthPro 接入自己的深度估计流程。
DepthPro 是什么:零样本、公制尺度、亚秒级
DepthPro(论文名《Depth Pro: Sharp Monocular Metric Depth in Less Than a Second》)是一个面向 zero-shot metric monocular depth estimation(零样本公制单目深度估计)的基础模型。与只能输出相对深度的经典单目深度模型不同,DepthPro 的预测是 metric(带绝对物理尺度) 的,不依赖相机内参这类元数据即可直接给出与真实世界尺度对齐的深度;其设计目标还包括在标准 GPU 上约 0.3 秒内产出 2.25 兆像素(约 225 万像素)的高分辨率深度图。
从论文摘要与文档描述可以归纳出支撑这些能力的几项关键技术贡献:
- 面向稠密预测的高效多尺度 Vision Transformer:对输入做多尺度缩放与切块,用共享的 ViT 编码器提取 patch 级特征,再重建、上采样并融合,兼顾高分辨率与计算效率;
- 真实数据 + 合成数据的联合训练协议:让模型在获得较高公制精度的同时具备精细的边界追踪能力;
- 专门的深度图边界精度评估指标;
- 单图焦点长度(focal length)估计:模型扩展出 FOV/焦点长度预测能力。
模型由 DepthPro 编码器与融合模块 实现,DepthProForDepthEstimation 负责端到端的深度估计推理。仓库中同时提供将 Apple 官方权重转换为 Transformers 格式的脚本 convert_depth_pro_weights_to_hf.py,对应检查点为 apple/DepthPro-hf。
整体架构:多尺度 ViT 编码 + DPT 式融合解码
按照 DepthPro 模型文档 的说明,DepthPro 的处理流水线可拆成四条主线:
- 输入图像在多个尺度上被降采样,每个缩放版本再被切成若干重叠 patch;
- 所有 patch 由一个共享的 Dinov2 patch 编码器处理,与此同时完整图像被送入另一个独立的 image 编码器;
- patch 编码得到的特征经过
merge / upsample / refine重建为特征图; - 重建出的特征送入 DPT-like 的
FeatureFusionStage融合,最终输出深度图。
在源码中,这一架构由 DepthProModel、DepthProForDepthEstimation 等类具体实现,其中 DepthProForDepthEstimation 使用一个 DepthProEncoder(编码输入图像)和一个 FeatureFusionStage(融合编码器输出特征)。
DepthProEncoder 内部包含两个编码器,均在 modeling_depth_pro.py 中定义:
patch_encoder(源码):- 输入图像按
scaled_images_ratios配置的多个比例缩放(默认[0.25, 0.5, 1.0],即三级图像金字塔); - 每个缩放图像按
patch_size切成小 patch,重叠比例由scaled_images_overlap_ratios决定(源码中通过F.unfold实现,见 split_to_patches); - patch 被
torch.cat拼接后以 batch 方式整体送入共享 patch 编码器(源码注释:高分辨率 patch 在前); - 编码器输出经过 reconstruct_feature_maps(reshape → 去重叠 padding 合并 → 双线性插值回目标尺寸)重建成特征图。
- 输入图像按
image_encoder(源码):- 输入图像被重缩放到
patch_size(默认 384),由独立的 image 编码器整体处理,提供全局上下文特征。
- 输入图像被重缩放到
两个编码器均可通过配置项 patch_model_config 与 image_model_config 分别定制,默认都是独立的 Dinov2Model(配置构造时自动回退,见下文 DepthProConfig 一节)。
融合阶段则使用 DPT 风格解码:patch 编码器输出的 last_hidden_state 与选中的若干中间层 hidden_states(由 intermediate_hook_ids 指定)一起进入 FeatureFusionStage。融合网络由三个关键组件构成(源码):
DepthProPreActResidualLayer:pre-activation 残差单元(ReLU → Conv → ReLU → Conv + 残差相加,可选 BatchNorm);DepthProFeatureFusionLayer:双残差单元 + 可选转置卷积上采样 + 1×1 投影;DepthProFeatureFusionStage:层数为len(intermediate_hook_ids) + len(scaled_images_ratios)(默认 2+3=5),其中除最后一层外都带转置卷积上采样,最后一层用 1×1 投影收尾。
值得注意:DepthProModel 与 DepthProEncoder 输出的是特征集合(DepthProOutput.features),真正的深度回归发生在 DepthProForDepthEstimation:它由 DepthProModel + FeatureFusionStage + 3 层卷积的深度估计头组成,深度头(DepthProDepthEstimationHead)逐层降维并上采样,最终压成单通道深度图,输出结构为 DepthProDepthEstimatorOutput(含 predicted_depth、可选的 field_of_view)。
DepthProConfig:配置参数全解
DepthProConfig 定义在 configuration_depth_pro.py,model_type = "depth_pro"。与多数模型不同,它声明了三个子配置 sub_configs = {"image_model_config", "patch_model_config", "fov_model_config"},子配置通过 AutoConfig 解析。
核心字段与默认值
| 配置参数 | 默认值 | 含义 |
|---|---|---|
fusion_hidden_size |
256 |
融合阶段(各子网统一投影到)的通道数 |
patch_size |
384 |
patch 边长,同时用于切块与图像重缩放目标尺寸 |
initializer_range |
0.02 |
权重初始化范围 |
intermediate_hook_ids |
(11, 5) |
从 patch 编码器取中间层特征用于融合的层索引 |
intermediate_feature_dims |
(256, 256) |
上述每个中间层特征上采样过程的隐层维度 |
scaled_images_ratios |
(0.25, 0.5, 1.0) |
patch 编码器使用的多尺度图像缩放比例(需升序排列) |
scaled_images_overlap_ratios |
(0.0, 0.5, 0.25) |
每个缩放级别下相邻 patch 的重叠比例 |
scaled_images_feature_dims |
(1024, 1024, 512) |
每个缩放级别特征重建/上采样过程的隐层维度 |
merge_padding_value |
3 |
小块合并回整图时,相邻块重叠边缘需要裁掉的宽度 |
use_batch_norm_in_fusion_residual |
False |
融合残差单元是否使用 BatchNorm |
use_bias_in_fusion_residual |
True |
融合残差单元卷积是否使用 bias |
use_fov_model |
False |
是否启用 DepthProFovModel 预测水平视场角 |
num_fov_head_layers |
2 |
FOV 预测头的卷积层数量 |
image_model_config |
None |
image 编码器配置(通过 AutoModel 加载,默认 Dinov2) |
patch_model_config |
None |
patch 编码器配置(通过 AutoModel 加载,默认 Dinov2) |
fov_model_config |
None |
FOV 编码器配置(通过 AutoModel 加载,默认 Dinov2) |
(默认值对应关系见 configuration_depth_pro.py 中的字段声明。)
自动解析与一致性校验
__post_init__(源码)会处理三个子配置,规则如下:
- 若子配置为
None:自动以CONFIG_MAPPING["dinov2"]生成Dinov2Config,且将其image_size强制设为config.patch_size(默认 384); - 若子配置为
dict:必须包含受支持的model_type键,image_size若不等于patch_size会被自动修正并打印日志; - 若子配置为
PreTrainedConfig:其image_size必须与patch_size一致,否则抛ValueError。
此外 validate_architecture(源码)会在严格模式下校验架构合法性:
scaled_images_ratios必须从低到高升序排列;scaled_images_ratios/scaled_images_overlap_ratios/scaled_images_feature_dims三者长度必须一致;intermediate_hook_ids与intermediate_feature_dims长度必须一致;fusion_hidden_size // 2**num_fov_head_layers必须大于 0(保证 FOV 头逐层减半通道后仍有意义)。
这些长度一致性约束直接呼应上面的参数表——改动某个比例列表时,务必同步更新配套列表,否则会构造失败。
快速上手:单张图片的端到端深度估计
最小推理示例
仓库文档给出了完整推理脚本,流程为:取图 → DepthProImageProcessor 预处理 → DepthProForDepthEstimation 前向 → post_process_depth_estimation 后处理 → 可视化。下文在其基础上补充了逐行注释:
import requests
import torch
from PIL import Image
from transformers import DepthProForDepthEstimation, DepthProImageProcessor
# 1. 加载示例图片(COCO 验证集)
url = 'http://images.cocodataset.org/val2017/000000039769.jpg'
image = Image.open(requests.get(url, stream=True).raw)
# 2. 加载图像处理器与模型(device_map="auto" 便于自动分配到可用设备)
image_processor = DepthProImageProcessor.from_pretrained("apple/DepthPro-hf")
model = DepthProForDepthEstimation.from_pretrained("apple/DepthPro-hf", device_map="auto")
# 3. 预处理并前向
inputs = image_processor(images=image, return_tensors="pt").to(model.device)
with torch.no_grad():
outputs = model(**inputs)
# 4. 后处理:把预测深度插值回原图尺寸,并解析 FOV / 焦距
post_processed_output = image_processor.post_process_depth_estimation(
outputs, target_sizes=[(image.height, image.width)],
)
field_of_view = post_processed_output[0]["field_of_view"]
focal_length = post_processed_output[0]["focal_length"]
depth = post_processed_output[0]["predicted_depth"]
# 5. 归一化到 0-255 并转成可视灰度图
depth = (depth - depth.min()) / depth.max()
depth = depth * 255.
depth = depth.detach().cpu().numpy()
depth = Image.fromarray(depth.astype("uint8"))
DepthProModel 也可独立使用(不含深度头)。模型文档 与 DepthProModel.forward 的 docstring 展示了用 AutoProcessor / AutoImageProcessor 的等价写法:此时 processor = AutoImageProcessor.from_pretrained(checkpoint),模型输出 last_hidden_state 的形状形如 (1, 35, 577, 1024)(patch 编码的多尺度特性使序列维较大)。
预处理与后处理的两个"反直觉"细节
DepthProImageProcessor(image_processing_depth_pro.py)默认参数为:输入尺寸 1536×1536、双线性插值、ImageNet 均值和方差、do_resize / do_rescale / do_normalize 全为 True。
其自定义 _preprocess(源码)有一个特殊顺序——先 rescale+normalize,再做 resize,并且 resize 关闭抗锯齿(antialias=False),使用 torch 插值以正确处理负像素值。这与大多数"先缩放后归一化"的视觉模型相反,是对齐原版实现的重要细节。
后处理 post_process_depth_estimation(源码)内部完成三件事:
- 若启用了 FOV 且提供了
target_sizes,按公式focal_length = 0.5 * width / tan(0.5 * deg2rad(fov))估算焦距,并用depth * width / focal_length做尺度校正; - 把深度图双线性插值回
target_sizes; - 对深度取倒数还原真实深度(
1.0 / clamp(depth, min=1e-4, max=1e4)),因为网络内部预测的是逆深度。
返回的 dict 包含三个键:predicted_depth、field_of_view、focal_length。
视场角(FOV)预测:开关与两种开启方式
FOV 预测是 DepthPro 的附加能力,用于从单张图片估计相机水平视场角,进而辅助得到焦点长度、提升深度精度。文档指出:一个小型卷积头同时吞入深度估计网络产出的冻结特征(frozen features)与来自独立 ViT 图像编码器的任务特征,输出水平视场角。
从源码看,FOV 分支由三层组成(modeling_depth_pro.py):
DepthProFovEncoder:独立 ViT(默认 Dinov2)+ 线性投影到fusion_hidden_size // 2通道;- 一个 3×3 stride=2 卷积 + ReLU,处理深度分支传来的全局特征;
DepthProFovHead:按num_fov_head_layers逐层将通道减半并下采样,最后卷积出标量 FOV 值并flatten。
在 DepthProForDepthEstimation.forward 中,深度分支用于 FOV 的特征是 features[0].detach()(源码),即冻结梯度的全局特征,这与文档"frozen features"的描述一致。
DepthProConfig.use_fov_model 控制是否启用 FOV 预测,默认 False 以节省显存与计算。启用时会依据 fov_model_config(默认 Dinov2Model)实例化 FOV 编码器。需要强调的是:
- 预训练检查点
apple/DepthPro-hf本身带 FOV 编码器。若想省计算,可在加载时显式传use_fov_model=False:
from transformers import DepthProForDepthEstimation
model = DepthProForDepthEstimation.from_pretrained("apple/DepthPro-hf", use_fov_model=False, device_map="auto")
- 新建模型并启用 FOV,可在 config 中开启:
from transformers import DepthProConfig, DepthProForDepthEstimation
config = DepthProConfig(use_fov_model=True)
model = DepthProForDepthEstimation(config)
- 也可以在构造模型时直接传参,此时会覆盖 config 中的值:
from transformers import DepthProConfig, DepthProForDepthEstimation
config = DepthProConfig()
model = DepthProForDepthEstimation(config, use_fov_model=True)
当前推理态约束
需要注意:本仓库实现的 DepthProForDepthEstimation.forward 目前只支持推理。若向 forward 传入 labels(真实深度图用于计算损失),会直接抛出 NotImplementedError("Training is not implemented yet")(源码)。即当前版本不支持在 Transformers 内直接微调训练,仅提供加载预训练权重做零样本估计的能力。
用 SDPA 与半精度加速推理
DepthPro 的模型类声明了 _supports_sdpa = True(源码),因此可无缝使用 PyTorch 原生的 scaled dot-product attention(SDPA) 算子。SDPA 是 torch.nn.functional.scaled_dot_product_attention 提供的融合注意力实现,会根据输入与硬件自动选择最优内核。
在 torch>=2.1.1 且存在可用实现时,SDPA 默认开启;也可以在 from_pretrained() 里显式指定 attn_implementation="sdpa":
from transformers import DepthProForDepthEstimation
model = DepthProForDepthEstimation.from_pretrained(
"apple/DepthPro-hf", attn_implementation="sdpa", device_map="auto"
)
想获得最大加速,建议把模型加载为半精度(torch.float16 或 torch.bfloat16)。模型文档给出了一组本地基准示例(A100-40GB、PyTorch 2.3.0、Ubuntu 22.04、float32、google/vit-base-patch16-224),SDPA 相对 eager 模式在 batch size 1~8 时约有 1.17×~1.33× 的推理加速;不同模型、分辨率与硬件上的实际收益会有差异,DepthPro 这类高分辨率输入通常更能体现 SDPA 的显存与延迟优势。
扩展到其他子任务
模型文档与社区实践显示,DepthPro 不仅可用于深度估计:由于 patch 编码器能产出锐利、多尺度、含高频细节的特征,研究者已将其用于超分辨率与图像分割(模型文档 Resources 节 中列出的 depthpro-beyond-depth 代码即演示了这类用法)。因此可把 DepthProModel 当作通用特征提取主干,替换默认的深度头来适配新任务——配置项里 patch_model_config / image_model_config 通过 AutoModel API 加载,理论上也允许替换成其他 ViT 变体作主干。
测试与本地验证
仓库为 DepthPro 提供了配套测试,可作为理解与验证实现的参考:
- test_modeling_depth_pro.py:
DepthProModelTester以小尺寸(如image_size=64, patch_size=16)构造DepthProConfig做前向一致性检查,并通过ModelTesterMixin覆盖序列化、from_pretrained加载、梯度检查点等通用行为; - test_image_processing_depth_pro.py:覆盖
DepthProImageProcessor的预处理与post_process_depth_estimation后处理。
运行模型相关测试的通用方式(仓库根目录)为 python -m pytest tests/models/depth_pro/,慢速集成测试需联网加载 apple/DepthPro-hf 权重。
小结
DepthPro 把"多尺度 patch 编码 + 全局 image 编码 + DPT 式逐级融合"三条线索拧在一起,实现了零样本、带公制尺度、亚秒级的高分辨率单目深度估计,并附带单图 FOV/焦距估计能力。在你的 Transformers 应用中,记住三条实操要点即可顺畅上手:
- 用
DepthProImageProcessor(1536×1536、先归一化后缩放)完成预处理,用post_process_depth_estimation(..., target_sizes=...)还原分辨率并得到focal_length/field_of_view/predicted_depth; apple/DepthPro-hf自带 FOV 分支,若只关心深度可用use_fov_model=False加载以省算力;反之在 config 或构造参数里开启;- 优先
torch>=2.1.1+ 半精度 + SDPA 以获得最佳推理性能;当前实现仅支持推理,labels训练路径尚未开放。
想要继续深入,可在仓库中直接阅读 configuration_depth_pro.py、modeling_depth_pro.py、image_processing_depth_pro.py 与权重转换脚本 convert_depth_pro_weights_to_hf.py。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00