查看 Markdown

DINOv2

DINOv2 是 Meta AI 训练的自监督 vision transformer,不用标注就能产出通用的图像特征。LibreYOLO 把它的 DINOv2-with-Registers 骨干封装成三个任务:语义分割、分类和整图嵌入。

任务
semantic, classify, embed
尺寸
n, s, m, l at 518 px
安装
pip install libreyolo
支持层级
已支持,自 v 起。起支撑作用的可训练家族:在 CI 里保持绿色,功能视情况落地。
上游
DINOv2,由 Meta AI (FAIR) 发布,采用 Apache-2.0 许可。论文源码
许可
代码采用 MIT,权重采用 Apache-2.0。商用

安装

LibreDINOv2 只在装了 transformers 之后才会注册,也就是 RF-DETR 给它的 DINOv2 骨干所需要的那个可选依赖,所以它用的是同一个 extra。

bash
pip install "libreyolo[rfdetr]"

预测

LibreYOLO 没有发布 LibreDINOv2 检查点(checkpoint)。不要去加载文件,直接构造这个 封装:model_path=None(默认值)会在首次使用时从 Hugging Face 下载 Meta 采用 Apache-2.0 许可的 facebook/dinov2-with-registers-small 骨干。task= 选择在它之上 跑什么。

语义分割
from libreyolo import SAMPLE_IMAGEfrom libreyolo.models.dinov2.model import LibreDINOv2 # 这个家族没有 LibreYOLO 托管的检查点:这里会从 Meta 的 Hugging Face# 组织下载采用 Apache-2.0 许可的 DINOv2-with-Registers-small 骨干。# 稠密 head 在你训练它之前一直是随机初始化的(见下面的训练一节)model = LibreDINOv2(size="s", task="semantic", nb_classes=19)result = model(SAMPLE_IMAGE) mask = result.semantic_maskprint(mask.data.shape, mask.classes)
分类
from libreyolo import SAMPLE_IMAGEfrom libreyolo.models.dinov2.model import LibreDINOv2 # nb_classes= 是你数据集的类别数;线性 head 在你训练它之前一直是# 随机初始化的model = LibreDINOv2(size="s", task="classify", nb_classes=10)result = model(SAMPLE_IMAGE) print(result.probs.top1, result.probs.top1conf)
嵌入
from libreyolo import SAMPLE_IMAGEfrom libreyolo.models.dinov2.model import LibreDINOv2 # 绕过所有任务 head:光靠骨干就够了,所以不用微调就能用model = LibreDINOv2(size="s", task="embed")result = model(SAMPLE_IMAGE) print(result.embeddings.data.shape)   # (1, D),已做 L2 归一化
批量嵌入
from libreyolo.models.dinov2.model import LibreDINOv2 model = LibreDINOv2(size="s", task="embed") # 便捷封装:内部跑一次 predict(),把每一行堆叠成一个 (N, D) 张量features = model.embed(["a.jpg", "b.jpg", "c.jpg"])print(features.shape)

task="semantic"task="classify" 会在骨干之上加一个稠密 head 或线性 head; 这个 head 是随机初始化的,只有在你训练它之后才有用(见训练)。 task="embed" 跳过所有 head,把骨干最后归一化的 CLS token 作为整图的一行返回到 result.embeddings 里,所以它完全不需要训练。result.boxes 永远是 None:这三个 任务都不产生逐实例的检测结果。数据源、流式处理和结果处理见预测

变体

size 选的是叠在骨干之上的、RF-DETR 风格的投影层宽度,而不是骨干本身:每种尺寸共用 同一个 DINOv2-S(small)编码器。语义分割跑在 DINOv2 原生的方形 patch 网格上;分类和 嵌入跑在训练线性探针时用的那个更小的分类分辨率上。

训练

task="semantic"task="classify" 都能训练;task="embed" 没有依赖类别的 head 要拟合,你在它上面调用 train() 会抛出 NotImplementedError

语义分割
from libreyolo.models.dinov2.model import LibreDINOv2 model = LibreDINOv2(size="s", task="semantic", nb_classes=19)model.train(data="my-dataset.yaml", epochs=100, batch_size=4, lr=1e-4)
分类
from libreyolo.models.dinov2.model import LibreDINOv2 model = LibreDINOv2(size="s", task="classify", nb_classes=10)model.train(data="my-dataset.yaml", epochs=100, batch_size=4, lr=1e-4)
多卡训练
from libreyolo.models.dinov2.model import LibreDINOv2 model = LibreDINOv2(size="s", task="semantic", nb_classes=19)model.train(    data="my-dataset.yaml", epochs=100, batch_size=4, lr=1e-4,    device="0,1",)

这里的主要关键字参数是 batch_sizelr,不是大多数其他家族用的 batchlr0batchlr0 仍然接受,并会映射到前者上,但两个一起传会报冲突错误。 output_dir=(默认 "runs/train")取代 project=/name=,成为安放一次运行结果的 主要方式,不过直接传 project=/name= 也仍然有效。数据集、数据增强、多卡训练和 日志器见训练

验证

val() 返回一个由 metrics/ 开头的键组成的字典:task="semantic" 是 mIoU 和像素 精度,task="classify" 是 top-1 和 top-5 精度。task="embed" 没有可供打分的真值 (ground truth),你在它上面调用 val() 会抛出 NotImplementedError

