基于多模态特征融合的电商图文检索系统

本文围绕图文跨模态检索展开研究,采用Chinese-CLIP预训练模型,对电商图文数据进行训练。该系统具有 “以文搜图”、“以图搜文”和“以图搜图”三个功能,能够显著提升用户体验,增强消费者的购买意愿,同时,还能为电商平台的企业和商家提供宝贵的建议,推动电子商务行业的进步。

本项目包含图文检索系统+优质论文,数据集可替换为其他场景数据集。

获取链接:

【闲鱼】https://m.tb.cn/h.goGB4V5?tk=t0rL3TRQGDL CZ3458 「我在闲鱼发布了【基于Chinese-CLIP的电商图文检索系统】」点击链接直接打开

一.启动Flask服务

(1)window+R

(2)cd +项目地址

(3)输入python .\gr_API\cnclip_api.py 命令

二.启动App

三.效果展示

(1)以文搜图

(2)以图搜文

(3)以图搜图

四.实现原理

本文围绕图文跨模态检索展开研究,采用Chinese-CLIP预训练模型,对电商图文数据进行训练。在此基础上,引入知识蒸馏技术,对模型进行进一步的优化和增强。同时,应用Prompt条件提示学习,引导模型更好地完成任务。在模型训练完成后,将最优Pytorch模型转换为Onnx格式,相比原始Pytorch模型,提升了特征计算的推理速度,同时不影响特征提取的下游任务效果。接下来,使用BERTBi-GRU网络提取文本侧特征,结合Faster R-CNNResNet101网络提取图像侧特征,并通过计算其图文相似度进行匹配,实现电商图文检索系统。该系统具有 “以文搜图”、“以图搜文”和“以图搜图”三个功能,能够显著提升用户体验,增强消费者的购买意愿,同时,还能为电商平台的企业和商家提供宝贵的建议,推动电子商务行业的进步。

(1)环境准备

GPU硬件要求:请准备Volta架构及以上的Nvidia GPU显卡(配备FP16 Tensor Core),Nvidia各架构对应显卡型号请参见此文档表格。本文我们以T4显卡为例
CUDA:推荐CUDA版本11.6及以上,本文以11.6为例
CUDNN:推荐CUDNN 8.6.0及以上,本文以8.6.0为例。请注意TensorRT和CUDNN有版本match关系,如TensorRT 8.5.x必须使用CUDNN 8.6.0,详见TensorRT的版本要求
ONNX:注意我们转换TensorRT模型时,将沿着Pytorch → ONNX → TensorRT的步骤,所以准备TensorRT模型也需要先安装ONNX库。本文以onnx版本1.13.0,onnxruntime-gpu版本1.13.1,onnxmltools版本1.11.1为例
TensorRT:推荐TensorRT版本8.5.x,本文以8.5.2.2为例。TensorRT各版本对应的CUDNN匹配版本,请从文档页面,查阅此TensorRT版本的"NVIDIA TensorRT Support Matrix"
Pytorch:推荐1.12.1及以上,本文以1.12.1为例(建议直接pip安装1.12.1+cu116,环境尽量不要再使用conda安装cudatoolkit,避免环境CUDNN版本变化,导致TensorRT报错)
requirements.txt要求的其他依赖项

执行代码:

pip install tensorrt==8.5.2.2 onnx==1.13.0 onnxruntime-gpu==1.13.1 onnxmltools==1.11.1
pip install torch==1.12.1+cu116 torchvision==0.13.1+cu116 torchaudio==0.12.1 -f https://download.pytorch.org/whl/torch_stable.html
pip install -r requirements.txt 

(2)转换和运行ONNX模型

2.1  转换模型

将Pytorch模型checkpoint转换为ONNX格式的代码,请参见cn_clip/deploy/pytorch_to_onnx.py。我们以转换ViT-B-16规模的Chinese-CLIP预训练模型为例,具体的代码运行方式如下(请参考Readme代码组织部分建好${DATAPATH}并替换下面的脚本内容,尽量使用相对路径):

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"],各规模细节详见Readme
pytorch-ckpt-path: 指定Pytorch模型ckpt路径,上面的代码示例中我们指定为预训练的ckpt路径,也可以指定为用户finetune ckpt的位置。ckpt中的参数需要与model-arch指定的模型规模对应
save-onnx-path: 指定输出ONNX格式模型的路径(前缀)。完成转换后,代码将分别输出文本侧和图像侧的ONNX格式编码模型文件,FP32与FP16各一版,该参数即指定了以上输出文件的路径前缀
convert-text和convert-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
上面示例代码执行结束后,我们得到了ViT-B-16规模,Chinese-CLIP文本侧和图像侧的ONNX模型,可以分别用于提取图文特征。输出ONNX模型的路径均以运行脚本时的save-onnx-path为前缀,后面依次拼上.img/.txt、.fp16/.fp32、.onnx。我们后续将主要使用FP16格式的ONNX模型vit-b-16.txt.fp16.onnx和vit-b-16.img.fp16.onnx

