15. CLIP

CLIP (Contrastive Language-Image Pre-Training) 模型是一种多模态预训练神经网络,由OpenAI在2021年发布,是从自然语言监督中学习的一种有效且可扩展的方法。

broken

CLIP的主要结构是一个文本编码器Text Encoder和一个图像编码器Image Encoder, 然后计算文本向量和图像向量的相似度来预测是否匹配。

CLIP用文本作为监督信号来训练可迁移的视觉模型, 使得最终模型的zero-shot效果堪比ResNet50,泛化性非常好。CLIP模型在多个领域表现出色:

  • zero-shot图像分类,即直接推理,用见过的图片特征去判断没见过的图片的类别;

  • zero-shot目标检测,即检测训练数据集没有包含的类别;

  • StyleCLIP,可以通过文字的改变引导图像的生成;

  • CLIP视频检索,可以通过输入文本直接找到视频中出现的对应物体;

  • 等等….

本章将在鲁班猫rk系列板卡上简单测试 CLIPChinese-CLIP 模型, 测试中使用的文件都在配套例程。

15.1. CLIP推理

教程测试CLIP模型是使用 Huggingface Transformers 提供的 clip-vit-base-patch32

先使用conda创建虚拟环境,安装相关pytorch等等库:

# 使用conda创建虚拟环境
conda create -n clip python=3.9
conda activate clip

# 根据自行的环境安装pytorch,详细命令参考https://pytorch.org/get-started/locally/,下面是参考命令:
conda install pytorch torchvision pytorch-cuda=12.1 -c pytorch -c nvidia

# 配置pip源(可选)
pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/

# 安装Huggingface Transformers
pip install transformers

参考Huggingface模型示例简单测试模型:

test_clip.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 省略.............
from PIL import Image
import requests
from transformers import AutoProcessor, CLIPModel

model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = AutoProcessor.from_pretrained("openai/clip-vit-base-patch32")

url = "http://images.cocodataset.org/val2017/000000039769.jpg"
image = Image.open(requests.get(url, stream=True).raw)

inputs = processor(
    text=["a photo of a cat", "a photo of a dog"], images=image, return_tensors="pt", padding=True
)

outputs = model(**inputs)
logits_per_image = outputs.logits_per_image  # this is the image-text similarity score
probs = logits_per_image.softmax(dim=1)  # we can take the softmax to get the label probabilities

print(probs)
(clip) llh@llh:/xxx/clip$ python test_clip.py
config.json: 100%|█████████████████████████████████████████████████████████████████████| 4.19k/4.19k [00:00<00:00, 728kB/s]
pytorch_model.bin: 100%|████████████████████████████████████████████████████████████| 605M/605M [00:16<00:00, 36.4MB/s]
preprocessor_config.json: 100%|██████████████████████████████████████████████████████████████████| 316/316 [00:00<00:00, 62.5kB/s]
tokenizer_config.json: 100%|██████████████████████████████████████████████████████████████████████| 592/592 [00:00<00:00, 757kB/s]
vocab.json: 100%|█████████████████████████████████████████████████████████████████████████████| 862k/862k [00:00<00:00, 1.42MB/s]
merges.txt: 100%|██████████████████████████████████████████████████████████████████████| 525k/525k [00:00<00:00, 12.4MB/s]
tokenizer.json: 100%|████████████████████████████████████████████████████████████████████| 2.22M/2.22M [00:00<00:00, 2.26MB/s]
special_tokens_map.json: 100%|██████████████████████████████████████████████| 389/389 [00:00<00:00, 501kB/s]
tensor([[0.9949, 0.0051]], grad_fn=<SoftmaxBackward0>)

15.2. CLIP模型部署

在鲁班猫RK系列板卡上部署detr模型,需要先使用Huggingface的工具 optimum 导出onnx模型,然后使用 使用toolkit2工具转换成rknn模型。

15.2.1. 转换成onnx模型

测试 clip-vit-base-patch32 模型转换成onnx。

# 安装optimum exporters依赖模块
pip install optimum[exporters]

# 导出onnx模型,将会自动下载的openai/clip-vit-base-patch32 ,最后指定转换后的模型保存在clip-vit-base-patch32-onnx目录下
(clip) llh@llh:/xxx/clip$ optimum-cli export onnx --model openai/clip-vit-base-patch32  --opset 18 ./clip-vit-base-patch32-onnx

导出的onnx模型保存在指定的目录clip-vit-base-patch32-onnx下,名称为model.onnx。

