架构演进 · 视觉与扩散
- 对比
- CLIP ViT-B/32 vs GPT-2 small
- 文本塔
- 12 × 512 · 因果 GPT-2 12 × 768
- 图像塔
- ViT-B/32 · 12 × 768 无
- 输出
- 1 个 512 维向量 GPT-2 50,257 个分数
- 上下文
- 77 个词元 GPT-2 1,024
- 参数
- 151M GPT-2 124M
全部步骤
两个编码器
CLIP 有两个编码器。文本编码器的形状像 GPT-2(因果,12 层),但输出的是一个向量(在文本结束词元处读取),而不是下一词元分数。图像编码器是一个视觉 Transformer。每个向量都投影到 512 维并缩放到长度 1。点击标签跳过去。
图像 → ViT → 512 · 文本 → Transformer → 512一个共享空间
这些是四张手绘图像及其说明文字的真实 CLIP 嵌入。在第一主成分上,所有图像在一侧,所有说明在另一侧(即所谓的 “modality gap”);在第二主成分上,爱心的图像和说明在一端,三角形的在另一端,而正方形和星形,无论图像还是说明,都挤在中间。
长度为 1 的向量 · 点积 = 余弦对比矩阵
训练时取一批图像–说明对,把每张图像与每段说明逐一计算:一次矩阵乘法。损失沿行和沿列把对角线(真正的配对)往上推,其余往下压。真实的 CLIP 数值;把鼠标停在格子上看看。
S = I · Tᵀ · 两个方向做 softmax零样本分类
因为标签只是文本,CLIP 不必为任务训练就能分类:为每个类别写一段说明,嵌入它们,再挑最相似的那个。CLIP 从没在这些图形上训练过,但这里八个答案全都对。
类别 = argmax cos(图像, “a photo of a …”)温度
原始余弦彼此很接近(0.2 到 0.4)。CLIP 在 softmax 之前把它们乘以一个学习得到的缩放系数,即温度的倒数。它从 14.3 开始,训练把它推到上限 100,把小差距变成有把握的答案。
softmax(100 · cos)
代码
# two encoders, one shared space
i = F.normalize(visual_projection(vit(images)[:, 0]), dim=-1) # (N, 512)
t = F.normalize(text_projection(text_tf(ids)[range(N), eot_pos]), dim=-1) # (N, 512)
# every image against every caption, scaled by the learned temperature
logits = logit_scale.exp() * i @ t.T # (N, N), scale capped at 100
labels = torch.arange(N) # the diagonal holds the true pairs
loss = (F.cross_entropy(logits, labels) + F.cross_entropy(logits.T, labels)) / 2
# zero-shot: one caption per class, pick the closest
classes = F.normalize(text_projection(text_tf(prompts)), dim=-1)
pred = (i @ classes.T).argmax(dim=-1)