基于 DINOv2 模型实现图搜图相似度检索任务

一、DINOv2 模型简介及使用

DINOv2是由Meta AI开发的第二代自监督视觉变换器模型,采用 Vision Transformer (ViT) 架构 。其核心特点是在无需人工标签的情况下,通过自监督学习技术,从海量无标注图像中学习有意义的视觉特征表示,类似于 NLP 领域的自监督 Base 模型,DINOv2 已经具有了对图像的理解能力,和强大的图像特征提取能力,因此它可以作为几乎所有计算机视觉任务的骨干模型。

下面是官方演示地址:

https://dinov2.metademolab.com/demos?category=segmentation

深度估计效果:

在这里插入图片描述

语义分割效果:

在这里插入图片描述

GitHub 开源地址:

https://github.com/facebookresearch/dinov2

huggingface 模型地址:

https://huggingface.co/facebook/dinov2-base/tree/main

在这里插入图片描述

本文借助 DINOv2 强大的特征提取能力,实现图图相似度检索任务,但开始前,首先 先了解一下如何基于 DINOv2 实现图像的相似度计算:

from transformers import AutoImageProcessor, AutoModel
from PIL import Image
import matplotlib.pyplot as plt
import torch
plt.rcParams['font.sans-serif'] = ['SimHei']
# 生成图像特征
def gen_image_features(processor, model, device, image):
    with torch.no_grad():
        inputs = processor(images=image, return_tensors="pt").to(device)
        outputs = model(**inputs)
        image_features = outputs.last_hidden_state
        image_features = image_features.mean(dim=1)
        return image_features[0]

# 计算两个图像的相似度
def similarity_image(processor, model, device, image1, image2):
    features1 = gen_image_features(processor, model, device, image1)
    features2 = gen_image_features(processor, model, device, image2)
    cos_sim = torch.cosine_similarity(features1, features2, dim=0)
    cos_sim = (cos_sim + 1) / 2
    return cos_sim.item()

def main():
    model_dir = "facebook/dinov2-base"
    processor = AutoImageProcessor.from_pretrained(model_dir)
    model = AutoModel.from_pretrained(model_dir)
    device = torch.device('cuda:0' if torch.cuda.is_available() else "cpu")
    model.to(device)
    image1 = Image.open("img/dog1.jpg")
    image2 = Image.open("img/dog2.jpg")
    similarity = similarity_image(processor, model, device, image1, image2)
    plt.figure()
    plt.axis('off')
    plt.title(f"相似度: {similarity}")
    plt.subplot(1, 2, 1)
    plt.imshow(image1)
    plt.subplot(1, 2, 2)
    plt.imshow(image2)
    plt.show()

if __name__ == '__main__':
    main()

在这里插入图片描述

在这里插入图片描述

相似度计算的主要核心就是基于 DINOv2 生成特征向量,图图相似度检索也依赖这一点,不过需要多出一个特征向量的持久化存储端,整体实现架构如下图所示,其中特征向量存储采用 Milvus 数据库。

被检索图像数据集特征提取过程:

在这里插入图片描述

图像相似度检索过程:

在这里插入图片描述

关于 Milvus 的使用,可以参考下面这篇博客:

Milvus 向量数据库介绍及使用

二、图图相似度检索实现 - 图像特征持久化

首先准备图像数据集,这里我随便准备了几张猫和狗的图片:

在这里插入图片描述

创建 Milvus Collection,其中 DINOv2 特征向量维度为 768 维:

from pymilvus import MilvusClient, DataType

client = MilvusClient("http://192.168.0.5:19530")

schema = MilvusClient.create_schema(
    auto_id=True,
    enable_dynamic_field=False,
)
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=768)
schema.add_field(field_name="image_name", datatype=DataType.VARCHAR, max_length=256)
schema.verify()
index_params = client.prepare_index_params()
index_params.add_index(
    field_name="id",
    index_type="STL_SORT"
)
index_params.add_index(
    field_name="vector",
    index_type="IVF_FLAT",
    metric_type="L2",
    params={"nlist": 1024}
)
# 创建 collection
client.create_collection(
    collection_name="dinov2_collection",
    schema=schema,
    index_params=index_params
)

图像数据集提取特征向量后,持久化到 Milvus 中:

from transformers import AutoImageProcessor, AutoModel
from PIL import Image
from pymilvus import MilvusClient
from tqdm import tqdm
import torch
import os

# 生成特征向量
def gen_image_features(processor, model, device, image):
    with torch.no_grad():
        inputs = processor(images=image, return_tensors="pt").to(device)
        outputs = model(**inputs)
        image_features = outputs.last_hidden_state
        image_features = image_features.mean(dim=1)
        return image_features[0]

def main():
    # 创建Milvus客户端
    client = MilvusClient("http://192.168.0.5:19530")
    # 加载模型
    model_dir = "facebook/dinov2-base"
    processor = AutoImageProcessor.from_pretrained(model_dir)
    model = AutoModel.from_pretrained(model_dir)
    device = torch.device('cuda:0' if torch.cuda.is_available() else "cpu")
    model.to(device)
    # 读取数据集
    dataset_path = "./img"
    for image_name in tqdm(os.listdir(dataset_path)):
        image_path = os.path.join(dataset_path, image_name)
        image = Image.open(image_path)
        # 提取特征向量
        features = gen_image_features(processor, model, device, image)
        # 存吃至 milvus
        client.insert(
            collection_name="dinov2_collection",
            data={
                "vector": features,
                "image_name": image_name
            }
        )