然后需要将模型截取出文本侧和图像侧模型,参考 rknn_model_zoo 中clip示例的truncated_onnx.py文件。

truncated_onnx.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import onnx
import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Export clip onnx model', add_help=True)
    parser.add_argument('--model', type=str, required=True,
                        help='onnx model path')
    args = parser.parse_args()

    output_path = './clip_text.onnx'
    input_names = ['input_ids', 'attention_mask']
    output_names = ['text_embeds']
    onnx.utils.extract_model(args.model, output_path, input_names, output_names)

    output_path = './clip_images.onnx'
    input_names = ['pixel_values']
    output_names = ['image_embeds']
    onnx.utils.extract_model(args.model, output_path, input_names, output_names)
# 执行程序
cd clip-vit-base-patch32-onnx
python ./truncated_onnx.py --model ./model.onnx

执行程序后,会在当前目录下生成clip_images.onnx和clip_text.onnx文件。

15.2.2. 转换成rknn模型

接着使用toolkit2工具,将前面的clip_images.onnx和clip_text.onnx模型文件转换成rknn模型。

convert_clip_text.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 省略.............

if __name__ == '__main__':
    model_path, platform, do_quant, output_path = parse_arg()

    # Create RKNN object
    rknn = RKNN(verbose=False)

    # Pre-process config
    print('--> Config model')
    rknn.config(target_platform=platform)
    print('done')

    # Load model
    print('--> Loading model')
    ret = rknn.load_onnx(model=model_path,
                     inputs=['input_ids', 'attention_mask'],
                     input_size_list=[[TEXT_BATCH_SIZE, SEQUENCE_LEN], [TEXT_BATCH_SIZE, SEQUENCE_LEN]])
    if ret != 0:
        print('Load model failed!')
        exit(ret)
    print('done')

    # 省略.............

convert_text.py将文本侧模型转换成rknn,需要注意设置的inputs和input_size_list,文本侧模型设置batch固定大小为1,序列长度为20。

convert_clip_images.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 省略.............
if __name__ == '__main__':
    model_path, platform, do_quant, output_path = parse_arg()

    # Create RKNN object
    rknn = RKNN(verbose=False)

    # Pre-process config
    print('--> Config model')
    rknn.config(target_platform=platform,
                mean_values=[[0.48145466*255, 0.4578275*255, 0.40821073*255]],
                std_values=[[0.26862954*255, 0.26130258*255, 0.27577711*255]])
    print('done')

    # Load model
    print('--> Loading model')
    ret = rknn.load_onnx(model=model_path,
                        inputs=['pixel_values'],
                        input_size_list=[[1, 3, IMAGE_SIZE[0], IMAGE_SIZE[1]]])
    if ret != 0:
        print('Load model failed!')
        exit(ret)
    print('done')

    # Build model
    print('--> Building model')
    ret = rknn.build(do_quantization=do_quant)
    if ret != 0:
        print('Build model failed!')
        exit(ret)
    print('done')

    # 省略.............

convert_images.py将图像侧模型转换成rknn,需要注意设置的inputs和input_size_list,图像侧模型设置batch固定大小为1,分辨率为224*224。

切换到toolkit2环境,然后执行程序:

# Usage: python3 convert_text.py onnx_model_path [platform] [dtype(optional)] [output_rknn_path(optional)]
# 运行文本侧模型转换程序,测试lubancat-4/5指定平台rk3588,lubancat-3设置rk3576等等,指定最后导出的rknn模型路径等
(toolkit2_2.3) llh@llh:/xxx/clip$ python convert_text.py ./clip_text.onnx rk3588 fp  ./clip_text.rknn
I rknn-toolkit2 version: 2.3.0
--> Config model
done
--> Loading model
W load_onnx: If you don't need to crop the model, don't set 'inputs'/'input_size_list'/'outputs'!
I Loading : 100%|███████████████████████████████████████████████| 197/197 [00:00<00:00, 3138.90it/s]
done
--> Building model
# 省略............
I OpFusing 0: 100%|██████████████████████████████████████████████| 100/100 [00:00<00:00, 393.32it/s]
I OpFusing 1 : 100%|█████████████████████████████████████████████| 100/100 [00:00<00:00, 133.26it/s]
I OpFusing 0 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 61.58it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 59.97it/s]
I OpFusing 0 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 57.92it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 57.49it/s]
I OpFusing 2 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 56.40it/s]
I OpFusing 0 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 53.64it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 52.98it/s]
I OpFusing 2 : 100%|██████████████████████████████████████████████| 100/100 [00:02<00:00, 47.30it/s]
I rknn building ...
I rknn building done.
done
--> Export rknn model
done

