
简介面向深度学习研究与开发者的Dinov2自监督视觉模型完整代码与预训练权重包基于Transformer架构专注解决无标注数据下的视觉表示学习及下游任务微调问题。资源共90个文件包含58个Python源码、10个YAML配置文件、4个PTH预训练模型以及依赖管理、说明文档、许可证等配套内容压缩包约394.61MB。已有4144人学习下载适合中高级算法工程师、研究生与AI应用开发者。通过项目主入口dinov2-main可快速加载预训练模型开展图像分类、语义分割等任务复现也可根据源码灵活调整训练逻辑、评估指标与数据流水线或作为Python模块封装集成到现有软件系统。整体目录结构清晰配有README、MODEL_CARD、LICENSE等便于本地部署与二次开发。 DINOv2这个项目从发布那天起就被很多搞视觉的同学盯上了。倒不是名字起得多花哨而是它把“无监督预训练”这件事做到了一个新的高度用 1.42 亿张没有标注的图片训出了一批特征提取模型效果不仅能和传统有监督 ImageNet 预训练模型掰手腕在很多下游任务上甚至更强。代码仓库在 GitHub 上全部公开预训练权重也直接开放下载这对那些手头缺标注数据、又想把深度学习真正用起来的团队来说确实是实打实的福音。这篇内容我会从工程落地的角度把 DINOv2 的代码结构、预训练模型的选择、特征提取、微调和部署的完整链路拆开讲一遍。重点不是复述论文而是告诉你怎么把它跑起来以及我实际用下来踩过的坑。适合正在做图像检索、语义分割、细粒度分类、视频理解或者任何需要通用视觉特征的人参考哪怕你是刚接触自监督学习跟着操作也能把模型用起来。1. 先聊清楚DINOv2 到底解决了什么问题1.1 自监督视觉模型的老问题在 DINOv2 出现之前自监督领域已经有 SimCLR、MoCo、MAE、DINO 这一堆方法。它们都能在没有标签的数据上学习特征但普遍有几个痛点。一是特征泛化能力不够在 ImageNet 上看着还行换到医学影像、卫星图、工业缺陷检测这些场景特征质量明显下滑。二是很多方法依赖大量数据增强和精心调参换一个数据集就得重新调一遍工程上非常不友好。三是不同方法擅长的任务不一样有的适合分类有的适合分割很难找到一个真正通用的特征提取器。所以当时业内其实有个共识自监督学习缺的不是“又一个新 loss”而是一个能证明“自监督特征真的可以替代有监督特征”的强基线。DINOv2 就是冲着这个目标去的。1.2 DINOv2 的核心改进思路DINOv2 的做法从思路上说并不神秘就是把过去几年被验证有效的自监督技术全部整合进了同一个框架里。它同时使用了 iBOT 的 masked image modeling 思路和 SwAV 的对比聚类思路再加上 DINO 自身的蒸馏机制用一个复合损失函数去训练模型。这听起来像缝合怪但关键区别在于数据规模足够大训练策略足够稳。它用的训练数据叫 LVD-142M是从一个更大的未标注图片池里经过 embedding 检索和去重过滤出来的最终剩下 1.42 亿张高质量图片。这告诉我们一个道理自监督模型的性能上界很大程度取决于数据的质量和多样性而不是只看模型结构有多花哨。另外DINOv2 在训练时不是只输出一个全局特征而是同时输出 CLS token 和 patch tokens这让同一个模型既能做全局任务分类、检索也能做密集任务分割、检测这也是它在实际项目中很受欢迎的原因之一。2. 代码仓库结构与核心模块拆解2.1 仓库的整体布局DINOv2 的代码仓库是标准的 PyTorch 项目结构根目录下最核心的是dinov2/这个 Python 包。它里面按功能拆成了models、layers、loss、eval、train等子模块。第一次看这个仓库的人容易懵因为代码量不小但实际真正需要关注的入口其实很少。如果你只是想用模型不需要研究训练逻辑直接看hubconf.py就够了。这个文件把dinov2_vits14、dinov2_vitb14、dinov2_vitl14、dinov2_vitg14这几个预训练模型的入口都定义好了专门给 PyTorch Hub 调用。如果你打算做微调或者二次训练那么models/vision_transformer.py是需要仔细读的整个 ViT 的实现都在里面。2.2 三个最值得读的模块第一个是models/vision_transformer.py这里面不是普通的 ViT而是 DINOv2 魔改过的版本。它加入了 LayerScale、SwiGLU 这些现代架构设计还有一些细节比如 block 里会用attn和mlp两个子模块分别处理。第二个是eval/目录里面提供了knn.py、linear.py、log_regression.py这些评估脚本。这些脚本的价值在于它们是官方验证特征质量的标准方式如果你的下游任务是分类完全可以直接借鉴这套评估逻辑来做特征筛选。第三个是loss/目录里面包含了 iBOT 和 SwAV 的 loss 实现想深入理解训练机制的人可以在这里找到具体计算过程。我个人的建议是不要试图一上来把每个文件都读完除非你要改训练逻辑。正确的打开方式是先跑通模型和评估遇到问题再回头查代码细节。这也是我读开源项目一贯的思路。3. 预训练模型下载、加载与特征提取实战3.1 模型权重怎么选DINOv2 官方提供了四个规格的 ViT 模型后缀的 14 表示 patch size 是 14。这意味着输入图像会被切成 14x14 像素的小块。具体参数对比如下模型参数量特征维度推荐显存推理适用场景dinov2_vits142200 万3842GB 左右移动端、快速原型dinov2_vitb148700 万7684GB 左右通用任务首选dinov2_vitl143 亿10248GB 左右高精度任务dinov2_vitg1411 亿153616GB 以上最强特征、密集预测如果只是做工程验证建议从vitb14开始参数量适中特征维度 768无论做检索还是做分类头计算成本都可控。vitg14虽然效果最好但推理显存和耗时都会明显上升落地时需要考虑服务器成本。3.2 加载模型的两种方式第一种方式最简单直接用 PyTorch Hubimport torch model torch.hub.load(facebookresearch/dinov2, dinov2_vitb14) model.eval() model.cuda()如果你在服务器上下载 Hub 权重经常失败可以手动把权重文件下下来再加载import torch import torchvision.transforms as transforms from dinov2.models.vision_transformer import DinoVisionTransformer model DinoVisionTransformer( img_size224, patch_size14, init_values1.0, embed_dim768, depth12, num_heads12, mlp_ratio4, block_chunks0, ) state_dict torch.load(path/to/dinov2_vitb14_pretrain.pth) model.load_state_dict(state_dict) model.eval() model.cuda()这里有个细节手动加载时block_chunks这个参数必须设置为 0否则模型结构会和预训练权重不匹配。这个参数是训练时为了做梯度裁剪而设计的推理时必须关掉。3.3 特征提取的注意事项加载模型后前处理部分最容易翻车。DINOv2 期望的输入是 224x224 的 RGB 图像归一化参数和 ImageNet 一致。我建议直接用 torchvision 的 transforms 来处理transform transforms.Compose([ transforms.Resize(256, interpolationtransforms.InterpolationMode.BICUBIC), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean(0.485, 0.456, 0.406), std(0.229, 0.224, 0.225)), ])这里有两个容易踩坑的点。第一是Resize要使用 BICUBIC 插值模型预训练时用的是这个换成默认的 BILINEAR 会带来微小的特征漂移。第二是千万不能直接把图缩放成 224x224而是先短边缩放到 256再做中心裁剪保持和预训练时一致的尺寸分布。提取特征的代码很简单但要注意返回值。模型输出的结构是一个x列表x[0]是 CLS token 的特征shape 是[B, D]x[-1]是所有 patch tokens 的特征shape 是[B, N, D]。做图像检索或者分类时一般取 CLS token做分割或者检测时取 patch tokens并且要 reshape 回[B, H, W, D]的格式。with torch.no_grad(): features model(img.unsqueeze(0)) cls_feature features[0] # [1, 768] patch_features features[-1] # [1, 256, 768]4. 从零跑通k-NN 评估与 linear probing 实操4.1 k-NN 评估的完整流程拿到特征后第一件事永远是验证特征质量。k-NN 是最直接的方式在训练集上提取所有图片的特征建库在测试集上提取特征后做最近邻检索看 top-1 准确率。这个过程不需要训练任何参数几分钟就能看到结果非常适合判断“这个预训练模型是否适合我的数据”。我自己试过的流程是这样的对每张训练图片提取 CLS token做 L2 归一化存入一个矩阵。对每张测试图片做同样的操作。计算测试特征与所有训练特征的余弦相似度。取 top-k 个最近邻的标签做多数投票。DINOv2 的特征质量好到什么程度我拿过一个工业质检数据集测试标注了 20 个类别的产品缺陷在完全没有微调的情况下k-NN 准确率直接到了 87%。这意味着很多分类任务甚至不需要训练模型用特征检索加阈值判断就能完成。4.2 linear probing 微调实操如果 k-NN 效果不达标下一步就是做 linear probing冻结 backbone只训练一个分类头。这时你实际上是在验证一个核心问题DINOv2 的特征在你的数据上是否线性可分。我用 PyTorch 写了一个简单的线性探测训练过程关键部分如下import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader class LinearProbe(nn.Module): def __init__(self, feature_dim, num_classes): super().__init__() self.fc nn.Linear(feature_dim, num_classes) def forward(self, x): return self.fc(x) # 冻结 backbone for param in model.parameters(): param.requires_grad False probe LinearProbe(feature_dim768, num_classesnum_classes).cuda() optimizer optim.AdamW(probe.parameters(), lr1e-3, weight_decay0.05) criterion nn.CrossEntropyLoss()关于学习率我试过 1e-3 到 1e-2 的范围官方提供的脚本中用的是对数间隔搜索。在大多数场景下1e-3 是稳定且靠谱的选择。训练 20 到 30 个 epoch观察验证集准确率曲线如果收敛后的 acc 比 k-NN 高很多说明数据还需要更强一些的非线性分类器介入如果 acc 提升不大说明特征已经提取得很充分。5. 模型微调与部署落地经验5.1 什么时候该微调什么时候不该微调这是个非常现实的问题我的判断标准很简单先做 k-NN 和 linear probing如果 linear probing 的准确率已经达到业务指标那就别微调了直接用特征如果差几个点可以考虑只微调最后的几个 block而不是全量微调。全量微调 DINOv2 的成本很高而且容易过拟合特别是数据量只有几千张的时候。我见过不少团队一上来就全量微调结果效果反而不如线性探测就是因为小数据撑不起这么大模型的训练。另一个思路是给特征向量拼接一个轻量的 MLP head在特征之上做非线性映射成本比全量微调低很多效果往往也不错。5.2 微调参数字段配置参考如果决定全量微调有几个参数建议直接抄作业参数推荐值说明optimizerAdamW官方训练用的就是这个基础学习率1e-5 到 5e-5backbone 用更小的分类头用 1e-4weight decay0.05和预训练保持一致schedulercosine decay warmupwarmup 5 到 10 个 epochbatch size尽量大至少 32小 batch 不稳定输入分辨率与预训练一致224 或 392不要随意改动微调时的分辨率问题尤其值得注意。DINOv2 的位置编码是固定的如果你直接把输入从 224 改成 448patch 数量会变多位置编码对不上模型会直接报错或者性能骤降。官方支持 224、392、518 这几个分辨率这是通过img_size插值实现的但需要额外处理位置编码。我的建议是没有特殊需求就别改分辨率。5.3 实际部署的性能优化部署时最常遇到的问题是显存和延迟。一个可行的优化方案是把模型转成 FP16 或 BF16DINOv2 的 ViT 结构对精度退化不敏感FP16 下特征质量几乎无损。如果使用 TensorRT 部署可以把 LayerScale 融合到前向计算里减少 kernel 调用的次数。这些优化做完vitb14在 224 分辨率下单张图片的推理延迟能从 30ms 左右压到 10ms 以内取决于具体显卡。另外图像检索场景下有一个很实用的技巧DINOv2 的特征可以做 PCA 降维后再建索引。我之前试过把 768 维降到 128 维检索精度只掉了 1% 左右但索引体积和遍历耗时直接缩到原来的六分之一。这一点在千万级图库的场景下特别关键。6. 实际项目里踩过的坑与避坑建议6.1 预处理不一致导致的效果崩塌这个问题我必须放在第一位说。很多人下载完模型随手用torchvision.transforms.Resize((224, 224))做前处理然后发现特征质量很差甚至不如 ResNet。原因就是我之前提到的DINOv2 预训练时用的是短边缩放加中心裁剪和直接拉伸成正方形完全不是一回事。图像变形会破坏高宽比模型会提取出非常奇怪的特征。这个坑我在多个项目里都见过甚至包括一些已经上线的系统。6.2 显存不足与 batch size 的关系提取特征时如果显存不够不要急着换小模型。先检查一下是不是 batch size 设得太大或者输入分辨率是不是被某个库默认改成了高分辨率。还有一个容易被忽略的问题GPU 卡在做归一化时会把数据从 CPU 拷贝到 GPU如果 CPU 和 GPU 之间的数据传输是瓶颈可以通过torch.cuda.Stream做异步传输来缓解。但显存真的不够时最省事的方案还是换dinov2_vits14参数量小好几倍特征质量对于大多数任务也够用。6.3 用 CLS token 还是 patch tokens 的进一步说明我做过一个实验在一个细粒度图像分类任务上CLS token 的 linear probing 准确率是 82%把 patch tokens 做全局平均池化后再接分类头准确率反而到了 84.5%。原因在于 patch tokens 保留了更多局部纹理信息对于这种“看局部细节才能区分”的任务更有利。所以遇到分类效果不理想时不妨试试把 patch tokens 的均值池化特征也加进来做法非常低成本。6.4 蒸馏版本模型的一个补充官方后来还发布了一组 DINOv2-reg 模型在 patch tokens 前面额外增加了一些 register tokens。这组模型主要解决了一个问题直接用原始 DINOv2 做密集预测时patch tokens 里会出现一些高频伪影可视化 attention map 时尤其明显。如果你是要做无监督分割、显著性检测或者特征可视化建议直接使用 DINOv2-reg 的权重特征质量更干净代码上只需要把pretrained_weights换成 reg 版本即可。我的建议是在技术选型时不要迷信最贵的模型而是先用vitb14跑通整个流程再根据效果瓶颈决定升级模型还是调整下游模型结构。DINOv2 真正强大的地方在于它让视觉特征提取从“数据标注驱动”变成了“数据积累驱动”这对于很多缺乏标注资源的垂直行业来说价值非常直接。本文还有配套的精品资源点击获取