首页
/ GLPN 单目深度估计模型完全指南:从 Mix-Transformer 编码器到轻量解码器(Transformers 仓库实战)

GLPN 单目深度估计模型完全指南:从 Mix-Transformer 编码器到轻量解码器(Transformers 仓库实战)

2026-09-07 23:57:12作者:姚月梅Lane

GLPN(Global-Local Path Networks,全局-局部路径网络)是 2022 年提出的单目深度估计(Monocular Depth Estimation)模型,它把 SegFormer 的分层 Mix-Transformer 编码器与一个轻量级解码器组合在一起,从单张 RGB 图像直接回归出稠密深度图。本文基于当前仓库中 docs/source/en/model_doc/glpn.md 的核心内容,结合 src/transformers/models/glpn/ 下的配置、建模与图像预处理源码,系统讲解 GLPN 的架构原理、GLPNConfig 全部超参数、AutoImageProcessor 预处理细节,以及端到端的推理与可视化代码。读完本文,你将能在 Transformers 生态内加载 vinvino02/glpn-kittivinvino02/glpn-nyu 等 GLPN 权重完成真实场景的深度估计,并能读懂该模型各模块在仓库中的落点,方便自行微调或二次开发。

GLPN 概览:为深度估计而生

GLPN 由 Doyeon Kim、Woonghyun Ga、Pyungwhan Ahn、Donggyu Joo、Sehwan Chun、Junmo Kim 在论文 Global-Local Path Networks for Monocular Depth Estimation with Vertical CutDepth(论文链接对应 2201.07436)中提出,作者于 2022-01-19 在 HF Papers 发布论文,并于 2022-03-22 将其代码贡献进 Transformers(贡献者 nielsr,社区实现可参考仓库根目录模型说明中给出的原始 GLPDepth 实现线索)。

论文摘要的核心观点可以概括为三点:

  1. 部署分层 Transformer 编码器来捕获并传递全局上下文;
  2. 设计轻量却强大的解码器,在考虑局部连接性的同时生成深度图——通过在多个尺度的局部特征与全局解码流之间构建连接路径(selective feature fusion module,选择性特征融合模块),网络能把全局与局部表征整合起来,恢复细节;
  3. 改进深度专用的数据增强方法(利用深度估计中的重要观测来增强模型)。

实验表明该解码器相比此前提出的解码器,在显著降低计算复杂度的同时取得了更好的性能,并在极具挑战性的 NYU Depth V2 数据集上达到了当时的领先水平,同时展现出更好的泛化与鲁棒性。注意,仓库中并未附带任何性能基准数字表,本文不臆造具体指标——上述结论仅转述原论文摘要文字本身。

需要说明的是,文档开头有一个官方 Tip:由于这是较新引入的模型,API 尚未被广泛测试,可能存在少量 bug 或未来会发生轻微破坏性变更。因此在生产使用前请核对当前仓库版本的实际 API 形态。

架构剖析:SegFormer 风格分层编码器 + 轻量解码器

modeling_glpn.py 的类结构可以清晰还原整条前向链路。源码中大量模块带有 "Copied from transformers.models.segformer..." 注释,印证了 GLPN 编码器直接继承自 SegFormer 的分层设计。

分层 Mix-Transformer 编码器(GLPNEncoder)