语义分割
from libreyolo.models.dinov2.model import LibreDINOv2 model = LibreDINOv2(size="s", task="semantic", nb_classes=19)metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mIoU"])print(metrics["metrics/pixel_accuracy"])
分类
from libreyolo.models.dinov2.model import LibreDINOv2 model = LibreDINOv2(size="s", task="classify", nb_classes=10)metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/accuracy_top1"])print(metrics["metrics/accuracy_top5"])

导出

任务ONNXTorchScriptExecuTorchTensorRTOpenVINOPaddleMNNRKNNncnnTFLiteCoreMLCore AI
semanticsemantic to ONNX:支持semantic to TorchScript:支持semantic to ExecuTorch:支持semantic to TensorRT:支持semantic to OpenVINO:支持semantic to Paddle:不支持semantic to MNN:不支持semantic to RKNN:不支持semantic to ncnn:不支持semantic to TFLite:不支持semantic to CoreML:不支持semantic to Core AI:不支持
classifyclassify to ONNX:支持classify to TorchScript:支持classify to ExecuTorch:支持classify to TensorRT:支持classify to OpenVINO:支持classify to Paddle:不支持classify to MNN:不支持classify to RKNN:不支持classify to ncnn:不支持classify to TFLite:不支持classify to CoreML:不支持classify to Core AI:支持
embedembed to ONNX:支持embed to TorchScript:支持embed to ExecuTorch:支持embed to TensorRT:支持embed to OpenVINO:支持embed to Paddle:不支持embed to MNN:不支持embed to RKNN:不支持embed to ncnn:不支持embed to TFLite:支持embed to CoreML:不支持embed to Core AI:不支持

每个任务支持的格式子集不同,如上所示。导出的产物按文件后缀通过 LibreYOLO() 加载 回来,所以一个 .onnx.engine 文件的表现和检查点一样,返回同样的 Results导出列出了每种格式接受的参数。

语义分割
from libreyolo.models.dinov2.model import LibreDINOv2 model = LibreDINOv2(size="s", task="semantic", nb_classes=19)model.export(format="onnx")
分类
from libreyolo.models.dinov2.model import LibreDINOv2 model = LibreDINOv2(size="s", task="classify", nb_classes=10)model.export(format="onnx")
嵌入
from libreyolo.models.dinov2.model import LibreDINOv2 model = LibreDINOv2(size="s", task="embed")model.export(format="tflite")
使用导出的文件
from libreyolo import LibreYOLO, SAMPLE_IMAGE # 工厂按文件后缀分发,所以导出的产物加载方式和任何检查点一样,返回的# 也是同一个 Results 对象。导出时文件名由任务决定,这里是# LibreDINOv2s-sem.onnxmodel = LibreYOLO("LibreDINOv2s-sem.onnx")result = model(SAMPLE_IMAGE)

许可证

请检查你所下载的具体权重在 Hugging Face 仓库中的许可。LibreYOLO 组织里的每个检查点都附有许可,同一家族内也不一定相同。该仓库是权威来源;以下摘要说明本页上次验证时适用的情况。

这里只说明涉及的许可证,不构成法律意见。如果答案对商用很重要,请自行阅读许可证并咨询法律顾问。

原始工作
DINOv2, Meta AI (FAIR)
上游许可
Apache-2.0
LibreYOLO 代码
MIT
权重
采用 Apache-2.0 许可,由作者分发。LibreYOLO 不托管或镜像这些权重。
解读
Apache-2.0 is a permissive license, so these weights can be used in commercial and closed-source products. It asks you to keep its license text and attribution notices with any copy of the weights you redistribute, and it grants a patent license. LibreYOLO does not host or republish a DINOv2 checkpoint of its own: LibreDINOv2 downloads the pretrained backbone directly from Meta's facebook/dinov2-with-registers-small repository on Hugging Face the first time it runs, unmodified. The semantic and classification heads start at random initialization until you train them, since LibreYOLO does not publish a trained head for this family.

上面「权重」那一行写的是适用的许可证,Apache-2.0,但这个家族其实没有任何东西以 LibreYOLO 的 Hugging Face 组织名义重新发布:LibreYOLO 自己并不托管 LibreDINOv2 检查 点。LibreDINOv2(model_path=None) 下载的是 Meta 自己的 facebook/dinov2-with-registers-small 仓库,原封不动。

引用

@misc{oquab2023dinov2,
  title={DINOv2: Learning Robust Visual Features without Supervision},
  author={Oquab, Maxime and Darcet, Timothée and Moutakanni, Theo and Vo, Huy V. and Szafraniec, Marc and Khalidov, Vasil and Fernandez, Pierre and Haziza, Daniel and Massa, Francisco and El-Nouby, Alaaeldin and Howes, Russell and Huang, Po-Yao and Xu, Hu and Sharma, Vasu and Li, Shang-Wen and Galuba, Wojciech and Rabbat, Mike and Assran, Mido and Ballas, Nicolas and Synnaeve, Gabriel and Misra, Ishan and Jegou, Herve and Mairal, Julien and Labatut, Patrick and Joulin, Armand and Bojanowski, Piotr},
  journal={arXiv:2304.07193},
  year={2023}
}

复制自作者在 github.com/facebookresearch/dinov2#citing-dinov2 上提供的引用块。

已针对 LibreYOLO v1.5.0 验证。本页的支持表、检查点和基准测试数据由已发布的库和权重生成,并非手工编写。