要使用 CLIP 模型进行预测,您可以按照以下步骤进行操作:
一、安装
安装依赖:首先,您需要安装相应的依赖项。您可以使用 Python 包管理器(如 pip )安装 OpenAI 的 CLIP 库。
pip install git+https://github.com/openai/CLIP.git
二、代码解读
2.1 代码逐行构建过程
import clip
import torch
from PIL import Image
导入所需的库,包括 clip(用于加载和使用 CLIP 模型)、torch(PyTorch 框架)和 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 对图像进行预处理。然后,将预处理后的图像转换为模型所需的格式,并将其移动到设备上(GPU 或 CPU)。对于文本输入,使用类别列表 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()
preprocess 是 CLIP 库中提供的预处理函数之一,用于对图像进行预处理以符合 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() 方法,我们可以改变张量的形状,以适应不同的计算需求和操作要求。