首页
/ Transformers DPT 模型完全指南:基于 Vision Transformer 的稠密预测(单目深度估计与语义分割)

Transformers DPT 模型完全指南:基于 Vision Transformer 的稠密预测(单目深度估计与语义分割)

2026-09-07 17:27:46作者:庞队千Virginia

DPT(Dense Prediction Transformer)是 🤗 Transformers 仓库中用于稠密预测任务的经典架构,它将 Vision Transformer 用作骨干网络而非卷积网络,从而完成单目深度估计与语义分割。本文以 DPT 官方模型文档 为核心骨架,结合 modeling_dpt.pyconfiguration_dpt.py 等源码,完整梳理其架构脉络、配置项、图像预处理方式与三个模型类的实战用法。读完本文,你将能够理解 DPT 的“多阶段特征重组 + 逐级融合上采样”解码机制,掌握如何用任意 Transformer 骨干(如 DINOv2)搭建 DPT 框架,以及如何直接跑通深度估计与语义分割的推理流程。

概览:什么是 DPT

DPT 模型由 René Ranftl、Alexey Bochkovskiy 和 Vladlen Koltun 在论文 Vision Transformers for Dense Prediction 中提出。根据官方模型文档,该模型论文于 2021-03-24 发表在 Hugging Face Papers,并于 2022-03-28 由社区贡献者 nielsr 合入 Transformers 仓库。

其核心思想非常简洁:Vision Transformer(ViT) 取代卷积网络作为稠密预测任务的骨干网络,服务于语义分割与深度估计。论文摘要指出:

我们提出了 dense vision transformers——一种在稠密预测任务中以视觉 Transformer 取代卷积网络作为骨干的架构。我们收集 Transformer 不同 stage 输出的 token,将它们重组成不同分辨率的类图像表示,再用一个卷积解码器逐级融合,最终产生全分辨率预测。Transformer 骨干在恒定且相对较高的分辨率下处理表示,且每一 stage 都具有全局感受野。这些特性使 dense vision transformer 相比全卷积网络能给出更细粒度、更全局一致的预测。实验显示该架构在稠密预测任务上带来了显著提升——在单目深度估计上与 SOTA 全卷积网络相比相对性能最高提升 28%;应用于语义分割时,在 ADE20K 上以 49.02% mIoU 刷新 SOTA。我们进一步验证了该架构可微调到 NYUv2、KITTI、Pascal Context 等较小数据集上并同样取得新 SOTA。

从实现层面看,当前仓库中的 DPT 与 DPT-Hybrid 均由 Intel 实验室与 OpenMMLab 的 mmsegmentation 实现启发而来,这一点在 modeling_dpt.py 的文件头注释中有明确说明。模型类同时声明了对 FlashAttention、SDPA、FlexAttention 与统一注意力后端的支持(见 DPTPreTrainedModel_supports_sdpa = True_supports_flash_attn = True_supports_flex_attn = True,源码见 modeling_dpt.py)。

整体架构:从特征序列到稠密预测的流水线

DPT 的前向流程并不是简单地把 ViT 输出接一个上采样层。它的核心创新在于 neck(颈部)模块,该模块位于骨干与输出头之间,由两段组成:DPTReassembleStage(特征重组)+ DPTFeatureFusionStage(多尺度特征融合)。模型文档中对应的 DPTModelDPTForDepthEstimationDPTForSemanticSegmentation 三类模型在 modeling_dpt.py 中依次实现,整体数据流为:

  1. 骨干编码:将图片切分为 patch(默认 16×16),送入 ViT 或任意层次化骨干,取第 2、5、8、11 层(对应 backbone_out_indices=(2, 5, 8, 11))的中间隐状态作为多尺度特征;
  2. 特征重组(Reassemble):把每个中间层的 (batch, seq_len, hidden) 序列表示恢复成 (batch, channels, height, width) 的类图像特征图,并利用 [CLS] readout token 补充全局信息,再按不同 factor 做上/下采样到多分辨率(源码见 DPTReassembleStage);
  3. 特征融合(Fusion):从最深、最粗的特征开始,逐层加入更浅、更细的特征并双线性上采样 ×2,最终得到融合的稠密特征(源码见 DPTFeatureFusionLayer);
  4. 任务头:将最后一级特征送入深度估计头或语义分割头,产生逐像素输出。

DPTNeck 的完整接线可以在 modeling_dpt.py 中看到:先对每个中间特征做一次 3×3 卷积把通道统一到 fusion_hidden_size(默认 256),再交由 DPTFeatureFusionStage 融合。需要注意的是,当骨干是 Swinv2 这种本身已是层次化 CNN 风格的骨干时(backbone_config.model_type == "swinv2"),会跳过 reassemble 阶段,因为其 feature map 已经是 (batch, channels, height, width) 形式。