# 运行图像侧模型转换程序,测试lubancat-4/5指定平台rk3588,lubancat-3设置rk3576等等,指定最后导出的rknn模型路径等
(toolkit2_2.3) llh@llh:/xxx/clip$ python convert_images.py ./clip_images.onnx rk3588 fp  ./clip_images.rknn
I rknn-toolkit2 version: 2.3.0
--> Config model
done
--> Loading model
W load_onnx: If you don't need to crop the model, don't set 'inputs'/'input_size_list'/'outputs'!
I Loading : 100%|███████████████████████████████████████████████| 200/200 [00:00<00:00, 2670.08it/s]
done
--> Building model
I OpFusing 0: 100%|██████████████████████████████████████████████| 100/100 [00:00<00:00, 421.53it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 88.17it/s]
I OpFusing 0 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 52.58it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 51.53it/s]
I OpFusing 0 : 100%|██████████████████████████████████████████████| 100/100 [00:02<00:00, 49.89it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:02<00:00, 49.57it/s]
I OpFusing 2 : 100%|██████████████████████████████████████████████| 100/100 [00:02<00:00, 48.85it/s]
I OpFusing 0 : 100%|██████████████████████████████████████████████| 100/100 [00:02<00:00, 47.26it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:02<00:00, 46.83it/s]
I OpFusing 2 : 100%|██████████████████████████████████████████████| 100/100 [00:02<00:00, 36.74it/s]
I rknn building ...
I rknn building done.
done
--> Export rknn model
done

在当前目录下生成clip_images.rknn和clip_text.rknn模型文件。

15.2.3. 板卡上部署测试

获取测试例程:

git clone https://gitee.com/LubanCat/lubancat_ai_manual_code

板卡上直接编译例程(教程测试lubancat-4):

sudo apt update
sudo apt install libboost-all-dev

# 切换到例程目录
cd lubancat_ai_manual_code/example/clip

# 复制前面转换出的rknn模型到model目录下
# 编译例程
cat@lubancat:~/xxx/clip$ ./build-linux.sh -t rk3588
./build-linux.sh -t rk3588
===================================
TARGET_SOC=rk3588
INSTALL_DIR=/home/cat/xxx/clip/cpp/install/rk3588_linux
BUILD_DIR=/home/cat/xxx/clip/cpp/build/build_rk3588_linux
DISABLE_RGA=OFF
BUILD_TYPE=Release
ENABLE_ASAN=OFF
CC=aarch64-linux-gnu-gcc
CXX=aarch64-linux-gnu-g++
===================================
-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
 # 省略..............
[ 95%] Built target clip_demo
[100%] Linking CXX executable cn_clip_demo
[100%] Built target cn_clip_demo
[  8%] Built target imageutils
[ 17%] Built target fileutils
[ 56%] Built target cn_clip_demo
[ 82%] Built target clip_demo
[ 91%] Built target audioutils
[100%] Built target imagedrawing
# 省略..............

生成的可执行文件在install/rk3588_linux目录下,有两个可执行文件,一个是CLIP部署例程(clip_demo), 一个是后面Chinese-CLIP模型部署的例程(cn_clip_demo),这里测试CLIP模型例程。

./clip_demo <image_model_path> <image_path> <text_model_path> <text_path>
# 第一个参数指rknn图像侧模型,第二个参数是输入的图像,第三个参数是rknn文本侧模型,第四个参数是输入文本
cat@lubancat:~/xxx/install/rk3588_linux$ ./clip_demo  ./model/clip_images.rknn  ./model/dog_224x224.jpg ./model/clip_text.rknn ./model/text.txt
--> init clip image model
# 省略...........
num_lines=2
rga_api version 1.10.1_[0]
-- inference_clip_model use: 195.167999 ms
--> rknn clip demo result
images: ./model/dog_224x224.jpg
text  : a photo of a dog
score : 0.989

程序指定标签文件(text.txt)用于构建每个类别的描述文本,测试例程中只有两个A photo of cat和A photo of dog,将这些文本送入Text Encoder得到对应的文本特征。

将要预测的图像(dog_224x224.jpg )送入Image Encoder得到图像特征,然后与前面的2个文本特征计算缩放的余弦相似,然后选择相似度最大的文本对应的类别作为图像分类预测结果。