编码器由 GLPNEncoder 组装,其结构是标准的四阶段金字塔:

  • 每个阶段前先经过 GLPNOverlapPatchEmbeddings 重叠 patch 嵌入(kernel_size 对应 patch_sizes、stride 对应 strides,padding 取 patch_size // 2),再送入若干 GLPNLayer
  • GLPNLayer 内部是 Pre-LN 结构:先 LayerNorm 再做 GLPNAttention(注意力内部使用 efficient self-attention / sequence reduction,即把高分辨率阶段的 key/value 用 sr_ratios 步长的卷积压缩后参与注意力),随后是 Mix-FFN 前馈与残差连接(残差上可施加随机深度 GlpnDropPath);
  • GLPNMixFFN 内含 GLPNDepthWiseConv 深度可分离卷积,这正是 Mix-Transformer 用卷积"隐式编码位置信息"、从而无需显式位置编码的关键;
  • 每个阶段结束后经 LayerNorm 并将序列重新 reshape 回 (batch, channels, height, width) 的空间形式,输出到下一阶段,形成多尺度特征金字塔 hidden_sizes = (32, 64, 160, 256)(默认小配置)或 (64, 128, 320, 512)(SegFormer-B4 规模,见下文转换脚本)。

注意 GLPNModel 只返回最后一个阶段(即最深层、分辨率最低)的特征作为 last_hidden_state;而解码器需要全部中间特征,因此 GLPNForDepthEstimation.forward 内部会强制以 output_hidden_states=True 调用编码器。

全局-局部解码器与选择性特征融合

GLPNDecoder 是本文标题"Global-Local Path Networks"的落点,代码结构如下:

  • config.hidden_sizes 反转得到 (256, 160, 64, 32),每一层构造一个 GLPNDecoderStage(in_channel, out_channel),其中 out_channel = decoder_hidden_size(默认 64);
  • 每一 stage 先用 1x1 卷积把不同通道数统一,再调用 GLPNSelectiveFeatureFusion上一 stage 上采样后的全局流当前层的局部特征按注意力权重融合,最后用双线性 nn.Upsample(scale_factor=2) 上采样;
  • 最深的第一个 stage(源码 self.stages[0].fusion = None)不做融合,仅做投影与上采样;
  • 末级 final_upsample 再上采样一次,恢复空间分辨率。

选择性特征融合模块(GLPNSelectiveFeatureFusion)正是论文解码器的核心:把局部特征与全局特征沿通道 concat 后,经 3 层 3x3 卷积(Conv2d → BN → ReLU 逐步降维)再通过 Sigmoid 生成双通道空间注意力图,用 local * attn[:,0] + global * attn[:,1] 逐元素加权相加,让网络自适应决定每个空间位置更信任局部细节还是全局语义。

深度估计头与训练损失

GLPNDepthEstimationHead 由两层 3x3 卷积(中间带 ReLU)构成,把 64 通道特征压到 1 通道,然后做关键一步:

predicted_depth = torch.sigmoid(hidden_states) * self.config.max_depth
predicted_depth = predicted_depth.squeeze(dim=1)  # 输出形状 (batch, height, width)

即输出值被约束在 [0, max_depth]max_depth 默认 10,单位为米量级的相对深度尺度)。模型也内置了训练损失函数 SiLogLoss(Scale-invariant Logarithmic Loss,源自 Eigen et al. 2014),只对 target > 0 的像素计算 sqrt(mean(d^2) - λ·mean(d)^2)(默认 lambd=0.5),因此在 GLPNForDepthEstimation 中传入真实深度图 labels 即可直接训练。

顶层模型与前向输出

  • GLPNModel(config):裸编码器(分层 Transformer),输出 BaseModelOutput,可用于提取多尺度视觉特征;
  • GLPNForDepthEstimation(config)glpn(编码器) + decoder + head 三层组合,返回 DepthEstimatorOutput,其中 loss(提供 labels 时)、predicted_depthhidden_statesattentions 一应俱全。

两个模型类的 __all__ 导出与 modeling_auto.py 中的映射均可在 src/transformers/models/glpn/modeling_glpn.pyauto_mappings.py"glpn" -> GLPNModel / GLPNForDepthEstimation)中找到证据。源码注释中类结构上标明它们由 KAIST 与 HuggingFace 团队维护,仓库归属清晰。

GLPNConfig:全部超参数详解

GLPNConfig 继承自 PreTrainedConfigmodel_type = "glpn",默认配置为 vinvino02/glpn-kitti 风格(见 configuration_glpn.py 顶部的 @auto_docstring(checkpoint="vinvino02/glpn-kitti"))。下面把所有字段、默认值与语义整理如下(均可被 GLPNConfig(...) 覆盖):