Reassemble 中的 readout 处理:三种策略

ViT 每个 stage 的输出都带一个 [CLS] token,而语义分割/深度估计需要逐空间位置的信息。readout_type 参数提供了三种把 [CLS] 信息注入其他 token 的策略(配置校验见 configuration_dpt.py,逻辑实现见 modeling_dpt.py):

  • "ignore":直接丢弃 [CLS] token,仅用其余 patch token;
  • "add":把 [CLS] 表示加到其余所有 token 上(广播相加),使每个位置都带上全局信息;
  • "project"(默认):先把 [CLS] token 沿空间维度拼接到每个 token 上,维度翻倍为 2 * hidden_size,再用一个线性层投影回原维度 hidden_size,并施加 hidden_act(默认 GELU)非线性。

注意约束:DPT-Hybrid 模式强制要求 readout_type == "project",否则在配置初始化阶段直接抛 ValueError(见 configuration_dpt.py)。

输出头设计

深度估计头DPTDepthEstimationHead)由 3 个卷积层组成:首层把 fusion_hidden_size(256)减半后立即做 scale_factor=2 的双线性上采样,再经 32 通道卷积与 ReLU,最后 1×1 卷积压缩到单通道输出并再次 ReLU,最后 squeeze 掉通道维。若 add_projection=True,还会在头部前先加一层 3×3 的投影卷积。头部默认使用 head_in_index=-1 指定的最后一级融合特征。

语义分割头DPTSemanticSegmentationHead)则是:3×3 卷积 → BatchNorm → ReLU → Dropout(比率由 semantic_classifier_dropout 控制,默认 0.1)→ 1×1 卷积映射到 num_labels → 双线性上采样 ×2。此外,训练时可开启 辅助头DPTAuxiliaryHead,默认启用),它只接收融合特征的最深一级(hidden_states[-1]),产生一个低分辨率的中间预测用于加深监督。

DPTConfig 配置项详解

DPTConfig 继承自 PreTrainedConfigmodel_type = "dpt",并声明了子配置 backbone_config(见 configuration_dpt.py)。其关键参数、默认值与含义如下表(依据源码类字段与 docstring,源码见 configuration_dpt.py):

