资讯动态

从 PyTorch 到 GGUF:depth-anything.cpp 模型转换脚本逐行拆解

发布时间:2026/10/16 5:42:22 来源:尧图企业网站定制
【免费下载链接】depth-anything.cppA from-scratch C17/ggml port of Depth Anything 2 and 3 (ByteDance)项目地址https://gitcode.com/gh_mirrors/de/depth-anything.cpp点击查看免费下载depth-anything.cpp 是 ByteDance Depth Anything 2/3 单目深度估计模型的 C17/ggml 从零移植项目。它用一组 Python 转换脚本把 PyTorch 官方权重转换成单个自包含的 GGUF 文件——推理时不需要 Python、PyTorch 或 CUDA只需一个原生 CLI。本文逐行拆解scripts/目录下的模型转换脚本带你看懂PyTorch 转 GGUF的完整原理。转换产物能做什么给一张普通照片模型输出稠密深度图、逐像素置信度、相机内外参甚至 3D 点云为什么要把 PyTorch 权重转换成 GGUF 格式直接用 PyTorch 跑 Depth Anything要拖上一整套 Python PyTorch CUDA 依赖栈。而 depth-anything.cpp 的思路是把模型烤进一个 GGUF 文件里——所有维度、超参数、预处理常数全部作为 KV 元数据写进文件头部权重以 f32 张量紧随其后。C 加载器读文件即可重建整个网络零外部配置。这正是模型转换的全部意义一次转换换来更快的推理、更小的文件q4_k 量化后仅 99 MB和零 Python 依赖的部署。转换前准备依赖安装与模型权重下载转换以及数值一致性校验需要 Python 环境推理不需要。在仓库根目录执行pip install -r requirements.txtrequirements.txt 里只有torch、numpy、gguf、huggingface_hub、safetensors、einops、pillow等少量依赖CPU 版 PyTorch 即可。然后下载官方 DA3-BASE 权重到本地python scripts/download_model.py --repo depth-anything/DA3-BASE --out models/DA3-BASEdownload_model.py 只有十几行核心就是调用snapshot_download把模型仓库快照拉到models/目录是四个转换脚本里最简单的一个。逐行拆解核心转换器 convert_da3_to_gguf.py主转换脚本 convert_da3_to_gguf.py 把 DA3 的DepthAnything3Netbackbone DualDPT 深度头 相机位姿解码器 cam_dec 可选 3D 高斯头 gs_head写进一个 GGUF。整个流程分三段。第一段读取架构参数写入 KV 元数据入口main()很简单#L223-L233def main(): ap argparse.ArgumentParser() ap.add_argument(--model, defaultmodels/DA3-BASE) ap.add_argument(--output, defaultmodels/depth-anything-base-f32.gguf) a ap.parse_args() _, net load_model(a.model) # 用 PyTorch 重建网络 write_da3_gguf(net, a.output, ...)load_model来自 da3_reference.py负责按官方定义实例化网络并加载权重。随后write_da3_gguf先从网络对象本身读出架构参数#L14-L37bb net.backbone.pretrained embed_dim bb.embed_dim # 隐藏维度 depth bb.n_blocks # ViT 层数 num_heads bb.num_heads head_dim embed_dim // num_heads mlp0 bb.blocks[0].mlp if hasattr(mlp0, w12): # giant 用 SwiGLUw12/w3 ffn_type swiglu mlp_hidden mlp0.w3.in_features else: # 其余型号用经典 MLPfc1/fc2 ffn_type mlp mlp_hidden mlp0.fc1.out_features pos_rows bb.pos_embed.shape[1] - 1 M int(round(pos_rows ** 0.5)) assert M * M pos_rows # 位置编码必须是 M*M 的方阵注意这段代码的两个设计点FFN 类型是探测出来的giant 型号用 SwiGLU 激活mlp_hidden取w3.in_features门控后维度 4096其他型号取fc1.out_features。同一份代码因此能通吃整个 DA3 家族。位置编码网格尺寸M用断言校验pos_embed去掉 CLS 行后必须是完美平方数否则直接报错退出。拿到参数后写入 GGUF 的 KV 元数据#L39-L66w gguf.GGUFWriter(output, K.ARCH) w.add_string(K.KV[arch], K.ARCH) # depthanything3 w.add_uint32(K.KV[vit.embed_dim], int(embed_dim)) w.add_uint32(K.KV[vit.depth], int(depth)) w.add_uint32(K.KV[vit.num_heads], int(num_heads)) w.add_uint32(K.KV[vit.ffn_type] and ...) # mlp 或 swiglu w.add_array(K.KV[img.mean], [0.485, 0.456, 0.406]) # 预处理常数 w.add_array(K.KV[img.std], [0.229, 0.224, 0.225]) w.add_string(K.KV[img.resize_mode], upper_bound) w.add_uint32(K.KV[img.resize_target], 504)紧接着 #L68-L91 还会写入 DualDPT 深度头head.features、head.out_channels等和相机位姿解码器cam.dim_in的配置。这一步之后GGUF 已经自我描述——加载器无需任何外部配置文件。第二段重命名权重并逐张量写入接下来是权重搬运。backbone 的循环#L93-L113written, skipped 0, [] for name, t in net.backbone.named_parameters(): canon name.split(pretrained.)[-1] if pretrained. in name else name g K.rename_backbone(canon) # PyTorch 名 - GGUF 名 if g is None: skipped.append(name) continue arr np.ascontiguousarray( t.detach().cpu().to(torch.float32).numpy(), dtypenp.float32) w.add_tensor(g, arr) written 1 if skipped: raise SystemExit( ferror: {len(skipped)} backbone param(s) unmapped (rename_backbone gap))这里体现的是失败要响亮fail loudly原则任何一张量映射不上脚本立刻报错退出而不是静默丢权重——静默丢权重会让模型能加载但算错远比报错难排查。head、cam_dec、gs_head 各有一段同构的循环#L115-L209分别调用K.rename_head、K.rename_cam、K.rename_gs。其中 aux 射线头是可选的默认关闭以保证发布的 GGUF 字节级一致加--with-aux才写入供 ray-pose 推理使用。giant 型号才有的gs_head3D 高斯头则在net.gs_head is not None时才处理。第三段落盘w.write_header_to_file() # GGUF 魔数 版本 w.write_kv_data_to_file() # 全部 KV 元数据 w.write_tensors_to_file() # 全部 f32 张量 w.close()#L211-L214三步写完输出类似wrote ...: backbone_tensors207 head_tensors62 cam_tensors10方便人工核对张量数量。键名映射的唯一事实源gguf_keys.py重命名规则集中在 gguf_keys.py文件开头注释说得很清楚C 加载器和 Python 转换器都从这里取键名两边永远不会漂移。架构名ARCH depthanything3#L6KV 字典短键 → 完整键字符串如vit.embed_dim → depthanything3.vit.embed_dim#L9-L97覆盖 backbone、预处理、深度头、位姿、3D 高斯乃至 nested 双分支m_vit.*/m_head.*rename_backbone#L99-L129PyTorch 参数名 → GGUF 张量名def rename_backbone(name): if n pos_embed: return vit.pos_embed m re.match(r^blocks\.(\d)\.(.)$, n) if m: table { attn.qkv.weight: attn_qkv.weight, mlp.fc1.weight: mlp_fc1.weight, mlp.w12.weight: mlp_w12.weight, # SwiGLU (giant) ... } if rest in table: return fvit.blk.{i}.{table[rest]} return None # None 未映射调用方必须报错rename_head#L143-L176则用正则把 DualDPT 头里scratch.refinenet2.resConfUnit1.conv3.weight这类长名字压成head.scratch.rn2.rc1.c3.weight的紧凑形式。C 侧的键名表 include/da_gguf_keys.h 由 gen_gguf_keys_header.py 自动生成#L13-L20文件头标注AUTO-GENERATED from scripts/gguf_keys.py - do not edit——改键名只需改一个 Python 文件。DA2、Mono 与 Nested 模型转换脚本一览除 DA3 主力型号外scripts/下还有三个同构变体脚本套路完全一致读架构 → 写 KV → 改名搬权重差异都在元数据细节脚本目标模型关键差异convert_da2_to_gguf.pyDepth Anything V2 全系arch 写depthanything2作判别值#L52DA2 是素 DINOv2无 RoPE/registerrope_start等一律写-1metric 版通过--max-depth室内 20 / 室外 80切换Sigmoid × max_depth输出convert_mono_to_gguf.pyDA3MONO-LARGE单头 DPToutput_dim1 并行天空头不写 cam_dec/gs_headconvert_nested_to_gguf.pyDA3NESTED-GIANT-LARGE输出两个GGUFanyview 分支ViT-g复用write_da3_gguf metric 分支ViT-L权重写到m_vit.*/m_head.*前缀DA2 脚本里还有一个值得学习的细节DINOv2 的mask_token只在掩码预训练时用推理时是死权重脚本用本地集合_DA2_SKIP_BACKBONE {mask_token}#L28跳过它而不往公共的rename_backbone里加规则——避免影响 DA3 路径。# DA2 转换示例 python scripts/convert_da2_to_gguf.py --encoder vitl --ckpt models/depth_anything_v2_vitl.pth \ --output models/depth-anything2-large-f32.gguf --name Depth-Anything-V2-Large转换后验证与量化round-trip 测试和 da3-cli quantize转换不能写完就算。test_convert_roundtrip.py 用GGUFReader把产物读回来做断言#L19-L63KV 里必须有depthanything3.vit.embed_dim、vit.depth等张量名必须包含vit.patch_embed.weight、head.scratch.out2b.weight等关键成员张量总数精确断言DA3-BASE backbone 207 深度头 62 cam_dec 10一个都不能多、不能少#L57-L63还断言 M2 阶段不允许_aux张量泄漏giant 变体则断言 SwiGLU 张量mlp_w12存在、经典mlp_fc*不存在确认 f32 无误后用 CLI 做量化类型f16 | q8_0 | q6_k | q5_k | q4_kbuild/examples/cli/da3-cli quantize models/depth-anything-base-f32.gguf \ models/depth-anything-base-q4_k.gguf q4_k量化产物清单和每个文件的说明见 models/MODEL_CARD.md。转换收益体积、速度与内存以 DA3-BASE504×336 生产路径16 线程 CPU为例量化收益一目了然推理延迟与内存同样占优——q8_0 档推理速度达到 PyTorch 的1.31 倍峰值内存只有其一半模型加载快约 6.7 倍更关键的是所有这些量化档位相对 PyTorch 参考实现逐组件数值一致相关系数 1.0完整验证记录在 docs/VERIFICATION.md。小结关键文件索引环节文件权重下载scripts/download_model.pyDA3 转换核心scripts/convert_da3_to_gguf.pyDA2 / Mono / Nested 转换scripts/convert_da2_to_gguf.py · scripts/convert_mono_to_gguf.py · scripts/convert_nested_to_gguf.py键名唯一事实源scripts/gguf_keys.py → include/da_gguf_keys.h转换回归测试scripts/test_convert_roundtrip.py产物模型卡models/MODEL_CARD.md一句话总结这套转换脚本的设计哲学配置即元数据、映射即白名单、缺失即报错。架构参数从活着的网络对象里探测权重搬运全靠白名单重命名任何漏网的张量都让脚本当场失败——这三条保证了 GGUF 既是自包含的也是不丢权重的。看懂了 convert_da3_to_gguf.py 这三段你就掌握了把任何 ViTDPT 结构模型转成自包含 GGUF 的通用模板。赞分享【免费下载链接】depth-anything.cppA from-scratch C17/ggml port of Depth Anything 2 and 3 (ByteDance)项目地址https://gitcode.com/gh_mirrors/de/depth-anything.cpp点击查看免费下载相关推荐从PyTorch到ONNXpytorch-image-models模型转换全攻略从PyTorch到ONNXpytorch image models模型转换全攻略 你是否还在为模型部署时的框架兼容性发愁是否想让训练好的PyTorch模型在人工智能计算机视觉深度学习RuoYi-Vue-Pro 企业级工作流审批系统架构解析与实施指南RuoYi Vue Pro 企业级工作流审批系统架构解析与实施指南 摘要 RuoYi Vue Pro 是基于 Spring Boot MyBatis Plu后端前端低代码认证鉴权codebase-memory-mcp增量索引与Delta管线pipeline_delta与增量更新机制完全指南codebase memory mcp增量索引与Delta管线pipeline_delta与增量更新机制完全指南 codebase memory mcp 是一AI 应用MCP 服务知识图谱创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