配置字段 默认值 含义
num_encoder_blocks 4 Mix-Transformer 编码器的阶段(stage)数
depths [2, 2, 2, 2] 每个阶段内 Transformer block(层)数量
hidden_sizes (32, 64, 160, 256) 每阶段输出的通道数(金字塔宽度);源码类属性中可见
sr_ratios [8, 4, 2, 1] 各阶段 attention 的序列缩减(sequence reduction)比
patch_sizes [7, 3, 3, 3] 每个阶段 patch 嵌入的卷积核大小
strides [4, 2, 2, 2] 每个阶段 patch 嵌入的卷积步长
num_attention_heads [1, 2, 5, 8] 各阶段每层注意力头数
mlp_ratios [4, 4, 4, 4] Mix-FFN 隐层相对于输入维度的比例
num_channels 3 输入图像通道数
hidden_act "gelu" FFN 激活函数
hidden_dropout_prob / attention_probs_dropout_prob 0.0 隐藏层 / 注意力 dropout
initializer_range 0.02 权重初始化标准差
drop_path_rate 0.1 随机深度(DropPath)上限,实际按层线性插值
layer_norm_eps 1e-6 LayerNorm epsilon
decoder_hidden_size 64 解码器各 stage 的统一通道维度
max_depth 10 深度头 Sigmoid 输出的放大上界(米)
head_in_index -1 取解码器输出列表的哪个元素送入 head(默认取最后一个)

值得注意的底层联动(可在 GLPNEncoder 源码看到):dpr = linspace(0, drop_path_rate, sum(depths)) 会为所有阶段的每一层分配逐步递增的随机深度概率;每个阶段输入通道是上一个阶段的 hidden_sizes[i-1](首个阶段用 num_channels)。

标准用法(与配置 docstring 一致):

>>> from transformers import GLPNConfig, GLPNModel

>>> # 以 vinvino02/glpn-kitti 风格初始化
>>> configuration = GLPNConfig()
>>> model = GLPNModel(configuration)          # 随机初始化
>>> configuration = model.config               # 取回配置

图像处理器:size_divisor 动态缩放与后处理

GLPN 使用的图像处理器有两个实现:

  • GLPNImageProcessor:Torchvision 后端(torch 张量流水线);
  • GLPNImageProcessorPil:PIL 后端(numpy 流水线)。

两者在 auto_mappings.py 中通过 AutoImageProcessor.from_pretrained 按 "torchvision"/"pil" 自动路由。它们的默认流水线一致:do_resize=True(BILINEAR 重采样)、do_rescale=Truerescale_factor = 1/255)、归一化由 checkpoint 的 preprocessor_config.json 决定。

GLPN 与一般视觉模型最不同的点在于 resize不把图像缩放到固定 size,而是把高、宽向下取整到 size_divisor(默认 32)的整数倍new_h = h // 32 * 32)。这一设计是为了配合分层编码器,使 4 级 [4,2,2,2] 总步长 32 的下采样得到整数空间维度,避免特征图错位。因此文档模型页与 docstring 都把 do_resize/size 的校验逻辑特殊处理(见 _validate_preprocess_kwargs 中 pop 掉 do_resize)。

此外还有 post_process_depth_estimation(outputs, target_sizes) 后处理接口:当提供 target_sizes=[(h, w)] 时,用 F.interpolate(..., mode="bicubic", align_corners=False) 把模型输出(通常为原图缩放到 32 倍数后的预测)插值回原始分辨率;要求 target_sizes 数量与 batch 相等。输出是一个 dict 列表,每项含 predicted_depth

实战:用 GLPNForDepthEstimation 做单目深度估计

快速推理与可视化

以下是模型 docstring 与源码自带的完整可用示例(数据加载用 httpx + BytesIO,避免额外依赖 requests/datasets),配合上述图像处理器即可零基础跑通推理:

>>> from transformers import AutoImageProcessor, GLPNForDepthEstimation
>>> import torch
>>> import numpy as np
>>> from PIL import Image
>>> import httpx
>>> from io import BytesIO

>>> # 1. 读取一张示例图片(COCO 验证集图片)
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
>>> with httpx.stream("GET", url) as response:
...     image = Image.open(BytesIO(response.read()))