参数 默认值 含义
hidden_size 768 内置 ViT 骨干的隐层维度
num_hidden_layers 12 内置 ViT 骨干层数
num_attention_heads 12 注意力头数
intermediate_size 3072 ViT MLP 中间维度
hidden_act "gelu" MLP 激活函数
hidden_dropout_prob / attention_probs_dropout_prob 0.0 隐层/注意力 dropout
image_size 384 内置 ViT 期望输入尺寸(DPT-large 风格)
patch_size 16 patch 尺寸
num_channels 3 输入通道数
is_hybrid False 是否使用 Hybrid 模式(配合卷积式 BiT 骨干加载 DPT-Hybrid 权重)
qkv_bias True 注意力 QKV 是否带偏置
backbone_out_indices (2, 5, 8, 11) 从骨干取哪些中间层特征;使用 AutoBackbone 时会被置空并由骨干 out_features 决定(见 configuration_dpt.py
readout_type "project" [CLS] readout 注入策略,枚举 "ignore" / "add" / "project"
reassemble_factors (4, 2, 1, 0.5) 四个重组层的上/下采样倍数
neck_hidden_sizes (96, 192, 384, 768) 各骨干特征图要投影到的通道数
fusion_hidden_size 256 融合前统一缩放的通道数
head_in_index -1 输出头取哪一级融合特征(-1 即最后一层)
use_batch_norm_in_fusion_residual False 融合残差块是否使用 BatchNorm
use_bias_in_fusion_residual None(语义上默认 True 融合残差块是否使用偏置
add_projection False 深度估计头前是否加投影卷积层
use_auxiliary_head True 训练语义分割时是否启用辅助头
auxiliary_loss_weight 0.4 辅助头交叉熵损失的权重系数
semantic_loss_ignore_index 255 语义分割交叉熵损失忽略的标签值
semantic_classifier_dropout 0.1 语义分类头 dropout
backbone_featmap_shape (1, 1024, 24, 24) 仅 Hybrid 模式使用,描述 BiT 骨干特征图形状
neck_ignore_stages (0, 1) 仅 Hybrid 模式使用,前两路 readout 特征会被 Identity 直接透传(对应官方实现中前两层不重组的做法)
backbone_config None 外挂骨干的 PreTrainedConfig 或配置字典
pooler_output_size None(自动取 hidden_size pooler 输出维度
pooler_act "tanh" pooler 激活函数

两个重要的自动行为(在 __post_init__ 中完成,见 configuration_dpt.py):

  • is_hybrid=True 时,若未提供 backbone_config,会自动按 BiT 骨干补全一组默认配置(global_padding="same"layer_type="bottleneck"depths=[3, 4, 9]out_features=["stage1","stage2","stage3"]);
  • 只有 is_hybrid=Truebackbone_featmap_shapeneck_ignore_stages 才生效(否则前者为 None、后者为空列表);
  • readout_type 若非法,配置初始化即报错,便于尽早暴露笔误。

使用 AutoBackbone 自由搭配骨干:以 DINOv2 为例

模型文档重点强调:DPT 框架兼容 AutoBackbone 机制,因此可以复用库中大量现成视觉骨干(如 VitDetBackboneDinov2Backbone),而不是被绑死在内置 ViT 上。官方示例给出了用 DINOv2 做骨干、随机初始化一个深度估计模型的完整写法:

from transformers import Dinov2Config, DPTConfig, DPTForDepthEstimation

# 以 Transformer 骨干(如 DINOv2)初始化
# 此时需设置 reshape_hidden_states=False,使骨干输出
# 形状为 (batch_size, num_channels, height, width) 的特征图
backbone_config = Dinov2Config.from_pretrained(
    "facebook/dinov2-base",
    out_features=["stage1", "stage2", "stage3", "stage4"],
    reshape_hidden_states=False,
)

config = DPTConfig(backbone_config=backbone_config)
model = DPTForDepthEstimation(config=config)

这段代码背后依赖两个源码机制:

  1. load_backbone:当 is_hybrid=False 且提供了 backbone_config 时,DPTForDepthEstimation 会通过 backbone_utils.load_backbone 加载外部骨干,而不是走内置 DPTModel(见 modeling_dpt.py);
  2. 动态 patch 尺寸推导:由于 ViT 序列被 reshape 成方形特征图时要求边长可开方,使用非方形输入时会依据 pixel_values 的实际高宽与 backbone_config.patch_size 计算出 patch_heightpatch_width,再传给重组层做 reshape(见 modeling_dpt.py)。

在仓库测试中,test_modeling_dpt_auto_backbone.py 覆盖了这一组合路径;而 DPT-Hybrid(BiT 骨干)与 Swinv2 骨干的接入逻辑分别由 convert_dpt_hybrid_to_pytorch.pyconvert_dpt_swinv2_to_hf.py 等转换脚本佐证——DPT 已经从“特定 ViT 变体”演化为“可插拔骨干的稠密预测框架”。

图像处理器:DPTImageProcessor 与 PIL 后端

DPT 的图像预处理有几个容易踩坑的细节,官方通过自定义的 resize/pad 逻辑处理。仓库中同时存在两个实现文件:

预处理默认值与常规图像分类略有差异(依据 PIL 后端类属性,见 image_processing_pil_dpt.py):

  • size = {"height": 384, "width": 384},默认缩放到 384×384;
  • 重采样方式为 BICUBIC(双三次);
  • 像素值以 1/255 rescale,并使用 ImageNet 标准均值/方差归一化;
  • 新增两个 DPT 专有开关:ensure_multiple_of(默认 1,保证缩放后尺寸是某数的整数倍)与 keep_aspect_ratio(默认 False);两者叠加时先等比缩放到尽量大、再把宽高约束为 multiple 的整数倍(算法见 get_resize_output_image_size);
  • do_pad(默认 False)配合 pad_image 做居中 padding,把图像补到 size_divisor 的整数倍(如原版 DPT 处理宽高需被 14/32 整除的场景),pad 逻辑见 image_processing_pil_dpt.py

后处理方法同样与模型输出配套:

  • post_process_depth_estimation(outputs, target_sizes):接收 DepthEstimatorOutput,把 predicted_depth 双线性插值回 target_sizes(原图高宽)并返回字典列表;
  • post_process_semantic_segmentation(outputs, target_sizes):接收分割 logits,插值回原图并返回 SegmentationMask(可选用 return_segmentation_scores=True 保留分数),其与另一文件中的对应实现细节见 image_processing_pil_dpt.py 类定义部分。

此外分割场景还支持 do_reduce_labels=True:把标签整体减 1、0 换为 255(背景占位),适配 ADE20k 这类“0 表示背景但背景不在类别表内”的数据集(见 image_processing_pil_dpt.py)。

三个模型类与实战用法

DPTModel:仅骨干编码器

DPTModelmodeling_dpt.py)返回 BaseModelOutputWithPoolingAndIntermediateActivations:它会输出包含中间激活的特征,供上层 DPT 解码流水线取用。它可选择是否附加 DPTViTPooler(取首 token 过线性层 + pooler_act 激活),构造函数中通过 add_pooling_layer 控制;深度估计/分割子类都会以 add_pooling_layer=False 实例化它(见 modeling_dpt.pymodeling_dpt.py)。配置类的内置示例即展示了这一用法(见 configuration_dpt.py):

from transformers import DPTModel, DPTConfig

# 初始化一个 dpt-large 风格配置
configuration = DPTConfig()
# 由配置初始化模型
model = DPTModel(configuration)

DPTForDepthEstimation:单目深度估计

该模型由一个骨干编码(内置 ViT 或外挂骨干)、DPTNeck 与 3 层卷积深度头组成。官方 docstring 给出的端到端推理示例(见 modeling_dpt.py)如下:

from transformers import AutoImageProcessor, DPTForDepthEstimation
from PIL import Image

image = Image.open("your_image.jpg")  # 换成你自己的图片

image_processor = AutoImageProcessor.from_pretrained("Intel/dpt-large")
model = DPTForDepthEstimation.from_pretrained("Intel/dpt-large")

# 为模型准备输入
inputs = image_processor(images=image, return_tensors="pt")

with torch.no_grad():
    outputs = model(**inputs)

# 插值回原始分辨率
post_processed_output = image_processor.post_process_depth_estimation(
    outputs,
    target_sizes=[(image.height, image.width)],
)

# 可视化预测结果
predicted_depth = post_processed_output[0]["predicted_depth"]
depth = predicted_depth * 255 / predicted_depth.max()
depth = depth.detach().cpu().numpy()
depth = Image.fromarray(depth.astype("uint8"))

注意两点:

  • 该模型的 forward 支持传入 labels,但官方当前尚未实现深度估计训练——一旦传 labels 会直接抛出 NotImplementedError("Training is not implemented yet")(见 modeling_dpt.py),因此 Intel/dpt-large 这类预训练权重主要用于推理;
  • 该模型返回 DepthEstimatorOutput(含 predicted_depth、可选 hidden_statesattentions),默认内部会强制开启 hidden states 输出、按 backbone_out_indices 裁剪后喂给 neck(见 modeling_dpt.py)。若用户未主动要求,最终输出不会携带完整 hidden states,避免内存浪费。

DPTForSemanticSegmentation:语义分割

模型结构为 DPTModel + DPTNeck + 分割头 + 可选辅助头(见 modeling_dpt.py)。官方 docstring 示例(modeling_dpt.py):

from transformers import AutoImageProcessor, DPTForSemanticSegmentation
from PIL import Image

image = Image.open("your_image.jpg")  # 换成你自己的图片

image_processor = AutoImageProcessor.from_pretrained("Intel/dpt-large-ade")
model = DPTForSemanticSegmentation.from_pretrained("Intel/dpt-large-ade")

inputs = image_processor(images=image, return_tensors="pt")
outputs = model(**inputs)
logits = outputs.logits

与前向流程相关的实现事实包括:

  • 返回 SemanticSegmenterOutput,主输出为原始分辨率下的 logits(1/2 输入分辨率附近);
  • 训练时(传入 labels)会先把主头与辅助头的 logits 各自插值到 labels 的空间尺寸,再用 CrossEntropyLoss(ignore_index=semantic_loss_ignore_index) 分别计算损失,最终 loss = 主损失 + auxiliary_loss_weight × 辅助损失(见 modeling_dpt.py);
  • num_labels == 1 却传入 labels,会抛出“标签数需大于 1”的 ValueError(见 modeling_dpt.py)。

任务指南与进一步探索

模型文档将 DPT 定位为两个下游任务指南的核心模型实现,对应任务文档位于仓库 语义分割任务指南单目深度估计任务指南,其中涵盖了完整的训练脚本、评估指标与更多调参建议,建议在正式使用前通读。

若想深入源码细节,可以按下面的路径继续阅读当前仓库:

总而言之,DPT 给“Transformer 骨干 + 稠密预测”提供了清晰的模块化范式:通用 ViT 编码多尺度特征 → reassemble 恢复空间结构并注入全局 readout → 卷积解码器逐级融合 → 轻量任务头出预测。在当前仓库中,这一框架既可用于 Intel/dpt-large 等经典权重做零样本推理,也能通过 AutoBackbone 无缝替换成 DINOv2、SwinV2、ViTDet 等新骨干进行定制训练,是理解 Vision Transformer 落地稠密视觉任务的一条理想学习路径。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
899
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525