上面测试可以看到图像分类输出结果“a photo of a dog ”和“0.989”,下面我们换一张有猫的图片,然后重新测试:

cat@lubancat:~/xxx/install/rk3588_linux$ ./clip_demo  ./model/clip_images.rknn  ./model/000000039769.jpg ./model/clip_text.rknn ./model/text.txt
--> init clip image model
# 省略.................
--> inference clip image model
--> rknn clip demo result
images: ./000000039769.jpg
text  : a photo of a cat
score : 0.994

也可以自行往text.txt添加其他类别,格式是:a photo of a {label},然后测试。

15.3. Chinese-CLIP模型部署

Chinese-CLIP 是CLIP模型的中文版本, 针对中文领域数据以及在中文数据上实现效果做了优化。

Chinese-CLIP项目地址:https://github.com/OFA-Sys/Chinese-CLIP

15.3.1. 转换出onnx模型

Chinese-CLIP 提供了API、训练代码和测试代码,部署代码等等, 参考工程目录deploy下的pytorch_to_onnx.py,将模型转换成onnx模型。

准备Chinese-CLIP环境:

# 进入前面创建的虚拟环境(安装了pytorch、onnx等等相关库)
conda activate clip

# 获取Chinese-CLIP工程文件
(clip) llh@llh:/xxx$ git clone https://github.com/OFA-Sys/Chinese-CLIP.git

# 切换到Chinese-CLIP工程目录
(clip) llh@llh:/xxx$ cd Chinese-CLIP
(clip) llh@llh:/xxx/Chinese-CLIP$

# 创建build文件,设置相关环境变量,安装相关库等等
(clip) llh@llh:/xxx/Chinese-CLIP$ mkdir build
(clip) llh@llh:/xxx/Chinese-CLIP$ pip install onnxmltools onnxconverter_common
(clip) llh@llh:/xxx/Chinese-CLIP$ export PYTHONPATH=${PYTHONPATH}:$(pwd)/cn_clip

# 也可以直接安装,然后使用接口
# pip install cn_clip

Chinese-CLIP目前开源5个不同规模,其模型信息和下载方式见 Chinese-CLIP README页面。

broken

教程测试CN-CLIPViT-B/16模型,获取预训练模型后使用deploy/pytorch_to_onnx.py例程转换出onnx模型, deploy/pytorch_to_onnx.py文件的使用,详细说明请查看下工程文件 deployment.md

# 获取预训练的ckpt文件
wget https://clip-cn-beijing.oss-cn-beijing.aliyuncs.com/checkpoints/clip_cn_vit-b-16.pt

# 然后修改deploy/pytorch_to_onnx.py中opset版本,改为14以上
opset_version=14,

# 修改deploy/pytorch_to_onnx.py导出的img和text的fp16onnx模型,不使用extra_file
    # convert vision FP16 ONNX model based on the FP32 model
    vision_fp16_onnx_path = f"{args.save_onnx_path}.img.fp16.onnx"
    vision_fp32_onnx_model = load_model(vision_fp32_onnx_path)
    vision_fp16_onnx_model = convert_float_to_float16(vision_fp32_onnx_model, keep_io_types=True, disable_shape_infer=True)
  + onnx.save(vision_fp16_onnx_model, f"{args.save_onnx_path}.img.fp16.onnx")
  -  # save_model(vision_fp16_onnx_model,
  -  #             vision_fp16_onnx_path,
  -  #             location="{}.extra_file".format(os.path.split(vision_fp16_onnx_path)[1]),
  -  #             save_as_external_data=True,
  -  #             all_tensors_to_one_file=True,
  -  #             size_threshold=1024,
  -  #             convert_attribute=True)

# 详细修改的deploy/pytorch_to_onnx.py请参考配套例程的pytorch_to_onnx.py

# 将配套例程的pytorch_to_onnx.py复制到Chinese-CLIP工程文件中
# 执行deploy/pytorch_to_onnx.py,其中--model-arch指定模型规模
# --pytorch-ckpt-path指定Pytorch模型ckpt路径
# 参数onvert-text和convert-vision指定是否转换文本侧和图像侧模型
# --context-length参数设置文本侧模型,文本序列长度,默认是52
(clip) llh@llh:/xxx/Chinese-CLIP$ python cn_clip/deploy/pytorch_to_onnx.py \
                                    --model-arch ViT-B-16 \
                                    --pytorch-ckpt-path ../clip_cn_vit-b-16.pt \
                                    --save-onnx-path ./build/vit-b-16 \
                                    --convert-text --convert-vision \
                                    --context-length 12
