基于电商图文数据跨模态检索 图文互检系统

跨模态检索 图文互检系统

可替换泰迪杯数据和模型权重(或者其他场景数据集)进行推理互检,实现图文互检、图图互检、文图互检三个功能以及模型特征向量输出,可做毕设。

效果预览:

视频预览:
bilibili视频演示

本地启动:

1、启动flask服务

在这里插入图片描述

2、启动app

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

实现原理:

训练后的最优模型pt转为onnx模型:将Pytorch模型checkpoint转换为ONNX格式的代码
cd Chinese-CLIP/
export CUDA_VISIBLE_DEVICES=0
export PYTHONPATH=${PYTHONPATH}:`pwd`/cn_clip

# ${DATAPATH}的指定,请参考Readme"代码组织"部分创建好目录,尽量使用相对路径:https://github.com/OFA-Sys/Chinese-CLIP#代码组织
checkpoint_path=${DATAPATH}/pretrained_weights/clip_cn_vit-b-16.pt # 指定要转换的ckpt完整路径
mkdir -p ${DATAPATH}/deploy/ # 创建ONNX模型的输出文件夹

python cn_clip/deploy/pytorch_to_onnx.py \
       --model-arch ViT-B-16 \
       --pytorch-ckpt-path ${checkpoint_path} \
       --save-onnx-path ${DATAPATH}/deploy/vit-b-16 \
       --convert-text --convert-vision
其中各配置项定义如下:
  • model-arch: 模型规模,选项包括["RN50", "ViT-B-16", "ViT-L-14", "ViT-L-14-336", "ViT-H-14"]
  • pytorch-ckpt-path: 指定Pytorch模型ckpt路径,上面的代码示例中我们指定为预训练的ckpt路径,也可以指定为用户finetune ckpt的位置。ckpt中的参数需要与model-arch指定的模型规模对应
  • save-onnx-path: 指定输出ONNX格式模型的路径(前缀)。完成转换后,代码将分别输出文本侧和图像侧的ONNX格式编码模型文件,FP32与FP16各一版,该参数即指定了以上输出文件的路径前缀
  • convert-textconvert-vision: 指定是否转换文本侧和图像侧模型
  • context-length(可选): 指定文本侧ONNX模型,接收输入的序列长度,默认为我们预训练ckpt所使用的52
  • download-root(可选): 如果不指定pytorch-ckpt-path,代码将根据model-arch自动下载Chinese-CLIP官方预训练ckpt用于转换,存放于download-root指定的目录

运行此代码转换完成后,将得到以下的log输出:

Finished PyTorch to ONNX conversion...
>>> The text FP32 ONNX model is saved at ${DATAPATH}/deploy/vit-b-16.txt.fp32.onnx
>>> The text FP16 ONNX model is saved at ${DATAPATH}/deploy/vit-b-16.txt.fp16.onnx with extra file ${DATAPATH}/deploy/vit-b-16.txt.fp16.onnx.extra_file
>>> The vision FP32 ONNX model is saved at ${DATAPATH}/deploy/vit-b-16.img.fp32.onnx
>>> The vision FP16 ONNX model is saved at ${DATAPATH}/deploy/vit-b-16.img.fp16.onnx with extra file ${DATAPATH}/deploy/vit-b-16.img.fp16.onnx.extra_file

定义模型对象代码。该对象具有图像特征导出、文本特征导出:
import onnxruntime
from PIL import Image
import numpy as np
import torch
from cn_clip.clip.utils import _MODEL_INFO, image_transform
import cn_clip.clip as clip