if __name__ == '__main__':
    main()

运行后,在 Milvus insight 工具中,可以看到存储的内容:

在这里插入图片描述

三、图图相似度检索实现 - 图像特征检索

检索就是拿着当前图像的特征,去向量数据库中检索相似的特征信息,实现过程如下:

from transformers import AutoImageProcessor, AutoModel
from PIL import Image
from pymilvus import MilvusClient
import matplotlib.pyplot as plt
import torch
import os


# 生成特征向量
def gen_image_features(processor, model, device, image):
    with torch.no_grad():
        inputs = processor(images=image, return_tensors="pt").to(device)
        outputs = model(**inputs)
        image_features = outputs.last_hidden_state
        image_features = image_features.mean(dim=1)
        return image_features[0].tolist()


def main():
    # 创建Milvus客户端
    client = MilvusClient("http://192.168.0.5:19530")
    # 加载模型
    model_dir = "facebook/dinov2-base"
    processor = AutoImageProcessor.from_pretrained(model_dir)
    model = AutoModel.from_pretrained(model_dir)
    device = torch.device('cuda:0' if torch.cuda.is_available() else "cpu")
    model.to(device)
    # 检索图像, 采用不在Milvus数据集中的图像
    image = Image.open("./img2/dog.jpeg")
    # 提取特征向量
    features = gen_image_features(processor, model, device, image)
    # 特征召回
    results = client.search(
        collection_name="dinov2_collection",
        data=[features],
        limit=2,
        output_fields=["image_name"],
        search_params={
            "metric_type": "L2",
            "params": {}
        }
    )
    plt.figure()
    plt.axis('off')
    for i, res in enumerate(results[0]):
        image_name = res["entity"]["image_name"]
        image_path = os.path.join("./img", image_name)
        image = Image.open(image_path)
        plt.subplot(1, 2, (i+1))
        plt.imshow(image)
    plt.show()

if __name__ == '__main__':
    main()

测试输入检索图像:

在这里插入图片描述

召回图像:

在这里插入图片描述

测试输入检索图像:

在这里插入图片描述

召回图像:

在这里插入图片描述

### 如何使用 DINOv2 #### 安装依赖项 要开始使用 DINOv2,首先需要准备环境并安装必要的依赖包。假设已配置好 Python 环境以及 PyTorch 框架,则可以通过 pip 或者 conda 来获取其他所需的软件包。 ```bash pip install -r requirements.txt ``` 此命令会依据 `requirements.txt` 文件中的列表来下载所有必需的第三方库[^1]。 #### 下载预训练模型权重文件 接着应当从官方仓库或者其他可信来源处获得预先训练好的 DINOv2 模型参数,并将其放置于指定目录下以便后续加载使用。 #### 单机多卡分布式训练 ViT-Small 网络实例 下面给出了一段用于启动基于 8 块 GPU 的单一计算节点上的 Vision Transformer (ViT)-small 架构微调过程的脚本: ```python import os os.system(''' python -m torch.distributed.launch \ --nproc_per_node=8 \ main_dino.py \ --arch vit_small \ --data_path /path/to/imagenet/train \ --output_dir /path/to/output ''') ``` 上述代码片段展示了怎样利用 PyTorch 提供的工具来进行分布式的深度神经网络训练操作,其中涉及到设置每台机器使用的 GPU 数量 (`--nproc_per_node`)、指明数据集路径 (`--data_path`) 及保存实验成果的位置 (`--output_dir`) 参数传递方式[^3]。 请注意,在执行以上指令之前,需确保本地存在 ImageNet 数据集副本并且正确设置了相应的存储位置;另外还需调整输出结果存放的具体地址以匹配个人需求。 #### 加载预训练模型进行推理 对于想要快速体验 DINOv2 性能而不必经历完整的再训练流程的研究人员来说,可以直接读取现成的权值来做预测任务。这里提供了一个简单的方法来完成这项工作: ```python from torchvision import transforms from PIL import Image import requests from io import BytesIO import torch from dinov2.models.vision_transformer import vit_small # 初始化模型结构并加载预训练权重 model = vit_small() checkpoint_url = "https://example.com/path_to_pretrained_weights.pth" response = requests.get(checkpoint_url) buffer = BytesIO(response.content) state_dict = torch.load(buffer, map_location="cpu") model.load_state_dict(state_dict) transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), ]) img_url = 'http://placekitten.com/g/200/300' response = requests.get(img_url) img = Image.open(BytesIO(response.content)).convert('RGB') input_tensor = transform(img).unsqueeze(0) # 添加批次维度 with torch.no_grad(): output = model(input_tensor) print(output.shape) ``` 这段程序说明了如何构建一个小型图像分类器,它能够接收任意大小的输入图片经过标准化处理之后送入到已经过良好初始化后的 ViT-small 中得到特征表示向量作为最终输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小毕超

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值