# 省略..................................................................................
Finished PyTorch to ONNX conversion...
>>> The text FP32 ONNX model is saved at ./build/vit-b-16.txt.fp32.onnx
>>> The text FP16 ONNX model is saved at ./build/vit-b-16.txt.fp16.onnx with extra file ./build/vit-b-16.txt.fp16.onnx.extra_file
>>> The vision FP32 ONNX model is saved at ./build/vit-b-16.img.fp32.onnx
>>> The vision FP16 ONNX model is saved at ./build/vit-b-16.img.fp16.onnx with extra file ./build/vit-b-16.img.fp16.onnx.extra_file

转换出的onnx模型保存在指定的路径build/目录下,将会生成多个onnx文件, 在后面部署阶段,我们将使用vit-b-16.txt.fp16.onnx和vit-b-16.img.fp16.onnx文件。

15.3.2. 导出rknn模型

接着使用toolkit2工具,将前面的vit-b-16.txt.fp16.onnx和vit-b-16.img.fp16.onnx模型文件转换成rknn模型, 参考前面CLIP的转换程序,并简单修改。

convert_cn_clip_text.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 省略.............

if __name__ == '__main__':
    model_path, platform, do_quant, output_path = parse_arg()

    # Create RKNN object
    rknn = RKNN(verbose=False)

    # Pre-process config
    print('--> Config model')
    rknn.config(target_platform=platform)
    print('done')

    # Load model
    print('--> Loading model')
    ret = rknn.load_onnx(model=model_path)
    if ret != 0:
        print('Load model failed!')
        exit(ret)
    print('done')

    # 省略.............

convert_cn_clip_text.py将vit-b-16.txt.fp16.onnx文本侧模型转换成rknn。

convert_cn_clip_images.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 省略.............
if __name__ == '__main__':
    model_path, platform, do_quant, output_path = parse_arg()

    # Create RKNN object
    rknn = RKNN(verbose=False)

    # Pre-process config
    print('--> Config model')
    rknn.config(target_platform=platform,
                mean_values=[[0.48145466*255, 0.4578275*255, 0.40821073*255]],
                std_values=[[0.26862954*255, 0.26130258*255, 0.27577711*255]])
    print('done')

    # Load model
    print('--> Loading model')
    ret = rknn.load_onnx(model=model_path)
    if ret != 0:
        print('Load model failed!')
        exit(ret)
    print('done')

    # Build model
    print('--> Building model')
    ret = rknn.build(do_quantization=do_quant)
    if ret != 0:
        print('Build model failed!')
        exit(ret)
    print('done')

    # 省略.............

convert_cn_clip_images.py将vit-b-16.img.fp16.onnx图像侧模型转换成rknn, 需要注意图像侧模型设置batch固定大小为1,分辨率为224*224。

# 切换到toolkit2环境,然后执行程序,转换模型
#
# Usage: python3 convert_cn_clip_text.py onnx_model_path [platform] [dtype(optional)] [output_rknn_path(optional)]
# 运行文本侧模型转换程序,测试lubancat-4/5指定平台rk3588,lubancat-3设置rk3576等等,指定最后导出的rknn模型路径等
(toolkit2_2.3) llh@llh:/xxx/clip$ python convert_cn_clip_text.py ./vit-b-16.txt.fp16.onnx rk3588 fp  ./vit-b-16.txt.rknn
I rknn-toolkit2 version: 2.3.0
--> Config model
done
--> Loading model
I Loading : 100%|███████████████████████████████████████████████| 198/198 [00:00<00:00, 4121.31it/s]
W load_onnx: Please note that some float16/float64 data types in the model have been modified to float32!
done
--> Building model
I OpFusing 0: 100%|██████████████████████████████████████████████| 100/100 [00:00<00:00, 260.97it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 99.85it/s]
I OpFusing 0 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 61.78it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 61.35it/s]
I OpFusing 2 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 60.14it/s]
I OpFusing 0 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 59.06it/s]
I OpFusing 1 : 100%|██████████████████████████████████████████████| 100/100 [00:01<00:00, 58.33it/s]
I OpFusing 2 : 100%|██████████████████████████████████████████████| 100/100 [00:02<00:00, 47.60it/s]
I rknn building ...
I rknn building done.
done
--> Export rknn model
done

# 运行图像侧模型转换程序,测试lubancat-4/5指定平台rk3588,lubancat-3设置rk3576等等,指定最后导出的rknn模型路径等
(toolkit2_2.3) llh@llh:/xxx/clip$ python convert_cn_clip_images.py ./vit-b-16.img.fp16.onnx rk3588 fp  ./vit-b-16.img.rknn