注意到部分ONNX模型文件还附带有一个extra_file,其也是对应ONNX模型的一部分。在使用这些ONNX模型时,由于.onnx文件存储了extra_file的路径(如${DATAPATH}/deploy/vit-b-16.txt.fp16.onnx.extra_file)并会根据此路径载入extra_file,所以使用ONNX模型请不要改动存放的路径名,转换时${DATAPATH}也尽量用相对路径(如../datapath),避免运行时按路径找不到extra_file报错

2.2  运行模型

2.2.1  提取图像侧特征

我们在Chinese-CLIP/目录下,使用以下的示例代码,读取刚刚转换好的ViT-B-16规模ONNX图像侧模型vit-b-16.img.fp16.onnx,并为Readme中示例的皮卡丘图片提取图像侧特征。注意转换好的ONNX模型只接受batch大小为1的输入,即一次调用只处理一张输入图片

# 完成必要的import(下文省略)
import onnxruntime
from PIL import Image
import numpy as np
import torch
import argparse
import cn_clip.clip as clip
from clip import load_from_name, available_models
from clip.utils import _MODELS, _MODEL_INFO, _download, available_models, create_model, image_transform

# 载入ONNX图像侧模型(**请替换${DATAPATH}为实际的路径**)
img_sess_options = onnxruntime.SessionOptions()
img_run_options = onnxruntime.RunOptions()
img_run_options.log_severity_level = 2
img_onnx_model_path="${DATAPATH}/deploy/vit-b-16.img.fp16.onnx"
img_session = onnxruntime.InferenceSession(img_onnx_model_path,
                                        sess_options=img_sess_options,
                                        providers=["CUDAExecutionProvider"])

# 预处理图片
model_arch = "ViT-B-16" # 这里我们使用的是ViT-B-16规模,其他规模请对应修改
preprocess = image_transform(_MODEL_INFO[model_arch]['input_resolution'])
# 示例皮卡丘图片,预处理后得到[1, 3, 分辨率, 分辨率]尺寸的Torch Tensor
image = preprocess(Image.open("examples/pokemon.jpeg")).unsqueeze(0)

# 用ONNX模型计算图像侧特征
image_features = 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, 特征向量维度]

2.2.2  提取文本侧特征

类似地,我们用如下代码完成文本侧ONNX模型的载入与特征计算,与图像侧相同,文本侧ONNX部署模型只接受batch大小为1的输入,即一次调用只处理一条输入文本。我们为4条候选文本依次计算ViT-B-16规模模型的文本特征。import相关代码与上文相同,这里省略:

# 载入ONNX文本侧模型(**请替换${DATAPATH}为实际的路径**)
txt_sess_options = onnxruntime.SessionOptions()
txt_run_options = onnxruntime.RunOptions()
txt_run_options.log_severity_level = 2
txt_onnx_model_path="${DATAPATH}/deploy/vit-b-16.txt.fp16.onnx"
txt_session = onnxruntime.InferenceSession(txt_onnx_model_path,
                                        sess_options=txt_sess_options,
                                        providers=["CUDAExecutionProvider"])

# 为4条输入文本进行分词。序列长度指定为52,需要和转换ONNX模型时保持一致(参见转换时的context-length参数)
text = clip.tokenize(["杰尼龟", "妙蛙种子", "小火龙", "皮卡丘"], context_length=52) 

# 用ONNX模型依次计算文本侧特征
text_features = []
for i in range(len(text)):
    one_text = np.expand_dims(text[i].cpu().numpy(),axis=0)
    text_feature = txt_session.run(["unnorm_text_features"], {"text":one_text})[0] # 未归一化的文本特征
    text_feature = torch.tensor(text_feature)
    text_features.append(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) # 归一化后的Chinese-CLIP文本特征,用于下游任务
print(text_features.shape) # Torch Tensor shape: [4, 特征向量维度]
 2.2.3  计算图文相似度

ONNX模型产出的归一化图文特征,内积后softmax即可计算相似度(需要考虑logit_scale),与原始Pytorch模型操作相同,参见以下代码。import相关代码与上文相同,这里省略:

ONNX模型产出的归一化图文特征,内积后softmax即可计算相似度(需要考虑logit_scale),与原始Pytorch模型操作相同,参见以下代码。import相关代码与上文相同,这里省略:

可以看到,给出的图文相似概率,和Readme中快速使用部分,基于Pytorch同一个模型计算的结果基本一致,证明了ONNX模型特征计算的正确性,而ONNX模型的特征计算速度相比Pytorch更有优势 

五.优质论文展示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值