CLIP:让图像与文字在同一个空间中互相检索
学术型精读 · 概念、公式、实验、源码与可验收练习
一句话总结
CLIP 用大规模图文配对训练两个编码器,再把类别写成文字进行零样本分类。读懂它需要区分对比训练、提示词分类、线性探测以及跨分布泛化。
任务变化:从固定类别到文字定义类别
传统图像分类器的最后一层通常绑定训练时的类别列表。CLIP 的思路是先学习“这张图和哪段文字相配”,然后在测试时把候选类别写成句子,比较图像与这些句子的相似度。新类别无需重新训练固定分类头,但仍然依赖候选名称、提示模板和预训练语料中获得的知识。
这篇论文使用约四亿对网络图像与文字进行训练。文字是自然语言监督,并非完全没有监督,也不是情绪标签。所谓零样本通常表示不使用目标数据集的标注训练分类器,不表示模型从未接触相关概念,更不保证网络预训练数据与测试图像绝无重叠。论文专门进行近重复检测,正是为了讨论这一问题。
Figure 1 展示三步:图文成对训练、用类别描述构造文本表示、图像与候选文本比较。Figure 3 的伪代码最值得逐行阅读,因为核心算法不复杂,很多误解来自把周边的大规模训练条件省略以后,仍把全部效果归因于一个相似度公式。
两个编码器如何在同一空间见面
图像编码器把像素映射到向量,文本编码器把描述映射到向量;两个向量再通过投影进入同一维度空间。图像分支可以是改进的残差网络或视觉 Transformer。文本分支使用带因果掩码的 Transformer,不能直接当作 BERT 的双向编码器。分支可以独立计算,这使预先缓存类别文本成为可能。
原论文文本模型使用序列末尾标记位置的表示。官方实现通过末尾标记的 token 编号定位它,随后做投影。这里不能随手换成平均全部 token 而仍称为原实现,也不能忽略 padding 与截断。公开代码的上下文窗口是七十七个 token,包含特殊标记;自然语言描述过长会触及长度约束。
投影后对图文向量做二范数归一化,使点积变为余弦相似度。这样比较的主要是方向,而非向量长度。学习到的温度缩放控制分类分布的尖锐程度:缩放越大,分数差异经过 softmax 后越明显。温度并不提供新的语义信息,也不让概率自动成为可靠的现实置信度。
一个批次包含若干真实配对,图像向量乘文本向量转置得到方阵。对角线是正确配对,其他位置被当作负例。图像到文本和文本到图像各计算一次交叉熵,再求平均。某些不同样本可能描述相同内容,却在批次中被当作负例,这是此类配对学习需要认识的假负例问题。
零样本分类与提示词
测试时把每个类别放进一个自然语言模板,例如表示照片及其对象。文本编码器得到每一类的向量,图像与各类向量比较,取最大分数。模型并没有先生成一句描述再从中抽取答案;它是在你提供的候选集合中选择。候选类别增加、名称改变或含义重叠,都可能改变最终结果。
Figure 4 说明提示词与模板集成会影响结果。作者报告在 ImageNet 上,使用模板相对直接类别名带来提升,多模板集成还能继续改进。这里的重要机制是让输入更接近预训练中常见的描述方式,并通过多个语境减少单一措辞的偶然性,而不是“找到某句神奇提示就获得任务知识”。
多个模板的文本向量需要按照明确规则归一化、平均并再归一化。对情绪类别尤其要谨慎:“愤怒的人”“愤怒的表情”和“充满愤怒的场景”不是同一观察对象。背景、姿态和面部肌肉可以提供不同线索。先写出标签操作性定义,再设计模板,才能知道模型到底在回答哪个问题。
零样本评估不应在目标测试集上反复挑选最优提示词。若依据目标域标签选择模板,需要明确记录这一监督使用情况。跨场景研究最好预先固定模板,或仅在源域验证集上选择,再到目标域一次评估。否则所谓跨域性能可能包含对目标集的适配收益。
哪些结果能说明什么
Table 1 的零样本 ImageNet 结果为 76.2,而 Table 10 的高性能线性探测结果可达到 85.4。后者在冻结特征上使用目标任务标注训练分类器,不是同一种零样本协议。很多介绍把这两个数字混在一起,导致读者误以为只输入类别文字就达到了线性探测的成绩。
Figure 13 与 Table 16 讨论自然分布变化。零样本 CLIP 在多个变化数据集上表现较强,但这些结果不意味着对任意医疗、工业或情绪场景都可靠。数据类型、任务定义、预训练覆盖与模型规模都在影响结果。原文还提醒比较模型之间不仅监督方式不同,训练数据与计算预算也不同。
本页第二张表使用 Table 16 的线性探测与零样本结果,显示同一预训练体系下评价方式改变后,ImageNet 与分布变化数据的相对表现会发生变化。ImageNet 更高并不保证每个偏移集合都更高。这对跨场景研究很重要:只优化源域分数可能改变特征对源域类别边界的依赖。
附录 Table 12 比较等规模 YFCC 与 WIT 子集。平均性能相近,并不代表每个细粒度任务都相近;鸟类、花卉、汽车等具体任务出现明显差异,作者将其与数据分布联系起来。这支持一个更实用的判断:迁移能力不仅取决于数据总量,还取决于相关概念在数据中出现得是否充分。
附录 Table 14 显示 OCR 能力并不均匀。零样本 MNIST 准确率为 88.4,甚至低于某些简单监督方法;不同文本图像任务差异很大。因此,CLIP 能识别部分文字并不等于具有统一可靠的文字识别能力。跨模态表征可能同时包含有用能力与明显盲点。
附录 Table 15 的视频线性评估使用单个中心帧,零样本设置则可以聚合多帧预测。论文明确提醒它们不能与完整视频方法无条件直接比较。这一点与情绪视频密切相关:静态帧的对象和姿态识别,不等于理解表情如何随时间变化。若把逐帧平均称为时序建模,论证就超出了实际计算。
数据重叠与偏差怎样理解
作者没有仅靠 CLIP 自身的语义相似度检测重复,因为同类物体可能被误判为同一图像,而不同缩放算法又可能降低近重复图像的相似度。附录 C 介绍另外训练的近重复检测器。检测结果可以帮助估计重叠影响,但检测器存在误差,因此不能把“做过检查”写成“绝不存在泄漏”。
Section 6 讨论细粒度任务、计数、分布外情况、评估集适配与数据偏差等限制。自然语言接口让模型灵活,也让类别描述影响输出。用于人脸和情绪时,应把“观察到表情外观”与“知道人的真实心理状态”分开;照片中笑并不必然说明当事人快乐,这是独立于模型精度的标签解释边界。
针对细粒度情绪,本页建议把 CLIP 当作一个可比较的视觉表示或文字原型来源。先建立固定提示的零样本基线,再比较冻结特征分类器,最后才考虑小规模微调。每个阶段对应不同监督资源,结果表应分栏。不要把使用大量目标标签的模型改进直接归功于零样本能力。
针对跨场景,重点检查背景与类别共现是否造成捷径。比如某类情绪总出现在室内近景,另一类总出现在舞台,模型可能主要识别场景。可用面部裁剪与整帧输入进行对照,但裁剪会同时改变视野和分辨率,解释时要保留这些条件,不能仅凭一次提升断定已经去除了全部背景偏差。
官方仓库主要发布推理代码和模型权重,并未提供原始四亿图文训练的完整流水线。代码中可核对编码、归一化、相似度和温度,但不能据此声称已经拥有原文全套训练复现。论文训练时描述对缩放的约束,当前前向函数只直接取指数;应区分训练规则与推理函数负责的工作。
公式逐步读:变量、运算与适用范围
教学整理:独立编码与投影
对应 Figure 3。两种模态先由各自编码器处理,再进入共同维度;不是逐词逐像素交叉注意力。
教学整理:归一化
归一化后点积取决于方向。实现时需考虑极小范数和精度,但不能随意更换作者的预处理。
教学整理:配对分数
t 是学习参数,指数保证缩放为正;它与直接把温度设为一个固定数的写法需要做倒数对应。
教学整理:双向损失
第一项给图找文字,第二项给文字找图。对角线标签只来自批次配对顺序,打乱一侧却不更新标签会破坏监督。
教学整理:零样本预测
候选类别在推理时由使用者定义。此表达为教学整理而非原论文编号公式;类别名称及模板属于评价配置。
实验读数:先固定协议,再比较数值
| 方法 | aYahoo | ImageNet | SUN |
|---|---|---|---|
| Visual N-Grams | 72.4 | 11.5 | 23.0 |
| CLIP | 98.4 | 76.2 | 58.5 |
| 方法 | ImageNet | ImageNet-V2 | ImageNet-A | ImageNet-R | ObjectNet |
|---|---|---|---|---|---|
| 线性探测 CLIP | 85.4 | 75.9 | 75.3 | 84.2 | 66.2 |
| 零样本 CLIP | 76.2 | 70.1 | 77.2 | 88.9 | 72.3 |
计算流程图
flowchart LR A[Image] --> B[Image encoder and projection] C[Paired text] --> D[Text encoder and projection] B --> E[Normalization and pairwise scores] D --> E E --> F[Symmetric contrastive loss] G[Class prompts at inference] --> D E --> H[Candidate class prediction]
沿图逐条检查箭头:每个箭头传递的是张量或监督信号,并不代表额外的数据集;训练目标旁的分支在部署时未必保留。建议先在纸上填入批大小、序列长度、通道数,再阅读下面的源码。一个模块即使名字相同,只要输入轴、掩码或输出使用方式改变,也不能直接视作同一个实验。
论文方法与固定版本源码对照
clip/model.py:343–356
def encode_text(self, text):
x = self.token_embedding(text).type(self.dtype) # [batch_size, n_ctx, d_model]
x = x + self.positional_embedding.type(self.dtype)
x = x.permute(1, 0, 2) # NLD -> LND
x = self.transformer(x)
x = x.permute(1, 0, 2) # LND -> NLD
x = self.ln_final(x).type(self.dtype)
# x.shape = [batch_size, n_ctx, transformer.width]
# take features from the eot embedding (eot_token is the highest number in each sequence)
x = x[torch.arange(x.shape[0]), text.argmax(dim=-1)] @ self.text_projection
return x文本分支经过 Transformer 后读取序列末尾位置并投影。这里使用末尾标记的索引约定,不能不检查词表就照搬到任意分词器。
clip/model.py:358–372
def forward(self, image, text):
image_features = self.encode_image(image)
text_features = self.encode_text(text)
# normalized features
image_features = image_features / image_features.norm(dim=1, keepdim=True)
text_features = text_features / text_features.norm(dim=1, keepdim=True)
# cosine similarity as logits
logit_scale = self.logit_scale.exp()
logits_per_image = logit_scale * image_features @ text_features.t()
logits_per_text = logits_per_image.t()
# shape = [global_batch_size, global_batch_size]
return logits_per_image, logits_per_text图像与文字特征分别归一化,logit_scale 取指数,矩阵乘法构成全部配对分数,转置得到反向分数。此处是前向推理,没有展示原始数据训练流水线。
代码核查固定在提交 d05afc436d78f1c48dc0dbf8e5980a9d471f35f6。这里展示的是公开仓库的实际文件,不把重新写的教学代码冒充作者实现。仓库后续可能包含新版本、工程兼容选项和不同默认参数;本文只将已核实的语句对应到论文机制。下载权重成功、模型能够前向传播、复现论文最终指标是三个不同的验收层级。
从读懂到能够独立实现:可执行学习任务
第一步,选取少量可合法使用的图像,固定三个候选类别和一个模板,保存原始余弦分数、缩放后的 logits 与最终预测。验收:能说明三者的关系,并验证改变共同正缩放不会改变单张图的最大分数类别,却会改变 softmax 的尖锐程度。
第二步,为同一类别编写对象、表情、场景三类描述,每类三种措辞。只在训练或验证样本上比较并固定模板。验收:保存全部模板及选择依据,不删除失败模板后只展示最好结果;解释模板究竟描述脸部动作还是推测内心状态。
第三步,对同一批图像比较整帧与面部裁剪,保持类别与模板不变。验收:至少列出十个预测改变的例子,区分背景信息被去除、脸部分辨率改变和裁剪失败,而不是把所有变化都解释为模型关注了表情。
第四步,建立零样本和冻结特征线性分类两条基线,记录使用标签的数量。验收:两者使用相同测试集合,但在结果表中明确监督条件不同;线性分类器的正则化参数只由验证集选择。
第五步,在一个未用于模板选择的目标场景上评估,报告宏平均 F1、各类召回率及混淆矩阵。验收:能够区分源域提升与目标域提升,并根据类别错误提出一个小规模实验。先把这一流程做完整,再考虑额外的提示学习或视频时序模块。
建立可检查的实验记录
开始第一轮实验前,建立四份小文件:数据清单记录样本编号、来源、标签与划分;配置文件记录预处理、随机种子、模型名称和冻结范围;结果表记录验证指标、选中轮次与最后测试指标;错误清单保存预测错误的样本编号及观察理由。这些文件比一张最高准确率截图更能说明你真正控制了实验条件,也能让后续细粒度或跨场景拓展沿用同一条证据链。
对视频、语音或多模态情绪数据,必须优先检查主体、会话和视频来源是否跨集合重复。同一原始视频切出的多个片段高度相关,随机按片段划分可能让模型记住说话人、背景或录制设备。跨场景问题至少要明确源域训练集、源域验证集和目标域测试集;若使用目标域标签选择提示词或超参数,就不应再把它描述为完全未见目标域的泛化结果。
为避免把实现错误误认为研究发现,先运行一个极小批次,打印输入输出形状、数值范围、有效长度以及损失是否有限。随后在少量训练样本上尝试拟合,验证模型确实能够更新指定参数。如果极小训练集都学不会,优先检查标签编码、掩码方向、归一化、学习率和冻结设置;此时直接扩大数据量通常只会延长排查时间,而不能证明模型本身不适合任务。
消融实验一次只改变一个关键因素,其他预处理、划分、优化预算和选择规则保持一致。第一轮以发现实现问题为目标,只用一个种子;确认代码与趋势合理之后,再增加多个种子并保留每次独立结果。均值用于概括趋势,标准差用于展示训练波动,但都不能替代对样本泄漏和评价口径的检查。不同论文中的最优数字不能在协议不明时直接相减。
解释实验失败时,先区分三层原因:实现层是否正确地执行了计算;优化层是否在给定预算内学到了信号;数据层是否提供了任务需要的信息。比如文本缺少反讽语调、静态图像看不到表情变化、音频包含录音噪声,这些问题不能仅靠增加网络深度解决。把失败样本分组后再提出修改,每项修改应能对应一个可观察的问题和一个预先规定的验证指标。
学习笔记采用“论文本身说了什么—源码实际做了什么—我在本地验证了什么”三栏记录。第一栏附页码或图表编号,第二栏附固定提交与行号,第三栏附命令、环境和输出。本文已完成原文及源码核对,未宣称在你的机器上重训原论文。下面的练习属于待执行计划;只有真正运行并保存结果后,才能把相应项目改为“已完成”。
短引语与阅读定位
原文短语 natural language supervision
(标题):文字提供学习信号,不能把训练称为完全无监督。
原文短语 zero-shot transfer
(摘要):需说明没有使用哪一类目标任务监督。
原文短语 Learning Transferable Visual Models
(标题):重点是可迁移表示,应连同规模与评价口径理解,而非承诺个人设备可轻松重训。
参考资料与核验边界
论文摘要与版本信息;完整论文 PDF;作者公开仓库固定版本。公式中标注“教学整理”的表达用于显式说明原文的计算步骤,不声称具有原文公式编号。所有实验数字均指原论文报告结果,不是本次新训练得到的结果。英文短引语合计不超过二十五个词。
自己的解释与验收记录
写出一条输入到输出的链路、一个关键公式的含义,以及你完成的最小检查。笔记仅保存在当前浏览器,可从主站「我的学习笔记」导出。