30分钟跑通 DINOv3 零样本语义分割:dinotxt 部署实战教程
【免费下载链接】dinov3Reference PyTorch implementation and models for DINOv3项目地址: https://gitcode.com/GitHub_Trending/di/dinov3
DINOv3 零样本语义分割实战教程,主题是 dinotxt 部署:传入类别名,直接输出像素级 mask,不训练、不用标注数据。下文按最短路径跑通、整图与滑窗推理怎么选、提示模板、mIoU 评估怎么读的顺序展开。
🖼️ 先看效果:零样本分割输出什么
先说清楚零样本分割的输入输出,建立预期:
- 不训练:没有标注数据,没有要微调的 head,模型参数不动。
- 输入:一张图 + 一组类别名,例如
("road", "car", "sky")。 - 输出:每个类别一张得分图,沿类别维取 argmax 就是逐像素 mask。
官方仓库自带一份可直接运行的推理 notebook:notebooks/dinotxt_segmentation_inference.ipynb,里面写好了 Cityscapes 19 类和 ADE20K 150 类的类别定义、两种推理模式与指标统计。本文所有代码都取自这份 notebook,照着交叉阅读即可。
🧰 环境搭建与最短路径跑通
第一步,clone 仓库并用 conda.yaml 建环境:
git clone https://gitcode.com/GitHub_Trending/di/dinov3 && cd dinov3 micromamba env create -f conda.yaml micromamba activate dinov3conda.yaml 固定了 python 3.11、torch/torchmetrics,以及 dino.txt 依赖的 ftfy 和 regex。验证方式:新环境里执行python -c "import torch",打印版本号即成功。
两点提醒:
- dinotxt 入口会同时加载 ViT-L/16 主干权重,权重需先按 README 的 Pretrained models 一节申请下载;已有本地权重时用
backbone_weights参数传入。 - 图像要按 ImageNet 均值方差归一化,且 H、W 拉伸到 16(patch 大小)的整数倍,这两步在 notebook 的
encode_image和ShortSideResize里。
第二步,一个脚本完成加载、文本编码、图像编码和取 mask:
model, tokenizer = dinov3_vitl16_dinotxt_tet1280d20h24l() model.to("cuda").eval() tokenizer = tokenizer.tokenize feats = model.encode_text(tokenizer(["a photo of a road.", "a photo of a car."]).to("cuda")) text_feats = F.normalize(feats[:, feats.shape[1]//2:], dim=-1) # [2, D] h, w = img.shape[-2]//16, img.shape[-1]//16 grid = F.normalize(model.visual_model.get_class_and_patch_tokens(img[None])[2].reshape(h, w, -1), dim=-1) mask = torch.einsum("cd,hwd->chw", text_feats, grid).argmax(0)这段做的事:dinov3_vitl16_dinotxt_tet1280d20h24l()返回模型和分词器;encode_text的输出一半对应 CLS token(丢弃)一半对应 patch 侧,取后半并归一化即得文本特征;get_class_and_patch_tokens的第三个返回值是骨干的 patch token,reshape 成网格就是图像侧特征;einsum算余弦相似度后逐点 argmax。mask形状是[h, w],即每个 16×16 块一个类别判断,双线性插值到原图尺寸就是最终 mask;如果全图只判出一类,先检查归一化和 16 倍数拉伸。
原理一句话版:mask 是怎么来的
整个机制只有一条:dinotxt 用图文对比的方式训练,视觉端给每个 16×16 patch 输出一个向量,文本端给每个类别名输出一个向量,两者落在同一特征空间,余弦相似度就是"这块像这个类别"的分数,分割 = 全图像素逐个 argmax。
由此有两个直接推论:
- 不需要额外分类头,mask 质量完全由骨干的密集特征决定。
- 类别列表可以运行时任意增删,不用动模型;换场景只改那组字符串。
⚡ 整图与滑窗推理怎么选
两种模式对应两种分辨率场景:
- 整图(
predict_whole):整张图一次过模型,输出低分辨率得分图再插值放大。快、稳,短边 512 以内的图选它。 - 滑窗(
predict_slide):按side×side的窗口、stride步长切片,每块走一遍整图流程,再按重叠加权拼回原图分辨率。细节更好,短边 1024 以上的街景、遥感图选它。
notebook 的参考参数是side=384, stride=192(50% 重叠)。显存紧张时优先调小side,而不是压缩类别数。跑滑窗前先用短边 512 的 resize 把图缩小,最终 mask 分辨率与输入图一致。调用本身是一行:predict_slide(model, img, text_feats, side=384, stride=192),返回与输入同尺寸的逐像素得分,argmax 即 mask。
提示模板怎么写与组合
为什么模板有用:单句 "a photo of a car" 只覆盖一种说法,类别表示容易被措辞带偏。notebook 用 80 条模板变体(模糊照片、渲染图、特写、涂鸦、黑白照等)分别编码后取平均,类别表示更稳、覆盖面更全。
组合方式:
- 默认全量使用,notebook 报数字就是这个配置。
- 时间紧时挑 8~10 条,覆盖"普通照片 / 低画质 / 渲染"三类即可。
- 类别名保持名词,不要塞颜色、尺寸修饰词。
- 平均之后必须重新归一化,否则余弦相似度退化成模长比较。
📊 mIoU 怎么看
评估只看一个指标:mIoU,即各类别 IoU(交并比)的宏平均,是语义分割的标准口径。notebook 用 torchmetrics 的MulticlassJaccardIndex(num_classes, average="macro", ignore_index=255)统计,255 是忽略标签。
看数三点:
- 总分定"能不能用",分类别看"哪里不行"。
- 小目标类别(如交通标志)通常拖分,总分高不代表安全。
- 对比不同配置的数字前,先固定 resize、side、stride,否则不可比。
关键文件索引
- dinov3/eval/text/dinotxt_model.py:组装 visual_model 与 text_model 两个塔,
encode_text与 patch 提取入口。 - dinov3/eval/text/vision_tower.py:视觉端定义,骨干加两个附加块。
- dinov3/hub/dinotxt.py:模型加载入口,
weights与backbone_weights参数在这里。
能力边界:街景、室内等常见场景零样本直接可用;长尾领域与极小目标上,训练过的模型仍更强。 下一步:先复现 notebook 的 Cityscapes 数字,再换自己的类别列表;需要训练侧看dinov3/eval/text/train_dinotxt.py。
【免费下载链接】dinov3Reference PyTorch implementation and models for DINOv3项目地址: https://gitcode.com/GitHub_Trending/di/dinov3
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考