class OnnxModel():
    def __init__(self, img_onnx_model_path, txt_onnx_model_path, model_arch = "ViT-B-16", ):
        self.img_model_path = img_onnx_model_path
        self.model_arch = model_arch


        # 载入ONNX图像侧模型(**请替换${DATAPATH}为实际的路径**)
        img_sess_options = onnxruntime.SessionOptions()
        img_run_options = onnxruntime.RunOptions()
        img_run_options.log_severity_level = 2
        self.img_session = onnxruntime.InferenceSession(self.img_model_path,
                                                   sess_options=img_sess_options,
                                                   providers=["CUDAExecutionProvider"])

        txt_sess_options = onnxruntime.SessionOptions()
        txt_run_options = onnxruntime.RunOptions()
        txt_run_options.log_severity_level = 2
        self.txt_session = onnxruntime.InferenceSession(txt_onnx_model_path,
                                                   sess_options=txt_sess_options,
                                                   providers=["CUDAExecutionProvider"])

    def extract_image_feat(self,image):
        # 预处理图片
        # model_arch = "ViT-B-16"  # 这里我们使用的是ViT-B-16规模,其他规模请对应修改
        preprocess = image_transform(_MODEL_INFO[self.model_arch]['input_resolution'])
        image = preprocess(image).unsqueeze(0)

        # 用ONNX模型计算图像侧特征
        image_features = self.img_session.run(["unnorm_image_features"], {"image": image.cpu().numpy()})[0]  # 未归一化的图像特征
        image_features = torch.tensor(image_features)
        image_features /= image_features.norm(dim=-1, keepdim=True)  # 归一化后的Chinese-CLIP图像特征,用于下游任务
        print(image_features.shape)  # Torch Tensor shape: [1, 特征向量维度]
        image_features_tensor = image_features.cuda()
        return image_features_tensor

    def extract_text_feat(self,text_):
        # 为4条输入文本进行分词。序列长度指定为52,需要和转换ONNX模型时保持一致(参见转换时的context-length参数)
        text = clip.tokenize(["{}".format(text_)], context_length=52)
        print(text)

        text_features = []
        for i in range(len(text)):
            one_text = np.expand_dims(text[i].cpu().numpy(), axis=0)
            text_feature = self.txt_session.run(["unnorm_text_features"], {"text": one_text})[0]  # 未归一化的文本特征
            text_feature = torch.tensor(text_feature)
            text_features.append(text_feature)
        # 拿到text_feature
        text_features = torch.squeeze(torch.stack(text_features), dim=1)  # 4个特征向量stack到一起
        text_features = text_features / text_features.norm(dim=1, keepdim=True)
        # 转为torch.Tensor 并放在cuda
        text_feat_tensor = text_features.cuda()
        return text_feat_tensor
编写后端模型推理API,初始化模型对象,调用模型进行互检。

项目框架介绍:

代码框架文件夹:

在这里插入图片描述

框架结构:

在这里插入图片描述

数据集、模型替换:

在这里插入图片描述

获取链接

烦请移步社区