在toolkit2环境中执行程序,将在当前目录下生成vit-b-16.img.rknn和vit-b-16.txt.rknn模型文件。

15.3.3. 部署测试Chinese-CLIP模型

获取部署例程,Chinese-CLIP模型部署例程和前面部署CLIP例程在一个工程中。

git clone https://gitee.com/LubanCat/lubancat_ai_manual_code

板卡上直接编译例程(教程测试lubancat-4):

sudo apt update
sudo apt install libboost-all-dev

# 复制前面转换出的rknn模型到model目录下
# 切换到例程目录
cd lubancat_ai_manual_code/examples/clip/cpp
# 编译
cat@lubancat:~/xxx/clip$ ./build-linux.sh -t rk3588

生成的可执行文件在install/rk3588_linux目录下,执行程序cn_clip_demo:

./clip_demo <image_model_path> <image_path> <text_model_path> <text_path>
# 第一个参数指rknn图像侧模型,第二个参数是输入的图像,第三个参数是rknn文本侧模型,第四个参数是输入文本
cat@lubancat:~/xxx/install/rk3588_linux$ ./cn_clip_demo  ./model/vit-b-16.img.rknn ./model/pokemon.jpg  ./model/vit-b-16.txt.rknn ./model/cn_text.txt
--> init cn_clip image model
model input num: 1, output num: 1
input tensors:
index=0, name=image, n_dims=4, dims=[1, 224, 224, 3], n_elems=150528, size=301056, fmt=NHWC, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
output tensors:
index=0, name=unnorm_image_features, n_dims=2, dims=[1, 512], n_elems=512, size=1024, fmt=UNDEFINED, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
model is NHWC input fmt
input image height=224, input image width=224, input image channel=3
--> init cn_clip text model
model input num: 1, output num: 1
input tensors:
index=0, name=text, n_dims=2, dims=[1, 52], n_elems=52, size=416, fmt=UNDEFINED, type=INT64, qnt_type=AFFINE, zp=0, scale=1.000000
output tensors:
index=0, name=unnorm_text_features, n_dims=2, dims=[1, 512], n_elems=512, size=1024, fmt=UNDEFINED, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
model is UNDEFINED input fmt
input text batch size=1, input sequence length=52
origin size=224x224 crop size=224x224
input image: 224 x 224, subsampling: 4:2:0, colorspace: YCbCr, orientation: 1
--> inference cn_clip image model
rga_api version 1.10.1_[0]
rknn_run
--> inference cn_clip text model
--> rknn clip demo result
images: ./model/pokemon.jpg
text  : 皮卡丘
score : 1.000

# 测试有小狗的照片
cat@lubancat:~/xxx/install/rk3588_linux$ ./cn_clip_demo  ./model/vit-b-16.img.rknn ./model/dog_224x224.jpg ./model/vit-b-16.txt.rknn ./model/cn_text.txt
--> init cn_clip image model
model input num: 1, output num: 1
input tensors:
index=0, name=image, n_dims=4, dims=[1, 224, 224, 3], n_elems=150528, size=301056, fmt=NHWC, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
output tensors:
index=0, name=unnorm_image_features, n_dims=2, dims=[1, 512], n_elems=512, size=1024, fmt=UNDEFINED, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
model is NHWC input fmt
input image height=224, input image width=224, input image channel=3
--> init cn_clip text model
model input num: 1, output num: 1
input tensors:
index=0, name=text, n_dims=2, dims=[1, 52], n_elems=52, size=416, fmt=UNDEFINED, type=INT64, qnt_type=AFFINE, zp=0, scale=1.000000
output tensors:
index=0, name=unnorm_text_features, n_dims=2, dims=[1, 512], n_elems=512, size=1024, fmt=UNDEFINED, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
model is UNDEFINED input fmt
input text batch size=1, input sequence length=52
origin size=224x224 crop size=224x224
input image: 224 x 224, subsampling: 4:2:0, colorspace: YCbCr, orientation: 1
num_lines=6
--> inference cn_clip image model
rga_api version 1.10.1_[0]
--> inference cn_clip text model
--> rknn CN_CLIP demo result
images: ./model/dog_224x224.jpg
text  : 狗狗
score : 1.000

以上就是在lubancat上简单部署Chinese-CLIP模型,详情请查看配套例程,可自行修改优化。