【计算机视觉】如何利用 CLIP 做简单的图像分类任务?(含源代码)

要使用 CLIP 模型进行预测,您可以按照以下步骤进行操作:

一、安装

安装依赖:首先,您需要安装相应的依赖项。您可以使用 Python 包管理器(如 pip )安装 OpenAICLIP 库。

pip install git+https://github.com/openai/CLIP.git

在这里插入图片描述

二、代码解读

2.1 代码逐行构建过程

import clip
import torch
from PIL import Image

导入所需的库,包括 clip(用于加载和使用 CLIP 模型)、torchPyTorch 框架)和 PIL(用于图像处理)。

img_pah = '1.png'
classes = ['person', 'not_person']

设置输入图像的路径 img_path 和标签类别列表 classes。在这个示例中,类别列表包含了两个类别:‘person’‘not_person’

device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load('ViT-B/32', device)

根据是否可用 GPU,将设备设置为 “cuda”“cpu” 。然后,使用 CLIP 库中的 clip.load() 方法加载预训练的 ViT-B/32 模型,并返回加载的模型 model 和预处理函数 preprocess

image = Image.open(img_pah)
image_input = preprocess(image).unsqueeze(0).to(device)
text_inputs = torch.cat([clip.tokenize(f"a photo of a {
      
      c}") for c in classes]).to(device)

打开图像文件并使用预处理函数 preprocess 对图像进行预处理。然后,将预处理后的图像转换为模型所需的格式,并将其移动到设备上(GPUCPU)。对于文本输入,使用类别列表 classes 生成对应的文字描述,并使用 clip.tokenize() 函数对文字描述进行处理。

with torch.no_grad():
    image_features = model.encode_image(image_input)
    text_features = model.encode_text(text_inputs)

在不进行梯度计算的上下文中,使用 CLIP 模型的 encode_image() 方法对图像进行特征编码,得到图像特征 image_features 。同时,使用 encode_text() 方法对文本进行特征编码,得到文本特征 text_features

image_features /= image_features.norm(dim=-1, keepdim=True)
text_features /= text_features.norm(dim=-1, keepdim=True)
similarity = (100.0 * image_features @ text_features.T).softmax(dim=-1)
values, indices = similarity[0].topk(1)

对图像特征和文本特征进行归一化处理,以便计算它们之间的相似度。然后,使用矩阵乘法计算图像特征和文本特征之间的相似度矩阵。接下来,对相似度矩阵进行 softmax 归一化处理,得到相似度分数。最后,找到相似度分数中最高的值和对应的索引。

print("\nTop predictions:\n")
print('classes:{} score:{:.2f}'.format(classes[indices.item()], values.item()))

打印输出结果,显示预测的最高分数和对应的类别标签。

2.2 源代码 + 运行结果

import clip
import torch
from PIL import Image

img_pah = '1.png'
classes = ['person', 'not_person']

# 加载模型
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load('ViT-B/32', device)


# 准备输入集
image = Image.open(img_pah)
image_input = preprocess(image).unsqueeze(0).to(device)
text_inputs = torch.cat([clip.tokenize(f"a photo of a {
      
      c}") for c in classes]).to(device) #生成文字描述

# 特征编码
with torch.no_grad():
    image_features = model.encode_image(image_input)
    text_features = model.encode_text(text_inputs)

# 选取参数最高的标签
image_features /= image_features.norm(dim=-1, keepdim=True)
text_features /= text_features.norm(dim=-1, keepdim=True)
similarity = (100.0 * image_features @ text_features.T).softmax(dim=-1) #对图像描述和图像特征  
values, indices = similarity[0].topk(1)

# 输出结果
print("\nTop predictions:\n")
print('classes:{} score:{:.2f}'.format(classes[indices.item()], values.item()))

运行结果为:

Top predictions:

classes:person score:0.81

2.3 细节补充

2.3.1 clip.load()

clip.load() 方法中,可以调用多个预训练的 CLIP 模型。以下是一些常用的 CLIP 模型名称:

  • ViT-B/32: Vision Transformer 模型,基于 ImageNet 预训练的 ViT-B/32
  • RN50: ResNet-50 模型,基于 ImageNet 预训练的 ResNet-50
  • RN101: ResNet-101 模型,基于 ImageNet 预训练的 ResNet-101
  • RN50x4: ResNet-50 模型的扩展版本,使用更大的 batch size 进行训练。
  • RN50x16: ResNet-50 模型的更大版本,使用更大的 batch size 进行训练。

以上列出的是一些常用的预训练模型,但并不是全部可用的模型列表。CLIP 库还提供其他模型和变体,您可以在官方文档中查找完整的模型列表,并根据您的需要选择适合的预训练模型。

请注意,选择不同的预训练模型可能会影响性能和计算资源的要求。较大的模型通常具有更多的参数和更高的计算成本,但可能具有更好的性能。因此,根据您的具体应用场景和可用资源,选择适当的预训练模型进行调用。

2.3.2 preprocess()

preprocessCLIP 库中提供的预处理函数之一,用于对图像进行预处理以符合 CLIP 模型的输入要求。下面是 preprocess 函数的一般步骤和说明:

  • 图像的缩放:首先,图像会被缩放到指定的大小。通常情况下,CLIP 模型要求输入图像的尺寸是正方形的,例如 224x224 像素。所以,在预处理过程中,图像会被调整为适当的尺寸。
  • 像素值归一化:接下来,图像的像素值会被归一化到特定的范围。CLIP 模型通常要求输入图像的像素值在 0 到 1 之间,因此预处理过程中会将像素值归一化到这个范围。
  • 通道的标准化:CLIP 模型对图像通道的顺序和均值标准差要求是固定的。因此,预处理过程中会对图像的通道进行重新排列,并进行标准化。具体来说,通常是将图像的通道顺序从 RGB(红绿蓝)调整为 BGR(蓝绿红),并对每个通道进行均值标准化。
  • 转换为张量:最后,经过预处理的图像会被转换为张量形式,以便于传递给 CLIP 模型进行计算。这通常涉及将图像的维度进行调整,例如从形状为 (H, W, C) 的图像转换为形状为 (C, H, W) 的张量。

总之,preprocess 函数负责将输入的图像进行缩放、归一化和格式转换,以使其符合 CLIP 模型的输入要求。具体的预处理操作可能因 CLIP 模型的不同版本而有所差异,建议参考 CLIP 库的官方文档或源代码以获得更详细的预处理细节。

2.3.3 unsqueeze

PyTorch 中,unsqueeze() 是一个张量的方法,用于在指定的维度上扩展维度。

具体而言,unsqueeze(dim) 的作用是在给定的 dim 维度上增加一个维度。这个操作会使得原始张量的形状发生变化。

以下是 unsqueeze(dim) 的详细解释:

  • 参数 dim:表示要在哪个维度上进行扩展。可以是一个整数或一个元组来指定多个维度。通常, dim 的取值范围是从 0 到 tensor.dim()(即张量的维度数)。
  • 返回值:返回一个新的张量,与原始张量共享数据内存,但形状发生了变化。

示例:

import torch

# 原始张量形状为 (2, 3)
x = torch.tensor([[1, 2, 3], [4, 5, 6]])

# 在维度0上扩展维度,结果形状为 (1, 2, 3)
y = x.unsqueeze(0)

# 在维度1上扩展维度,结果形状为 (2, 1, 3)
z = x.unsqueeze(1)

在上述示例中,原始张量 x 的形状为 (2, 3)。通过调用 unsqueeze() 方法并传递不同的维度参数,我们可以在指定的维度上扩展维度。结果张量 y 在维度0上扩展维度,形状变为 (1, 2, 3);结果张量 z 在维度1上扩展维度,形状变为 (2, 1, 3)。

通过使用 unsqueeze() 方法,我们可以改变张量的形状,以适应不同的计算需求和操作要求。

猜你喜欢

转载自blog.csdn.net/wzk4869/article/details/130679770