>>> # 2. 加载处理器与模型
>>> image_processor = AutoImageProcessor.from_pretrained("vinvino02/glpn-kitti")
>>> model = GLPNForDepthEstimation.from_pretrained("vinvino02/glpn-kitti")

>>> # 3. 预处理:自动完成 size_divisor 缩放 + 归一化
>>> inputs = image_processor(images=image, return_tensors="pt")

>>> # 4. 推理
>>> with torch.no_grad():
...     outputs = model(**inputs)          # DepthEstimatorOutput

>>> # 5. 插值回原图尺寸
>>> post_processed_output = image_processor.post_process_depth_estimation(
...     outputs,
...     target_sizes=[(image.height, image.width)],
... )

>>> # 6. 归一化到 0~255 后可视化深度图
>>> 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"))

关键点:模型输入张量名是 pixel_valuesmain_input_name = "pixel_values"),predicted_depth 的原始形状为 (batch, H', W')H', W' 是向下取 32 倍数后的分辨率),后处理会自动回插到 (H, W)

用 pipeline 一行调用

除手动加载外,仓库在 src/transformers/pipelines/init.py 中已导出 DepthEstimationPipelinetransformers.pipelines.depth_estimation)。在安装 transformers 与 PyTorch 的前提下,可参考以下等价写法:

>>> from transformers import pipeline
>>> depth_estimator = pipeline(task="depth-estimation", model="vinvino02/glpn-kitti")
>>> result = depth_estimator(image)   # 返回包含深度预测的结果

提示:具体可用的 task/model 组合以当前仓库版本为准;小批量图像尺寸一致性对 batched 推理有要求,跨尺寸输入建议走 AutoImageProcessor 的分组路径。

训练/微调与 loss

如需在自有数据上微调,把真实深度图作为 labels 传入 GLPNForDepthEstimation 即可自动计算 SiLogLoss

>>> outputs = model(pixel_values=..., labels=depth_map)  # depth_map 形状 (batch, H, W)
>>> loss = outputs.loss

损失对深度对数域的方差建模天然具备尺度不变性,适用于以米为单位的 KITTI / NYUv2 数据。

仓库内配套资源

  • 模型文档页docs/source/en/model_doc/glpn.md,其中把 GLPN 定位为 SegFormer(见 SegFormer 文档)的后继,并链向 单目深度估计任务指南(原文档的 ../tasks/monocular_depth_estimation 局部链接在此已按仓库根路径还原)。
  • 权重转换脚本convert_glpn_to_pytorch.py 展示了如何把原始 GLPDepth 的 state_dict 改名为 HF 结构。脚本内可看到官方 checkpoint 的骨架即为 SegFormer-B4 规模:GLPNConfig(hidden_sizes=[64, 128, 320, 512], decoder_hidden_size=64, depths=[3, 8, 27, 3]),并以 expected_shape = torch.Size([1, 480, 640])torch.allclose 数值切片(nyu/kitti 各有独立期望值)做端到端一致性校验——这从侧面说明 vinvino02/glpn-kittivinvino02/glpn-nyu 两个官方权重在 480x640 输入下可用。
  • 测试用例tests/models/glpn/test_modeling_glpn.py 覆盖 GLPNModel/GLPNForDepthEstimation 的 forward 与 hidden_states/attentions 输出,tests/models/glpn/test_image_processing_glpn.py 覆盖 size_divisor 缩放与 post_process_depth_estimation,可作为复现与回归验证的入口。

小结

GLPN 在 Transformers 仓库中的实现可概括为一句话:SegFormer 分层 Mix-Transformer 负责全局语义,带选择性特征融合的轻量解码器负责逐级融合局部细节,Sigmoid×max_depth 的深度头输出稠密深度图。本文覆盖了从 GLPNConfig 全部超参数、图像处理器的 32 整除缩放策略,到端到端推理、后处理与 SiLogLoss 微调的完整链路。对单目深度估计任务感兴趣的读者,可继续阅读本文引用的 单目深度估计任务指南,并结合 GLPN 建模源码 逐行对照论文中的全局-局部路径设计。

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

项目优选

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