一、CLIP介绍
CLIP(Contrastive Language-Image Pre-training)模型是一种通过自然语言监督来学习可迁移视觉模型的方法。CLIP模型利用海量的图像和相关文本数据对图像编码器和文本编码器进行联合训练,目标是最大化图像和文本对的余弦相似性。通过这种训练方法,CLIP能够在没有针对特定任务训练的情况下(零样本学习),对多种视觉任务进行有效的预测。
CLIP代码链接
CLIP(Contrastive Language-Image Pre-training)模型的技术路线包含以下几个核心方面:
- 数据集构建:
CLIP模型的训练基于一个包含约4亿对图像和文本的大规模数据集。这些数据对从互联网收集而来,涵盖了极其丰富的视觉内容和对应的自然语言描述。这样广泛的数据覆盖确保了模型能够接触到多样的视觉概念和语言表达,为后续的模型训练奠定了基础。
- 对比学习:
CLIP通过对比学习框架来进行训练,即通过最大化匹配的图像和文本对的相似度同时最小化不匹配对的相似度。具体来说,模型使用余弦相似性来度量图像和文本之间的匹配程度,并通过对比损失函数来优化模型参数,使得正确的图像-文本对相似度高于错误对。
- 双编码器架构:
CLIP模型包括两个主要组件:图像编码器和文本编码器。图像编码器负责将输入图像转换为高维特征向量;文本编码器则将文本描述转换为同维度的向量。这两个编码器通常使用神经网络实现,如ResNet或Transformer模型。
- 零样本学习能力:
在预训练结束后,CLIP能够直接利用训练好的文本编码器生成新的类别描述的特征,与图像特征进行匹配,实现零样本分类。这意味着CLIP可以在没有额外训练数据的情况下,直接根据文本描述进行图像分类或其他视觉任务。
- 跨任务迁移能力:
由于CLIP在训练时不依赖于特定任务的标注,其学习到的视觉表示具有很强的通用性和迁移能力。这使得CLIP可以在多种视觉任务上表现出色,包括但不限于对象识别、场景分类、动作识别等。
- 效率和性能:
CLIP的训练和应用都显示出较高的效率。在多个标准视觉任务上,CLIP与专门为特定任务训练的模型相比,展示了竞争性的或更优的性能,而且常常不需要针对特定数据集的再训练或微调。
二、代码实现
2.1代码思路
- 图像和文本的预处理
图像预处理
-
功能:图像预处理的主要目的是将图像数据标准化,确保输入到模型的图像具有一致的大小和类型格式,以便模型能够正确解析和处理图像数据。
-
操作步骤:
尺寸调整:CLIP模型要求输入图像具有特定的尺寸(如224x224像素),预处理函数会将所有图像调整到这一尺寸。
颜色转换:将图像从其原始颜色空间(如RGBA)转换到RGB,因为CLIP模型是在RGB图像上训练的。
归一化:对图像的像素值进行归一化处理,通常是使其均值为0,标准差为1。这有助于模型更快地收敛,提高训练稳定性。
文本预处理
-
功能:文本预处理确保文本数据被正确分词、编码,转换成模型能够理解的格式。
-
操作步骤:
分词:使用CLIP的内置tokenize函数,将一串文本分解成单独的词汇或符号。
编码:将分词后的文本转换为模型能接受的数值ID。
填充或截断:确保所有文本序列长度一致,以满足模型输入要求。
- 特征提取
图像特征
-
处理流程:图像数据通过CLIP的图像编码器部分(一个预训练的Vision Transformer或ResNet模型)处理,转换成高维的特征向量。
-
归一化:对特征向量进行归一化(L2归一化),确保特征向量的长度为1,这样相似度计算将只基于向量之间的角度差异。
文本特征
-
处理流程:同样,文本数据通过CLIP的文本编码器(基于Transformer的模型)处理,每个标记或词被映射到高维空间以形成特征向量。
-
归一化:文本特征向量也进行L2归一化,以便与图像特征在同一度量空间比较。
- 相似度计算
- 内积:归一化后的图像和文本特征向量通过计算内积(点积)来衡量相似度。因为向量已归一化,所以内积结果反映了两个向量之间的余弦相似度,即它们之间的夹角。
- 可视化相似度矩阵
-
生成热图:使用matplotlib生成热图,其中横坐标表示不同的图像,纵坐标表示不同的文本描述。每个格子的颜色深浅代表了对应图像和文本之间的相似度,颜色越深表示相似度越高。
-
视觉表示:这种可视化方法直观地展示了模型是如何理解和关联图像与文本的。
- 保存与展示结果
-
保存图像:热图被保存为PNG文件,以便于文档记录或进一步分析。
-
显示图像:同时,热图在屏幕上显示,允许用户直接观察和分析模型输出的相似度结果。
2.2完整代码
import os
from PIL import Image
import numpy as np
import torch
import clip
import matplotlib.pyplot as plt
# 加载 CLIP 模型
model, preprocess = clip.load("ViT-B/32")
# print(model)
model.cuda().eval()
# 准备你的图像和文本
your_image_folder = "img" # 替换为你的图像文件夹路径
your_texts = ["plates with knives"] # 替换为你的文本列表
images = []
for filename in os.listdir(your_image_folder):
if filename.endswith(".png") or filename.endswith(".jpg"):
path = os.path.join(your_image_folder, filename)
image = Image.open(path).convert("RGB")
images.append(preprocess(image))
# 图像和文本预处理
image_input = torch.tensor(np.stack(images)).cuda()
text_tokens = clip.tokenize(your_texts).cuda()
# 计算特征
with torch.no_grad():
image_features = model.encode_image(image_input).float()
text_features = model.encode_text(text_tokens).float()
# 计算相似度
image_features /= image_features.norm(dim=-1, keepdim=True)
text_features /= text_features.norm(dim=-1, keepdim=True)
similarity = (text_features.cpu().numpy() @ image_features.cpu().numpy().T)
print('similarity:',similarity)
# 可视化相似度
plt.imshow(similarity, cmap="hot", interpolation="nearest")
plt.colorbar()
plt.xlabel("Images")
plt.ylabel("Texts")
plt.title("Similarity between Texts and Images")
plt.xticks(range(len(images)), range(len(images)), rotation=90)
plt.yticks(range(len(your_texts)), your_texts, rotation='vertical', va='center') # 设置标签竖向显示并居中
# 保存图像到文件
plt.savefig("similarity.png", bbox_inches='tight') # 确保所有内容都在保存的图片里
# 显示图像
plt.show()
2.3运行结果
我们比较了文本 plates with knives 和以下三幅图片之间的相似度:
得到的相似度结果如下:
similarity: [[0.29848784 0.19507146 0.21618465]]
将相似度结果进行可视化后的图片如下: