目录
第二课区分了分类、图文对齐和视觉自监督,这一课把图文对齐单独展开:一张猫的照片和一句“a photo of a cat”,原本分别是像素与字符,怎样才能计算它们是否匹配?
CLIP 不需要先把图片翻译成一句话,而是分别编码图片与文字,将它们变成可以比较的向量,再通过大量图文配对学习这种比较方式。[1]
1、先把训练想成一个配对游戏
桌上有三张图片:猫、狗、自行车;旁边放着三段对应描述。每次训练,模型要给每张图片选描述,也给每段描述选图片,选错时调整参数,下次再试。
如果按配对顺序排列,正确答案就落在下表的对角线上。其他格子不是人类逐个标注的错误描述,而是从同一批数据中构造出来的竞争候选。
| 图片 \ 描述 | 猫的照片 | 狗的照片 | 自行车的照片 |
|---|---|---|---|
| 猫 | 正确配对 | 候选 | 候选 |
| 狗 | 候选 | 正确配对 | 候选 |
| 自行车 | 候选 | 候选 | 正确配对 |
训练希望正确配对的分数比竞争候选更高,并不要求每一对不匹配图文的相似度都变成零。
现实里可能有两张猫图、重复描述或不完整的文字,因此同批的“负例”不一定都在语义上错误。这种噪声和假负例也是理解对比学习时需要记住的边界。
2、共同空间怎样建立?
2.1 两个编码器,各自提取特征
图片经过视觉编码器得到全图特征,文字经过文本编码器得到句子特征,再由各自的投影层映射到相同宽度。图中的长度为教学示意,实际维度取决于模型配置。
图片编码器和文字编码器不需要共享参数;“共同空间”指它们的最终表示可以按同一规则比较,而不是内部结构或每个隐藏维度都相同。
2.2 相同维度只是接口条件
两位同学各写一张六列的表,并不意味着每一列记录同一种东西。类似地,把图像与文字都投影到 $d$ 维,只解决了形状问题,训练中的配对信号才逐渐让它们形成有用的对应关系。
设图像编码器与投影得到 $u_i$,文本编码器与投影得到 $w_j$,先把向量归一化:
\[v_i=\frac{u_i}{\|u_i\|_2},\qquad t_j=\frac{w_j}{\|w_j\|_2}\]归一化后长度都是 1,点积 $v_i^Tt_j$ 就是余弦相似度,比较的是方向而不是向量长度。“接近”因此是这套表示中的相似,不代表所有人类理解的语义关系都被完整保留。
3、配对关系怎样变成损失?
3.1 先算一张分数表
一批有 $B$ 对图文,图像和文字特征的形状均为 [B,d],将两者相乘得到 [B,B] 的分数矩阵:
第 $i$ 行表示“这张图与各段描述有多匹配”,第 $j$ 列则表示“这段描述与各张图有多匹配”;$\tau>0$ 是温度,官方实现通过可学习的对数尺度参数构造它的倒数。[2]
3.2 对每一行选正确描述,再对每一列选正确图片
以一行示意 logits [2,1,0] 为例,softmax 后约为 [0.665,0.245,0.090]。如果第一项是正确配对,损失为 $-\log(0.665)\approx0.408$;正确项概率越大,这个损失越小。
这就是常见的 InfoNCE 风格对比目标在图像找文字方向上的形式:分子是正确配对,分母包含全部候选。转置分数表后,对文字找图片再算一次交叉熵,最后取平均:
\[L_{text}=-\frac1B\sum_{j=1}^{B}\log\frac{\exp(S_{jj})}{\sum_{i=1}^{B}\exp(S_{ij})},\qquad L=\frac{L_{image}+L_{text}}2\]梯度会沿分数计算、投影层和编码器往回传,使模型逐渐改善配对结果。两个编码器不是先各自训练完,再靠一个固定规则自动获得语义对齐。
3.3 温度改变什么?
对同一组相似度,较小的温度会放大 logits 差异,让 softmax 更尖锐。例如 [0.6,0.3,0] 在 $\tau=1$ 时约为 [0.437,0.324,0.240],在 $\tau=0.1$ 时约为 [0.950,0.047,0.002]。
固定特征时,这种正比例缩放不会改变候选排序,却会改变概率分布与训练梯度;如果最高分恰好是错误答案,也会让模型更加确信错误,所以温度不是越小越好。
4、用最小代码算一次 CLIP 损失
下面用手工向量演示归一化、分数矩阵和双向交叉熵,省去图片加载与编码器。它能在安装了 PyTorch 的环境运行,但不是完整的 CLIP 训练,也不代表真实特征。
import torch
import torch.nn.functional as F
image_features = torch.tensor([
[1.0, 0.0], [0.0, 1.0], [-1.0, 0.0]
], requires_grad=True)
text_features = torch.tensor([
[0.9, 0.1], [0.1, 0.9], [-0.9, 0.1]
], requires_grad=True)
v = F.normalize(image_features, dim=-1)
t = F.normalize(text_features, dim=-1)
tau = 0.1
logits = v @ t.T / tau # [3, 3]
labels = torch.arange(3) # 正确配对位于对角线
loss_image = F.cross_entropy(logits, labels)
loss_text = F.cross_entropy(logits.T, labels)
loss = (loss_image + loss_text) / 2
loss.backward()
print(logits.detach().round(decimals=2))
print(round(loss.item(), 4)) # 约 0.0002
这里特意使用相互匹配的方向,所以损失很小。可以交换两行文字向量再计算,观察配对顺序错误如何增大损失;真实训练中还需要优化器更新编码器、投影层与尺度参数。
有两个常见错误:不做归一化会把向量长度混入打分;先 softmax 再传入 cross_entropy 会重复处理,因为这个函数期望接收 logits,内部已经包含 log-softmax。
5、零样本分类为什么不需要另训分类头?
训练时学会图文比较后,可以把类别写成描述,让文字编码器为每个类别生成一个向量,再拿待分类图片与这些向量逐一比较。比如候选类别是猫、狗和自行车,分别构造 “a photo of a cat”、 “a photo of a dog”、 “a photo of a bicycle”。
\[\widehat y=\arg\max_c v_{image}^Tt_{prompt(c)}\]这相当于用文本特征临时构造分类器,不需要在当前目标数据集上额外训练一个类别头。“零样本”指这次迁移没有用目标任务标签做训练,并不说明模型从未见过相关概念,也不意味着能识别所有新类别。
官方实现提供了图像预处理、文本分词与特征提取接口,使用时应成套使用同一个模型的两路编码器。[2]
提示语会影响文本表示,换描述、补上下文或对多个模板的特征做聚合,都可能改变效果;需要在固定评价数据上验证,而不是只选一个看起来效果好的示例。
6、容易混淆的事与一个小实验
| 容易误解的地方 | 更准确的理解 |
|---|---|
| CLIP 会给图片生成描述 | 基础 CLIP 比较图文向量,没有自回归文本生成器 |
| 相同维度就能比较语义 | 还要有共同训练、正确投影和归一化 |
| softmax 得到的是客观置信度 | 它依赖候选集合与尺度,不是自动校准的可信度 |
| 同批其他图文都是错误配对 | 重复主体与描述会产生假负例 |
| 图文相似度高就证明细节正确 | 整体语义匹配不能替代定位、计数或时间证据 |
可以挑一组图片,先做固定候选的零样本分类,再将某个类别提示改得更具体,记录结果变化。接着加入一个新的候选类别,观察原有候选的 softmax 概率变化;这个实验能直观看到“相对候选得分”与“客观置信度”的区别。
游戏截图中的遮挡、小目标和准星关系,往往超出一句整体描述能够表达的范围。CLIP 可作为检索或表示学习的起点,具体审核判断仍要用任务数据验证局部与时间证据。
7、把整条流程串起来
图像与文字分别编码,经过投影和归一化后进入可比较的空间;训练时,用一批图文构造分数表,提高正确配对的相对得分;使用时,再通过候选文本完成检索或零样本分类。
读完后,试着回答:为什么损失要算两个方向?减小温度为什么不改变固定特征的排序?新增候选类别时,原有类别的 softmax 概率为什么会变化?
下一课看 SigLIP:如果不在整批候选之间做 softmax,而是逐对判断是否匹配,训练目标会怎样变化?
8、参考文献(References)
- Radford, A., Kim, J. W., Hallacy, C., et al. “Learning Transferable Visual Models From Natural Language Supervision.” ICML, 2021. arXiv:2103.00020.↩
- OpenAI. “CLIP: Official Implementation.” GitHub repository, 2021. Accessed 2026-10-07.↩