拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

DINOv3 7B实战:从Hugging Face加载到分割检测全流程

DINOv3 7B实战:从Hugging Face加载到分割检测全流程

刚把DINOv3的7B权重拉下来跑通分割和检测的时候,说实话我是有点恍惚的。DINOv2出来那会儿,大家还在为3亿参数的ViT-Large带来的特征质量惊讶,现在Meta直接把视觉自监督模型推到了70亿参数这个量级,而且不是只能在ImageNet上刷分类准确率,是真正能直接拿来当图像分割和目标检测的通用特征底座。这篇文章我就用一套完整的实战流程,把DINOv3从模型加载、Hugging Face配置,到用它做分割和检测的完整链路讲清楚。不管你是刚开始接触ViT方向的研究生,还是已经在做工业视觉落地的工程师,只要你手里有一块显存稍微像样的卡,这篇文章给的方案基本都能直接复现。

先说明一下我的测试环境,方便你对照:Ubuntu 22.04,RTX 4090 24GB,PyTorch 2.4,Transformers 4.52,CUDA 12.1。DINOv3的7B权重用bf16加载后大概占13GB到14GB显存,单张518x518的图推理时显存峰值大概在18GB到20GB,所以24GB的卡做推理和特征提取是够的,但你要是想微调整个backbone,那至少得准备80GB级别的卡,这个后面我会细说。

1. DINOv3是什么:从DINOv2到DINOv3,7B ViT到底解决了什么问题

1.1 自监督视觉模型的核心逻辑

在聊DINOv3之前,得先把自监督视觉模型这件事说透。所谓自监督,就是不依赖人工标注,直接在海量无标签图像上学到有意义的表示。DINO系列的做法可以理解成一个“师生互学”的过程:一个teacher模型和一个student模型同时看同一张图的不同裁剪版本,student要去预测teacher输出的特征分布。通过这种约束,模型被迫去理解“这张图里哪些区域是同一个语义实体”,于是逐渐学会了物体边界、部件关系、甚至部分语义信息。

DINOv2在2023年发布的时候,已经让人眼前一亮。它用约1.42亿张图训练出ViT-L/14,提取的特征在k-NN分类、深度估计、语义分割等下游任务上表现非常强。而且DINOv2的特征有一个特别宝贵的性质:语义对齐非常干净,不同图片中同一个物体的patch特征彼此靠近,这为很多无监督视觉任务提供了极好的基础。

但DINOv2也有明显短板。最典型的就是随着模型变大,patch特征会出现严重的“同质化”现象,当模型加深加宽以后,中间层的很多token最后学习到的模式非常相似,导致特征多样性下降。这有点像一群人都在重复喊同一个口号,信息冗余很大,真正有用的差异化表达反而变少了。

1.2 DINOv3与DINOv2的关键差异

DINOv3是Meta在DINOv2基础上升级出来的新一代自监督ViT,官方发布的权重从1.1B一直覆盖到7B参数,把视觉模型直接推到了LLM量级。如果你看过代码就会注意到,DINOv3在架构上有几个很关键的变化。

第一个变化是去掉CLS token。DINOv2当时还保留着ViT的CLS token,用它作为图像级特征的出口。DINOv3直接把这个角色取消了,改用一组register token来做信息汇聚。这个设计的动机,就是前面提到的特征同质化问题。register token专门承担全局交互和中间沟通的职责,patch token就能更专注地表达局部语义,这就能让特征的空间细节保留得更完整。

第二个变化是teacher模型优化策略调整。DINOv3采用更长的训练计划和更平滑的teacher权重移动平均。简单理解就是把“老师”的水平更新得更稳,避免训练后期因为收敛波动破坏已经学好的特征。

第三个变化是训练数据的清洗和质量,以及在多头自注意力机制上做了一些工程优化。7B模型能训练出来,靠的不只是算法设计,还有非常庞大的算力支撑。对应用层的人来说,我们更关心的是结果:DINOv3在分割、检测、深度估计、语义匹配等一揽子任务上,把DINOv2留下的SOTA记录又整体抬了一大截。

1.3 7B参数意味着什么:容量、显存与训练成本

这里得说一句大实话,7B模型不是银弹,它是一把双刃剑。好处是容量大,能记住更细粒度的视觉模式,对遮挡、重合、少见类别的鲁棒性明显强于小模型。坏处也很直接:显存开销高、推理慢、微调成本贵。

