OpenAI 在 2021 年提出了 CLIP(Contrastive Language–Image Pretraining)算法,这是一个先进的机器学习模型,旨在理解和解释图像和文本之间的关系。CLIP 的核心思想是通过大规模的图像和文本对进行训练,学习图像内容与自然语言描述之间的对应关系。这种方法使得模型能够在没有特定任务训练的情况下,对广泛的视觉概念进行理解和分类。
OpenAI 的 CLIP(Contrastive Language–Image Pretraining)算法是在多模态学习领域的一个重要发展,而要理解其历史发展,首先需要明确“模态”的含义及其在人工智能中的应用。
在人工智能和计算机科学中,“模态”(Modality)通常指的是不同类型的数据或通信方式。常见的模态包括文本、图像、视频、音频等。每种模态具有独特的特性和处理方式。
多模态学习涉及同时使用和分析多种不同类型的数据(即多种模态)。例如,一个多模态系统可能会同时处理图像和文本信息,以更全面地理解和解释内容。
OpenAI CLIP 模型并不是最初为 GPT(Generative Pretrained Transformer)设计的。虽然 CLIP 和 GPT 都是 OpenAI 开发的模型,但它们是针对不同用途和应用场景设计的。
OpenAI 的 CLIP(Contrastive Language–Image Pretraining)模型是在一个非常大的图像-文本对数据集上训练的。具体来说,据 OpenAI 的原始论文所述,CLIP 是在一个包含约4亿个图像-文本对的数据集上进行训练的。
这个数据集的规模是其显著特点之一,它使得模型能够学习并理解广泛的视觉概念和自然语言描述。大规模的数据集对于训练如 CLIP 这样的多模态模型来说至关重要,因为它们提供了足够的样本来捕捉和理解图像内容和相关文本之间复杂的关系。
随着技术发展,现在已经超过论文所述4亿对。
CLIP(Contrastive Language–Image Pretraining)模型实现监督信息的方式是通过对比学习。这是一种自监督学习方法,不需要传统的标注数据集。 CLIP 的基本工作原理:
通过图像编码器生成一个向量,每个文本
通过文本编码器生成一个向量。
,同时最小化与错误配对的点积
。
,正确的配对被视为正样本,而该图像与数据集中其他所有文本
的配对被视为负样本。
通过这种方式,CLIP 可以在没有显式标注的情况下学习图像内容与文本描述之间的语义关系。训练完成后,CLIP 能够根据其文本描述识别图像,或者根据图像内容找到合适的文本标签。这种方法的优势在于其能够处理开放式任务,并对未见过的图像和文本描述具有较好的泛化能力。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision.models import resnet50
from transformers import BertTokenizer, BertModel
# 假设你已经有一个包含图像和文本对的 Dataset
class YourDataset(torch.utils.data.Dataset):
# 初始化方法,加载数据等
# 返回数据集大小
# 获取单个样本的方法
# 定义图像编码器
class ImageEncoder(nn.Module):
def __init__(self):
super(ImageEncoder, self).__init__()
# 使用预训练的ResNet50作为图像编码器
self.resnet = resnet50(pretrained=True)
self.resnet.fc = nn.Linear(self.resnet.fc.in_features, 512) # 假设我们的特征空间大小为512
def forward(self, images):
return self.resnet(images)
# 定义文本编码器
class TextEncoder(nn.Module):
def __init__(self):
super(TextEncoder, self).__init__()
# 使用预训练的BERT作为文本编码器
self.bert = BertModel.from_pretrained('bert-base-uncased')
self.linear = nn.Linear(self.bert.config.hidden_size, 512) # 假设我们的特征空间大小为512
def forward(self, input_ids, attention_mask):
outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
pooled_output = outputs.pooler_output
return self.linear(pooled_output)
# 对比损失函数
class ContrastiveLoss(nn.Module):
def forward(self, image_features, text_features):
# 计算图像和文本特征之间的相似度
logits = image_features @ text_features.T
# 使用温度缩放 softmax
temperature = 0.07
logits = logits / temperature
# 对角线元素是正样本对的相似度
labels = torch.arange(logits.size(0)).to(logits.device)
loss = nn.CrossEntropyLoss()(logits, labels)
return loss
# 实例化模型和损失函数
image_encoder = ImageEncoder()
text_encoder = TextEncoder()
contrastive_loss = ContrastiveLoss()
# 优化器
params = list(image_encoder.parameters()) + list(text_encoder.parameters())
optimizer = optim.Adam(params, lr=1e-4)
# 数据加载器
dataset = YourDataset()
data_loader = DataLoader(dataset, batch_size=32, shuffle=True)
# 训练循环
for epoch in range(num_epochs):
for images, texts in data_loader:
# 对图像和文本进行编码
image_features = image_encoder(images)
input_ids, attention_mask = texts # 假设这些是经过BERT Tokenizer处理的文本
text_features = text_encoder(input_ids, attention_mask)
# 计算对比损失
loss = contrastive_loss(image_features, text_features)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f"Epoch {epoch}: Loss {loss.item()}")
注意:这个代码提供了一个高级概述,并没有涉及一些实际实现中的细节,比如数据预处理、设备管理(CPU/GPU)、模型保存和加载、评估逻辑等。
可以考虑使用 OpenAI 发布的官方代码库或者像 transformers 这样的第三方库,它们提供了预训练的 CLIP 模型和方便的接口。
在构建多模态模型如 CLIP 时,可以使用多种方法来衡量图像表示和文本表示之间的相似度。两种常用的方法是点积(dot product)和余弦相似度(cosine similarity)。
点积直接计算两个向量的对应元素的乘积之和。如果两个向量在相同维度的数值都很大且符号相同(即都是正数或都是负数),它们的点积就会很大。
余弦相似度是通过测量两个向量之间的夹角的余弦值来确定它们之间的相似度。计算公式为两个向量的点积除以它们各自范数(norm)的乘积。这样,余弦相似度主要关注向量的方向而不是其大小。
在结合 CLIP 架构时,可以采取以下步骤:
OpenAI 只是开源了 CLIP 模型的权重,并没有开源对应的 4 亿图文对。后来的学者便开始复现 OpenAI 的工作。比较有代表性的工作包括 OpenCLIP、ChineseCLIP 和 EVA-CLIP。
https://modelscope.cn/studios/damo/chinese_clip_applications/summary