<think>好的,我需要设计并实现一个基于CLIP的跨模态哈希检索系统。首先,我需要理解CLIP模型的基本原理和它在跨模态检索中的应用。CLIP(Contrastive Language-Image Pretraining)是由OpenAI开发的模型,能够将图像和文本映射到同一个语义空间,从而实现跨模态的相似性匹配。这在图文检索中非常有用,比如用户可以用文本搜索相关图片,或者用图片搜索相关文本。 接下来,我需要考虑系统的整体架构。根据引用[1]提到的多模态融合架构,可能适用联合架构或编解码架构。但CLIP本身已经是一个预训练好的模型,能够将不同模态的数据编码到同一空间,因此可能不需要复杂的融合架构,而是直接利用CLIP的编码能力。不过,为了实现哈希检索,可能需要将高维的CLIP嵌入向量转换为低维的哈希码,以提升检索效率。 然后,哈希编码的设计是关键步骤。传统的哈希方法如LSH(局部敏感哈希)可能不适用于深度学习的特征,因此需要考虑深度哈希方法,比如在CLIP的编码器后添加一个哈希层,将特征向量二值化。同时,需要设计损失函数来保持跨模态的相似性,比如使用对比损失或三元组损失,确保相似的图像和文本在哈希码空间中距离更近。 在训练过程中,可能需要冻结CLIP的部分层,只训练哈希层和微调部分顶层,以节省计算资源。此外,数据预处理也很重要,需要准备大量的图像-文本对数据集,如COCO或Flickr30k,并进行适当的数据增强,以提高模型的泛化能力。 系统实现方面,可以分为以下几个步骤:首先,使用CLIP编码器处理图像和文本,得到高维特征向量;其次,通过哈希层将特征转换为二进制哈希码;然后,构建哈希索引数据库;最后,实现检索接口,根据查询的哈希码在数据库中进行快速相似性搜索。 可能遇到的问题包括哈希码长度选择(平衡检索精度和效率)、训练过程中的收敛问题,以及如何处理大规模数据下的检索效率。需要参考引用[2]中提到的LexLIP方法,看看是否有词典瓶颈技术可以借鉴,来优化哈希码的生成。此外,引用[3]提到的图文检索应用场景,提醒我需要考虑实际应用中的用户体验,比如如何快速响应用户查询,并展示相关结果。 最后,系统评估是关键。需要采用常见的检索指标,如mAP(平均精度均值)、Recall@K等,来评估系统的性能。同时,对比不同哈希码长度和不同训练策略的效果,选择最优配置。</think>### 基于CLIP的跨模态哈希检索系统设计与实现 #### 一、系统设计原理 1. **CLIP模型基础** CLIP(Contrastive Language-Image Pretraining)通过对比学习将图像和文本映射到共享的语义空间,其输出特征向量可直接用于相似性计算[^3]。跨模态哈希检索的核心是将高维特征压缩为二进制哈希码,同时保留语义相似性。 2. **哈希编码设计** - **目标**: 将CLIP输出的$d$维特征(如512维)转换为$k$位二进制哈希码(如64位)。 - **方法**: 在CLIP编码器后添加全连接层+符号函数,例如: $$ H(x) = \text{sign}(W \cdot f_{\text{CLIP}}(x) + b) $$ 其中$f_{\text{CLIP}}$为CLIP编码器,$W \in \mathbb{R}^{k \times d}$为可训练参数。 3. **损失函数** 使用跨模态三元组损失(Triplet Loss)约束相似性: $$ \mathcal{L} = \max(0, \|H_{\text{img}} - H_{\text{text}}^+\| - \|H_{\text{img}} - H_{\text{text}}^-\| + \alpha) $$ 其中$\alpha$为间隔超参数,$H_{\text{text}}^+$为匹配文本哈希码,$H_{\text{text}}^-$为不匹配文本哈希码。 #### 二、实现步骤与代码示例 1. **数据预处理** 使用图像-文本对数据集(如Flickr30k),对图像进行归一化,文本进行分词。 ```python from PIL import Image import torch from transformers import CLIPProcessor, CLIPModel # 加载预训练CLIP模型 model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32") processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32") # 图像和文本编码示例 image = Image.open("image.jpg") inputs = processor(text=["a cat", "a dog"], images=image, return_tensors="pt", padding=True) outputs = model(**inputs) image_emb = outputs.image_embeds # 图像特征向量 text_emb = outputs.text_embeds # 文本特征向量 ``` 2. **哈希层实现** ```python import torch.nn as nn class HashLayer(nn.Module): def __init__(self, input_dim=512, hash_dim=64): super().__init__() self.fc = nn.Linear(input_dim, hash_dim) def forward(self, x): return torch.sign(self.fc(x)) # 二值化输出 ``` 3. **训练流程** ```python # 定义联合训练模型 class HashCLIP(nn.Module): def __init__(self, clip_model, hash_dim=64): super().__init__() self.clip = clip_model self.img_hash = HashLayer(hash_dim=hash_dim) self.text_hash = HashLayer(hash_dim=hash_dim) def forward(self, images, texts): # 冻结CLIP参数(可选) with torch.no_grad(): image_features = self.clip.get_image_features(**images) text_features = self.clip.get_text_features(**texts) return self.img_hash(image_features), self.text_hash(text_features) ``` #### 三、性能优化关键 1. **量化加速**: 使用汉明距离(Hamming Distance)代替欧氏距离加速检索: $$ \text{汉明距离}(H_1, H_2) = \sum_{i=1}^k \mathbb{I}(H_1^{(i)} \neq H_2^{(i)}) $$ 2. **索引构建**: 采用倒排索引或图索引(如HNSW)管理哈希码数据库[^2]。 3. **长尾问题**: 通过动态难例挖掘(Hard Negative Mining)改进三元组采样策略。 #### 四、评估指标 | 指标 | 计算公式 | 说明 | |------------|-----------------------------------|--------------------------| | mAP@K | $\frac{1}{|Q|}\sum_{q=1}^{|Q|} \frac{1}{K}\sum_{k=1}^K P@k$ | 平均检索精度 | | Recall@K | $\frac{\text{相关结果中前K个的数量}}{\text{所有相关结果数量}}$ | 前K位的召回率 | #### 五、应用场景 1. 手机相册的模糊图片检索(如输入“去年夏天的海边照片”) 2. 电商平台的跨模态搜索(用文字描述搜索商品图片) 3. 医学影像的标签-图像关联检索
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

葡萄成熟时_

谢谢您,祝您生活愉快,所想及得

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

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

打赏作者

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

抵扣说明:

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

余额充值