我从官方repo拉下facebook/dinov3-7b这个权重后简单看了下配置。模型结构是ViT-Huge级别的深度扩展,patch size仍然是14,embed_dim约4096,transformer层数在32层左右。你哪怕不做任何微调,只做inference,也需要把14GB左右的bf16权重加载到显存里,加上中间激活值,24GB的卡其实已经很紧张了。

我的建议是:如果你的任务场景比较简单,比如常规的分割和检测,先试1.1B甚至更小的版本,因为特征质量和7B的差距没有想象中那么大。7B用在那些需要精细边界、复杂遮挡、语义细节要求极高的场景里,性价比才体现得出来。后面我会给出具体对比思路。

2. 实战第一步:环境准备与Hugging Face模型加载配置

2.1 显卡与CUDA环境盘点

先把基础环境捋一遍。跑DINOv3 7B推理,我最推荐的是RTX 4090 24GB或者A6000 48GB,A100/H100自然更好。如果是16GB显存的卡,建议直接用DINOv3的large或者small版本,架构和用法完全一致,只是特征维度不同。24GB是7B推理比较舒服的起步线,你再怎么优化,14GB的权重在那摆着。

软件环境方面,Python建议用3.10或3.11,PyTorch建议2.x版本。CUDA倒不用刻意追求最新,12.1及以上都能跑,关键是显卡驱动版本要跟CUDA匹配。装好之后先跑一句python -c "import torch; print(torch.cuda.get_device_name(0))",确认PyTorch能看到显卡再做下一步。

2.2 依赖安装与Hugging Face模型下载配置

Hugging Face在国内的访问速度,懂的都懂。下载7B权重这种十几个G的文件,如果直接用默认源,等到天黑也下不完。这里我建议大家直接在环境变量里把Hugging Face的下载端点切到镜像站,一劳永逸。

export HF_ENDPOINT=https://hf-mirror.com

这个环境变量可以写到~/.bashrc里,下次终端启动就自动生效。设置好之后,用huggingface-cli下载模型就顺畅多了。第一次使用需要先安装huggingface_hub的命令行工具:

pip install -U "huggingface_hub[cli]" huggingface-cli download facebook/dinov3-7b --local-dir ./dinov3-7b

用--local-dir指定本地目录有个好处,模型会完整下载到你自己指定的路径,后续不用再经过Hugging Face的缓存目录,方便管理和断点续传。如果下载中途断了,重跑同一条命令,它会自动从断点继续,不用删掉重来。这一点在下载7B这种大权重的时候特别重要。

还有一个思路是用ModelScope下载。ModelScope上有不少DINOv3的镜像权重,如果HF镜像站的速度还是不够快,可以拿ModelScope兜底。下载完以后把权重文件手动整理到一个目录,然后用from_pretrained时传local_files_only=True就行。

2.3 加载DINOv3权重并跑通第一次推理

DINOv3在Hugging Face上是以自定义代码的形式发布的,加载时必须带trust_remote_code=True,这个参数的含义是信任repo里提供的模型代码。因为DINOv3的模型结构不是Transformers库原生内置的,需要在加载时执行仓库里的自定义Python代码。你要是忘了这个参数,会直接报一个跟trust_remote_code相关的错误。

下面这段是最小可复现的加载代码,先确认权重能不能正常起来:

import torch from transformers import AutoModel device = "cuda" if torch.cuda.is_available() else "cpu" model = AutoModel.from_pretrained( "facebook/dinov3-7b", trust_remote_code=True, torch_dtype=torch.bfloat16, local_files_only=False, ) model = model.to(device).eval() print("model loaded:", type(model).__name__)

加载的时候用torch_dtype=torch.bfloat16非常关键。DINOv3内部很多计算都用bf16格式,你如果默认用fp32加载,不仅显存直接翻倍,而且速度反而变慢。bf16和fp32在视觉特征提取场景下的精度差异几乎可以忽略,但显存占用能砍一半,这笔账怎么算都划算。

跑通加载之后,就该验证特征提取了。这里我顺手把图像预处理也一起写了。DINOv3的输入是518x518分辨率,patch size为14,所以你会得到37x37共1369个patch token,另外加上若干register token。图像归一化的mean和std,跟ImageNet预训练的标准一致。

import torch import torchvision.transforms as T from PIL import Image transform = T.Compose([ T.Resize((518, 518)), T.ToTensor(), T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) image = Image.open("test.jpg").convert("RGB") pixel_values = transform(image).unsqueeze(0).to(device).to(torch.bfloat16) with torch.no_grad(): outputs = model(pixel_values, output_hidden_states=True) features = outputs.hidden_states[-1] # [B, num_tokens, dim] print(features.shape)

这里我取的是hidden_states[-1],也就是最后一层的输出。在大部分下游任务中,最后一层特征的语义最凝练。不过你要做细粒度分割,中间几层的特征反而可能更有用,因为空间细节保留得好。这个话题我放到后面分割实战里展开。

3. 用DINOv3特征做图像分割:无标注方案实战

3.1 特征提取与KMeans分割

DINOv3最惊艳我的地方,就是不需要任何标注,只用它提取的特征做KMeans聚类,就能得到质量相当不错的语义分割结果。原理很简单:DINOv3通过自监督学到的高层特征,天然把不同语义区域的patch特征拉开距离,同一个物体或者同一类背景的特征聚在一起。KMeans做的只是在特征空间里找到这些天然的簇。

这里我把完整代码写出来,你直接用就行:

import numpy as np from sklearn.cluster import KMeans # features shape: [1, 1373, 4096],前4个是register token patch_features = features[0, 4:, :].float().cpu().numpy() num_clusters = 4 kmeans = KMeans(n_clusters=num_clusters, random_state=0, n_init=10) labels = kmeans.fit_predict(patch_features) labels = labels.reshape(37, 37) # 放大到原图尺寸 from PIL import Image label_img = Image.fromarray((labels.astype(np.uint8) * (255 // (num_clusters - 1)))) label_img = label_img.resize((image.width, image.height), Image.NEAREST) label_img.save("segmentation_result.png")

分割结果保存出来之后,你会看到图像里的主要语义区域被划分成了几块。KMeans的簇数需要根据你的图来调,像一张包含天空、树木、地面、建筑物的场景图,设4到5个簇就差不多。簇数越多,分割越细碎,但也会开始出现同一个物体被切碎的情况。

这里面有个细节需要提醒:patch_features里前面的4个token是register token,特征语义跟空间位置没有直接对应关系,聚类之前一定要去掉。我第一次跑的时候没意识到这个,直接把全部token丢给KMeans,结果聚类结果里出现了两个奇怪的“全局类”,后来排查才发现是register token搞的鬼。

3.2 从分割Mask到轮廓与实例区域

拿到了37x37的粗糙标签图,这只是第一步。实际使用中,你通常需要把它变成可以直接用的轮廓或者区域掩膜。因为分辨率太低,直接放大用会有一块一块的马赛克感,所以要做一步后处理。

一个很实用的流程是:先用KMeans得到粗标签,然后缩放到原图尺寸,再用OpenCV做轮廓提取和mask精修。比如我们可以提取每个语义类别的连通域,过滤掉面积太小的噪声区域,再生成精细的二值mask。核心参数就两个:min_area和一个形态学核大小,这两个我一般根据项目分辨率来定,1000x1000左右的图,min_area设在500到1000像素,核大小3到5就能有不错的效果。

实际上,如果你只是要一个“哪块区域属于目标”的mask,我更推荐的做法是:在KMeans结果上找到目标簇,然后直接用这个簇的37x37 mask作为prompt,喂给SAM系列模型做精细化分割。这样能得到高分辨率、边界像素级的mask,比任何插值放大都自然。SAM2对大块mask prompt非常鲁棒,哪怕37x37的mask缩成原图尺寸已经很糊,SAM2也能根据粗糙位置补出干净边界。

3.3 用线性探测适配特定品类分割

有时候无监督聚类做到的效果可能不够,比如你需要专门分割“人”这个类别,KMeans不管你设几个簇,都不一定能把“人”单独分出来。这时候可以引入少量标注,做一个线性探测头。

所谓线性探测,就是在DINOv3输出的特征上,接一个简单的线性分类层。冻结backbone,只训练这个分类层。因为backbone的特征已经足够好,所以线性层很容易收敛,你只需要几十张标注图就能训练出一个不错的分割分类器。训练完成后,对每个patch预测一个语义类别,再上采样到原图尺寸。

优势很明显:7B的backbone不需要动,训练成本极低,一张4090跑几分钟就完事。而且因为DINOv3特征在大规模数据上学得很充分,线性探测的结果通常比从头训练一个小分割网络的泛化性好很多。如果你的项目需要给客户演示“快速适配新类别的能力”,这个方案是必杀技。

实现上建议直接用torch.nn.Linear(4096, num_classes)就行,不需要非线性层,因为DINOv3的特征本身已经非线性变换得很彻底了。优化器用AdamW,学习率设置在2e-3左右,迭代几百步就收敛得差不多。

这里还有个使用技巧:如果你不确定用最后一层特征还是倒数第二层,一个比较稳妥的方案是concat最后两层的特征。因为分割这种稠密预测任务,既需要语义信息也需要部分空间细节,最后两层特征concat往往比单层效果更稳。

4. 用DINOv3做目标检测:零样本方案与检测头微调

4.1 零样本检测:DINOv3特性 + SAM2

DINOv3特征的一个重要性质是跨图像的语义对齐,也就是说不同图片中同一类物体的patch特征在特征空间里靠得很近。利用这个性质,可以做一个非常实用的零样本目标检测:你在一张参考图上框出目标区域,提取该区域的DINOv3特征向量,然后在测试图上逐patch计算相似度,找到相似度高的区域,这就是候选目标位置。

具体的实现思路是把参考框内的patch token特征做平均,得到一个代表目标的查询向量。然后在测试图像的每个patch特征上计算余弦相似度,得到一张相似度热力图。对热力图做阈值处理,就能得到目标的粗略坐标区域,再用非极大值抑制合并重叠框。

流程清晰以后,代码也不复杂。关键部分是这样:

import torch.nn.functional as F # query_feat: [1, 4096] 参考目标的平均特征 # test_features: [1, 4096, 1369] 测试图像patch特征,做L2归一化 query_feat_norm = F.normalize(query_feat, dim=-1) # [1, 4096] test_features_norm = F.normalize(test_features, dim=1) # [1, 4096, 1369] cosine_scores = test_features_norm.transpose(1, 2) @ query_feat_norm.transpose(0, 1) scores = cosine_scores.squeeze(-1).squeeze(0) # [1369] sim_map = scores.reshape(37, 37).float().cpu() # 对sim_map插值回原图尺寸 sim_map_resized = F.interpolate( sim_map.unsqueeze(0).unsqueeze(0), size=(image.height, image.width), mode="bilinear", align_corners=False, ).squeeze()

拿到相似度热力图之后,你可以按阈值筛选像素,把高于阈值的像素集合的外接矩形作为检测框候选,也可以直接找热力图的局部峰值点作为目标中心。前者适合密集目标,后者适合稀疏目标。我自己的经验是,在相似度图上用OpenCV的connectedComponentsWithStats按阈值提取连通区,然后取每个连通区的外接矩形,这套组合在大多数场景下都靠谱。

检测框出来之后,你可以选择把框交给SAM2去生成精细的mask。SAM2对盒子和点prompt的支持都很成熟,直接调用SAM2ImagePredictor的predict接口就能拿到高精度的实例mask。这样一来整个链路就变成了:DINOv3负责“找到目标在哪”,SAM2负责“把目标边界抠出来”,完全不需要额外训练,就能在任意图片上检测并分割你关心的任意目标类别。

4.2 检测头微调:只调决策层不调backbone

零样本方案胜在快速,但精度上限受限于参考特征的表征能力。如果你的场景固定,比如流水线上检测特定规格的零件,还想追求更高的准确率,那就走微调路线。

但注意,这里说的微调不是让你在7B模型上做全量微调。没人能在一个普通的工作站上全量训练7B参数的视觉模型,那需要极大的显存和训练时间。常规的做法是用DINOv3作为backbone,后面接一个轻量检测头,训练时冻结backbone,只更新检测头。这种做法在视觉领域已经成为一种标准范式。

检测头这边有两种选择。一种是直接用DETR风格的小型Transformer头,比如用conditional DETR的decoder部分,输入DINOv3的patch特征序列,做集合预测输出框。另一种更工程化的方案是直接用现成框架,比如Mask2Former或者Detectron2,把backbone替换成DINOv3,然后只训练pixel decoder和transformer decoder部分。

用Mask2Former框架的话,操作路径大概是:加载DINOv3权重,把backbone输出接到Mask2Former的pixel decoder输入,训练时设置backbone的requires_grad=False。这么做的好处是,Mask2Former本身是一个统一的分割检测框架,既能出语义分割也能出实例分割和全景分割,一个头搞定所有输出。

从训练数据量上来说,因为7B特征质量足够高,检测头通常只需要几百到几千张标注图就能达到可用的水平。我在一个工业零件检测的小项目上用这套方案,大概标了800张图,验证集的mAP就超过了用YOLOv8从头训练6000张图的效果。这就是大模型自监督特征带来的红利。

4.3 从检测框到下游应用

拿DINOv3做完检测之后,后续的路子其实很开阔。最典型的应用是把它当成数据标注的“半自动标注器”:先用DINOv3+参考图的方式在成千上万张未标注图上跑一遍零样本检测,拿到初步的粗框,然后人工只做修正而不是从零框选,标注效率能提升好几倍。这在很多数据标注团队里已经是常规打法了。

第二个典型应用是视频分析。视频相邻帧之间存在大量冗余,你可以在关键帧上用DINOv3做检测,然后利用特征的时序一致性做传播和修正。因为DINOv3的特征跨帧稳定,同类目标在不同帧中特征非常接近,所以检测框在连续帧间的抖动明显比传统检测器小,输出运动的轨迹也更平滑。做行人和车辆轨迹分析的同行,可以重点试一下这个路线。

第三个方向是跨模态。DINOv3的特征空间虽然是在图像上训练的,但它的语义对齐特性天然适合跟CLIP这类图文模型做特征拼接。比如用DINOv3定位目标位置,然后把目标区域的特征交给CLIP做类别文本匹配,就能实现自然语言驱动的开放词汇检测,相当于一个简化版的Grounded SAM流程。工程上可以先把DINOv3裁剪出的目标图块统一缩放到224x224,再走CLIP的image encoder算文本相似度,效果非常显著。

5. 高频踩坑实录与排查方法

5.1 显存不够直接OOM怎么办

OOM是7B模型绕不过去的一道坎,我自己的24GB卡在加载模型后做单张高分辨率图推理时,也经常能感到显存吃紧。我验证下来比较管用的几个手段,按优先级排序:

第一,确认模型是bf16加载,不是fp32。很多OOM案例都是因为这个,fp32状态下7B模型权重就接近28GB,24GB卡根本跑不起来。第二,控制输入分辨率。DINOv3默认是518x518,你非要输入1024x1024,显存占用会成倍增长。如果不是必须高分辨率,别自找麻烦。第三,推理时全程用torch.no_grad(),这个写过的人都知道,但新手经常会忽略,导致中间过程保存了很多不必要的计算图。第四,在非常极限的情况下,可以对patch做分块推理,即把图像切成多块,分别提取特征再做拼接。不过这个方案会影响边缘patch的上下文信息,我一般只在最后关头用。

注意:不要在加载模型的同时再去加载一个完整的SAM2模型,两个模型叠一起显存直接爆炸。建议流程上分开,先跑DINOv3拿到检测框,再按需加载SAM2做mask,跑完就释放。

5.2 HFF下载速度太慢或者下到一半卡死

这个问题我处理过太多次。除了前面说的HF_ENDPOINT=https://hf-mirror.com这个环境变量之外,还有两个小技巧。

一是用huggingface-cli download配合--local-dir在我前面写过的路径下载。不要用浏览器直接点下载链接,浏览器没有断点续传能力,中途断了又得重头来。二是如果镜像站的速度仍然不理想,可以考虑用ModelScope下载,搜一下dinov3就能找到对应repo,下载完手动整理成Hugging Face标准的目录结构,之后from_pretrained照样能用,只是需要传local_files_only=True。

另外提醒一句,7B权重在下载时需要预留至少30GB的磁盘空间。下载下来的文件是分片存储的,本地路径下会有多个bin文件加一个model.safetensors.index.json。不要手动改文件结构,from_pretrained认的是这个标准布局。

5.3 特征维度、token数量对不上怎么办

很多人在接自己的下游模块时,会把DINOv3输出的token数量和特征维度搞混。DINOv3 7B的最后一层特征维度是4096,patch token数量则是根据输入分辨率动态变化的,输入518x518就是1369个patch token,再加上4个register token,一共1373个token。

如果你的输入尺寸不是518,token数量就会变,比如输入是700x700,token数量就是(700/14)^2=2500个。所以在写后续逻辑时,不要硬编码token数量,最好根据输入动态计算h = w = pixel_values.shape[-1] // 14。同时兼容register token的方式,是在拿到features后固定取features[:, 4:, :]作为patch部分的特征,register token永远在前面。

如果你加载模型后拿到的features维度跟你预期不一致,先检查output_hidden_states=True是否传对了。如果你只拿model(pixel_values)的返回值,DINOv3的自定义代码返回的可能是最后的hidden state,但更稳妥的做法是显式请求hidden states。

5.4 分割结果噪声大、边界不够干净

KMeans做粗分割,噪声和碎块几乎是必然的。应对手段主要是两步后处理:第一步用OpenCV的形态学开闭运算,先开运算去掉小白点,再闭运算补上目标内部的小洞,核大小推荐3到5;第二步用连通域分析,把面积小于阈值的区域直接过滤掉,阈值根据你图像分辨率设置,我一般设成图像总像素的0.1%。

如果做完这些你还是觉得分割边界粗糙,那就直接上SAM2细化。前面已经提过,把37x37的粗mask放大到原图尺寸后喂给SAM2,SAM2会把边界修得很干净。这是我认为DINOv3分割链路里最值得用的一个组合,没有之一。

5.5 preprocessing差异导致的特征质量下降

有一个非常隐蔽的坑是预处理不匹配。DINOv3在预训练时用的是特定预处理流程:先做双线性插值resize到短边再裁剪,最后归一化。如果你在测试时改成了直接拉伸到518x518,图像长宽比变了,特征分布就会有一定程度的偏移。所以跑特征提取前,最好验证自己的预处理跟官方一致,不要自己发挥。

具体到代码上,如果你用torchvision.transforms.Resize((518, 518)),实际上是把图拉伸了。如果原图是16:9的宽图,拉伸到正方形,物体的形变会直接干扰特征质量。一个更稳的做法是先按比例缩放,让短边接近518,然后居中裁剪到518x518,或者干脆用Resize加CenterCrop组合。这一个小小的改动,在某些场景下能让相似度检测的精确率提升好几个百分点。

5.6 关于trust_remote_code的安全提示

加载DINOv3必须用trust_remote_code=True,这个热度很高,但也意味着你需要运行Hugging Face仓库里提供的自定义代码。如果你本身对代码安全有严格要求,建议下载完权重后,手动把仓库里的modeling文件从头到尾过一遍再加载,这是负责任的做法。平时做实验无所谓,但是企业内部部署时,这个安全检查习惯建议还是保留。

6. 最后的实操心得

整个流程跑下来,我最深的体会是:DINOv3最大的价值不在于“它本身能做什么”,而在于“它给下游视觉任务提供了一个多强的底座”。以前我们做图像分割,要么训练一个像素级的全卷积网络,要么搞一套复杂的多阶段pipeline。现在DINOv3给出的路线非常清晰:用自监督大模型提取语义特征,然后用最简单的聚类或者线性层就能得到不错的结果,再不行就接SAM2做精修。这套组合几乎覆盖了视觉分割检测的大多数真实场景。

如果你问我7B和1.1B怎么选,我的建议是先用1.1B跑通流程,确认需求和效果,遇到明显的语义理解瓶颈了再切换到7B。因为两者的下游代码完全一致,切换成本很低。7B的“猛药效应”是在复杂场景、遮挡严重、细粒度类别上才体现出来的,如果只是常规工业检测,1.1B的速度优势反而更能提升迭代效率。

最后再分享一个使用小技巧:DINOv3的特征并不一定要用最后一层。做分割时可以比较倒数第一层和倒数第二层特征的KMeans结果,哪个更符合你的语义直觉就用哪个,没有绝对的标准。视觉自监督模型的特征层级本身就是一座富矿,值得多花点时间挖掘一下。

返回列表