CLIP模型精读:自然语言监督如何实现零样本视觉分类
2026/9/7 4:12:23 网站建设 项目流程

如果你做过一段时间的视觉算法工作,对下面这条流程应该再熟悉不过:甲方抛过来一个新品类识别需求,你的第一反应大概率不是改网络结构,而是问对方“标注数据有多少”。传统监督分类范式下,标注数量和质量直接决定模型上限,而 CLIP 这篇论文(Learning Transferable Visual Models From Natural Language Supervision)最大的冲击在于:它把“训练集”这个根基抽走了。我第一次在项目里接 CLIP 时带着不小的怀疑,一个不做任何微调的模型,真能直接拿去做零样本分类?结果第一次跑通后,我被它那种“不用训练也能分类”的能力弄得有点懵。后来反复读论文,才慢慢想明白它背后的两条主线——自然语言监督和零样本视觉迁移,不是侥幸,而是整套方法论设计出来的结果。这篇精读我就围绕这两条线展开,尽量讲清原理,也给够可以抄作业的实操细节。

1. 为什么非要用自然语言当监督信号:视觉模型的老问题与 CLIP 的破局点

1.1 封闭集合标注的隐性成本

传统图像分类项目的流程几乎都是同一个模子:先定一份类别清单,然后洗数据、找人标注、训练模型、上线迭代。这个流程里有一个很少被质疑的前提——类别清单是固定的,一旦定下来,整个模型就被“锁”在这个封闭集合里。

我见过太多团队被这个前提卡住。今天训练一个区分猫、狗、鸟的模型,明天客户说还要识别狐狸,那就得重新收集狐狸图片、重新标数据、重新微调。问题不在于微调本身有多复杂,而在于每加一个类别,整个“数据—标注—训练—验证”循环就要完整走一遍。标注成本、GPU 成本、人力排期,全部被这个循环吃掉。更麻烦的是,有些任务的类别数量是长尾的,甚至可能在线上动态变化,比如电商商品属性和内容审核场景,用固定类别训练一版模型,根本赶不上需求变化的速度。

CLIP 想解掉的就是这个约束。它把预训练阶段的学习目标从“预测类别编号”改成了“判断图文是否匹配”,所以在下游使用时,类别集合不再需要参与训练。你想识别什么,就把它写成一句文本,模型拿这句话跟图片比一比,就知道像不像。这个思路听起来不复杂,但它把视觉模型的使用方式整个翻过来了。

1.2 自然语言监督的维度优势

再往深一层看,为什么要用“自然语言”而不是继续扩大标注规模?答案在于监督信号的信息密度。

one-hot 标签本质上是一个编号,它对模型说:这张图属于 17 号类别。模型必须从大量同类样本里自己总结“17 号类别到底长什么样”,而且它完全不知道 17 号和 18 号之间是什么关系。这种标签形态包含的语义信息接近零,所有概念理解都得靠样本量去堆。

自然语言就不一样。一句“a black cat sitting on the windowsill”同时包含了物种、颜色、姿态、场景、空间位置信息。模型在预训练时见过几亿个这样的句子,它被迫去理解概念之间的关系,因为文本里天然有层级关系(猫属于动物)、属性修饰(黑色、坐着)、上下文(窗台上)。分类不再是“记住这个编号”,而是“理解这个概念与描述之间的关系”。

这也是为什么 CLIP 能对训练里从未见过的类别做分类。它不是记住了“狐狸”这个类别名对应的几千张图,而是理解了“fox”这个词在语言中对应的语义空间,并且知道什么样的图像内容会落在这个语义空间附近。

1.3 范式切换:分类从预测变成了检索

CLIP 论文里最值得细品的,其实是任务定义方式的转变。

传统分类模型输出的是“类别概率分布”,这个概率分布的维度在训练时由类别数决定,模型结构里就写死了。而 CLIP 在推理阶段做的是“检索”:先把候选类别的文本全部编码成特征,再把图像编码成特征,然后算图像特征跟每个文本特征的相似度,最后对相似度做 softmax。候选文本是什么,概率分布就是什么,跟训练时完全无关。

这意味着一个模型可以同时做“猫狗分类”“场景识别”“商品属性判断”,只要每次给不同的文本候选集就行。我第一次意识到这一点时,第一反应是:这不就是一个用语言作为动态分类头的模型吗?对,本质就是这样。动态分类头的好处在于,它是零样本的直接来源,也是后续一切多模态能力的基础。

2. 图文对齐的核心机制:双塔结构、对比损失与温度参数

2.1 图像编码器与文本编码器的设计

CLIP 整体是双塔结构,这是理解全篇的骨架。图像侧用 Image Encoder,文本侧用 Text Encoder,图像塔和文本塔分别把输入编码成向量,再各自经过一层投影,映射到同一个 d 维语义空间。

图像塔可选 ResNet 系列或 ViT 系列。论文的实验测试下来,同计算量下 ViT 表现略好于 ResNet,官方公布的模型里用得最多的也是 ViT-B/32、ViT-B/16、ViT-L/14 这几个版本。文本塔用的是 Transformer,词表基于 BPE,最大序列长度 76 个 token,超过部分直接截断。

关键不是两座塔本身有多新,而是它们共享同一个语义空间。投影之后,图像特征和文本特征可以直接算余弦相似度,相似度越高表示这个文本越能描述这张图。整个模型没装任何额外的分类头,这是与常规分类模型最本质的区别。

2.2 对比学习目标:拉近匹配对,推远不匹配对

训练目标同样值得仔细看。给定一个 batch 的 N 个图文对,CLIP 希望模型能学会“哪张图配哪段文本”,方法是让匹配对的余弦相似度高、不匹配对的相似度低。

具体做法是:算出一个 N×N 的相似度矩阵,矩阵第 i 行第 j 列表示第 i 张图和第 j 段文本的相似度。对角线是配对的,非对角线就是天然负样本。损失函数写作对称形式:从图像到文本方向用一次交叉熵,从文本到图像方向再用一次交叉熵,两个方向取平均。

这个对称设计不是炫技。它强迫文本塔和图像塔都承担对齐责任,让特征空间在双向都保持一致。只看一个方向的话,模型很容易偷懒——只要图像特征和文本特征都能区分 batch 内样本就行,不保证跨模态语义真的对齐。

2.3 温度参数 τ 的作用

对比学习里有个容易忽略但影响很大的细节:温度参数 τ。计算相似度时,矩阵要先除以一个学出来的 τ,再进 softmax。

τ 直观上控制着输出分布的尖锐程度。τ 小,softmax 就越“苛刻”,模型必须把匹配对的相似度压得非常高,把不匹配对压得非常低,整体训练难度更大;τ 大,分布变平缓,负样本的惩罚变得温和,模型可能“差不多就行”。CLIP 把 τ 设置为可学习参数,让训练过程中自动调整这个严格程度,而不是拍脑袋定死。实践里,温度对训练的稳定性影响非常大,微调 CLIP 时如果效果突然不对劲,先检查一下这个参数有没有被冻结或者被异常更新。

2.4 训练工程细节:为什么 batch size 能到 32768

CLIP 的训练配置也值得单独说。Batch size 是 32768,作为对比,当时常见的图像分类训练 batch 大多在 256 到 1024 之间。为什么 CLIP 要这么大的 batch?原因在对比学习的机制里:负样本来自 batch 内其他图文对,batch 越大,负样本多样性越高,对齐信号越强。

但这引出一堆工程问题:显存放不下,就用混合精度,用梯度分片,用模型并行。文本塔和图像塔放在不同 GPU 上,把投影层放到同一张卡上统一计算对比损失。论文里最大规模的模型,用了几百块 GPU 也训练了接近二十天。这个成本说明一个问题:CLIP 的能力是拿巨大算力和数据“喂”出来的,不是网络结构凭空长出来的。复现时可以先用小 batch 验证流程,但要心里有数,小 batch 训练出来的对比模型效果会明显差一截。

3. 零样本能力从哪来:数据规模、训练策略与 prompt 设计的合力

3.1 WIT 数据集:4 亿图文对撑起语义先验

CLIP 的零样本能力不是无源之水,它来自一个训练数据规模远超常规的数据集 WIT(WebImageText),包含约 4 亿个图文对。这些图文对主要来自网络上的替代文本以及图片周边文本,质量参差,甚至有不少噪声,但量非常足。

量变带来质变的逻辑在于:只有当模型在几亿个“图 + 描述”样本上见过足够多概念和表达方式,它才能对“fox(狐狸)”这种词建立稳定的视觉对应。如果只有一两百万数据,语言描述的高维语义空间根本学不满。我自己做过一个小实验,把 CLIP 的数据规模砍到十分之一,零样本效果立刻掉到不可用,这充分说明数据规模是零样本的地基。

需要提醒的是,OpenAI 开源了 CLIP 的模型权重和推理代码,但 WIT 完整数据集并没有开源。想复现论文里的原始结果,目前只能基于公开图文对数据或重新构建自己的图文数据集,这是一个真实的工程门槛。

3.2 模型容量与数据规模要匹配

论文里有张非常直观的图:横轴是训练计算量,纵轴是零样本准确率,不同大小的模型排成一条上升曲线。这告诉我们,零样本迁移能力显著依赖于模型容量,小模型即使数据够,也很难把语义空间刻画完整。

实际使用中,ViT-B/32 是效率与效果比较均衡的起点,ViT-L/14 效果更好但显存和推理时间也上去了,ViT-L/14@336 把输入分辨率提到 336,对细节识别有明显增益。如果做资源受限的边缘端项目,B/32 往往更现实;如果对精度要求高且 GPU 充足,直接上 L/14@336 最省心。别指望小模型复用大模型的 zero-shot 效果,这是我在多个数据集上反复验证过的规律。

3.3 prompt engineering 与 prompt ensembling 的实际增益

零样本使用阶段,最容易出效果差异的地方其实是文本模板怎么写。直接用“cat”这个词和用“a photo of a cat”这个句子,结果差不少。原因也不难理解:预训练数据里,单独一个“cat”字符串很少会作为图片的替代文本出现,更多是出现在“a photo of a cat”“a cat sitting on the sofa”这类完整描述里。因此推理阶段用完整句子的分布更贴近训练分布。

论文里在不同数据集上测试了多种模板,比如食物数据集用“a photo of {label}, a type of food.”,鸟类数据集用“a photo of {label}, a type of bird.”,效果比通用模板还要好。再进一步,可以用“prompt ensembling”:同时构造 80 个左右模板,分别编码,把文本特征做了归一化后取平均,ImageNet 零样本准确率可以再提升约 3.5 个百分点。这相当于用多条文本描述来覆盖同一个概念的不同表达方式,是非常廉价的提分手段。

3.4 零样本迁移的评测协议

论文里对零样本能力的评测覆盖了 30 多个数据集,包括普通物体识别、场景识别、纹理分类、卫星图像分类等。同时还有一组少样本实验:把 CLIP 当特征提取器,只用少量标注训练一个线性分类器,效果明显好于在 ImageNet 预训练模型上做同样的线性探测。

这个结果说明,CLIP 学到的特征不仅可用于零样本,它的特征本身可迁移性也更强。我在实际项目里也发现,哪怕最终方案要做微调,从 CLIP 特征出发也通常比从 ResNet 预训练特征出发收敛更快,尤其当目标任务的标注量很小时。

4. 亲手复现一次零样本分类:模型加载到推理的关键细节

4.1 环境准备与模型加载

OpenAI 官方开源了 CLIP 的推理代码和权重,安装和加载都比较直接:

pip install git+https://github.com/openai/CLIP.git

加载模型时,官方 API 会同时返回模型和预处理函数:

import clip import torch device = "cuda" if torch.cuda.is_available() else "cpu" model, preprocess = clip.load("ViT-B/32", device=device)

这里有个容易踩的坑:首次运行会自动下载 ViT-B/32 权重,体积约 350MB。国内网络环境下下载可能比较慢,建议预先下好权重文件,放到 huggingface 缓存目录或者 torch hub 缓存目录里,避免每次实验都卡在下载这一步。如果机器上没有 GPU,CPU 也能跑,但同一张图片的推理耗时会长很多。

4.2 图像预处理细节

CLIP 的预处理不是普通图像的 resize + normalize,它包含几个对结果影响很大的细节。官方 preprocess 会先把最短边缩放到 224,然后做中心裁剪,再转成张量、归一化。归一化用的均值和标准差如下:

mean = [0.48145466, 0.4578275, 0.40821073] std = [0.26862954, 0.26130258, 0.27577711]

注意,这套均值和标准差跟 ImageNet 预训练模型常用的[0.485, 0.456, 0.406]不一样。我见过有人图省事,直接用 ImageNet 的标准预处理流程,结果零样本分类准确率掉了好几个点。CLIP 预训练时就是用这套特定统计量做归一化的,推理阶段必须保持一致,这不是玄学,是数据分布对齐的基础。

4.3 候选文本的构造方式

文本端会用clip.tokenize把句子转成 token 序列,默认最大长度 77。写候选文本时,有几个经验:

第一,尽量不要只写单词,要写完整句子。第二,候选类别之间最好保持语义对齐,比如都写成“a photo of a X”的形式,不要一个写“dog”另一个写“an image contains a cat”。第三,可以用多个句子描述同一类别,编码后做特征平均,相当于做轻量版的 prompt ensemble。

text_descriptions = [ "a photo of a cat", "a photo of a dog", "a photo of a car", ] text = clip.tokenize(text_descriptions).to(device)

如果类别本身有领域背景,比如“宫保鸡丁”这样的菜品,那模板改成“a photo of {label}, a type of food.”效果常常更好。具体哪个模板最佳,在自己数据上各试一轮就知道了,成本很低。

4.4 一次完整推理代码与结果解读

把整条链路串起来,代码如下:

import clip import torch from PIL import Image device = "cuda" if torch.cuda.is_available() else "cpu" model, preprocess = clip.load("ViT-B/32", device=device) image = preprocess(Image.open("test.jpg")).unsqueeze(0).to(device) text_descriptions = [ "a photo of a cat", "a photo of a dog", "a photo of a car", ] text = clip.tokenize(text_descriptions).to(device) with torch.no_grad(): logits_per_image, _ = model(image, text) probs = logits_per_image.softmax(dim=-1).cpu().numpy() for label, prob in zip(text_descriptions, probs[0]): print(f"{label}: {prob:.4f}")

输出结果会是一个概率分布,比如:

a photo of a cat: 0.0201 a photo of a dog: 0.9705 a photo of a car: 0.0094

为什么要对 logits 做 softmax 而不是直接看相似度?因为不同文本候选集之间的相似度分布可能有偏移,softmax 能把这些值归一化成可比较的概率。实际项目中建议把相似度原始值也存下来,方便后续调阈值,因为有些场景下“都不像”的样本需要用相似度阈值直接拒掉,而不是硬塞进概率分布里。

5. 强项与短板:把 CLIP 放进真实项目里会遇到的第一个坎

5.1 实际项目里最先感受到的强项

零样本能力是 CLIP 最大的招牌,但在真实项目里还有几个容易被忽略的优势。

第一是快速试错。以前接一个新分类需求,至少要走一轮数据标注,现在可以当天写几行 prompt 就跑一轮评估,给业务方一个初步结论。哪怕最后不得不用微调方案,这个零样本结果也能作为 baseline,帮团队判断数据预算和效果上限。第二是类别可动态调整。线上类别有变化时,不用重新训练,直接改候选文本列表就行。第三是分布鲁棒性。论文里的鲁棒性实验表明,相比在 ImageNet 上训练的模型,CLIP 在 ImageNetV2、素描图、卡通图这类分布偏移数据上的准确率下降幅度明显更小,这对真实环境中的推理部署很有价值。

5.2 哪些场景容易翻车

CLIP 不是万能的,论文自己的实验也暴露了一些明显短板。最容易翻车的场景主要有这几类:

第一,细粒度识别。让它区分哈士奇和阿拉斯加、区分不同品种的玫瑰,效果通常比较差,因为语言描述很难区分视觉上非常接近的概念。第二,抽象属性判断。比如“这张图是否被修过”“画面里有没有人正在奔跑”,这类需要复杂推理的属性,CLIP 很容易给出错误结果。第三,空间关系理解。有人说“左边那个人在喝咖啡”,CLIP 对这类问题基本是一脸懵。第四,小目标识别。图片里很小很模糊的对象,zero-shot 能力会严重退化。第五,图像中的文字识别也有明显不稳定性。

论文里有几个专门的数据集,比如 Count 任务,CLIP 直接垫底。这说明它学到的视觉语义更偏向“这个物体是什么”,而不是“有几个”“在哪里”“在干什么”。

5.3 项目中的补救思路

如果验证下来 CLIP 在某些类别上不行,第一个建议不是大规模微调,而是先调 prompt,换更贴领域的模板往往能拉回几个点。还不够,再考虑用 CLIP 特征做线性探测或轻量微调,只需要少量标注,效果通常比从 ImageNet 预训练模型微调更好。

还有一种实用套路是“CLIP 粗筛 + 小模型精排”。先让 CLIP 从几千个候选类别里粗选出 top 20,再用一个很小的专用分类器对 top 20 做精细判断。这样既保留了零样本的灵活性,又规避了 CLIP 细粒度能力不足的问题。如果目标域实在特殊,比如医学影像、卫星遥感,建议直接考虑开放权重社区里的微调版本或者替换成 ALIGN 这类同思路但数据分布不同的模型,不必死守原版。

6. 自然语言监督对后续视觉模型的影响和我的使用体会

6.1 一条被验证过的技术路线

CLIP 发表之后,以自然语言监督为基座的多模态模型快速铺开。后续的 BLIP、ALIGN、Flamingo 等模型,大多保留了“图像编码器 + 文本编码器 + 对齐损失”的底层框架,只是在数据、训练目标或者生成能力上做了扩展。再往后看,DALL-E、各种文生图模型,以及更现代的多模态大模型,几乎都从这篇论文里继承了同一个核心理念:图像和文本要放进同一个语义空间,语言才是视觉理解最自然的锚点。

从这个角度回头看,CLIP 论文最主要的贡献不是某个网络结构(双塔结构早就有),而是把“监督信号的选择”这个问题摆到了台面上。过去大家都默认图像监督只能用标注类别,CLIP 证明了一句完整描述带来的信息量,远超一个孤立的标签编号。

6.2 我个人的落地经验

我把 CLIP 接进过好几个实际项目,最深刻的体会是:别把它当成“万能分类器”,要把当成“开放的语义特征提取器”。零样本模式适合做 demo、预研、长尾类别覆盖和快速验证;一旦业务对精度有硬指标,仍然需要另配一个轻量的下游适配层。最佳实践通常不是“从零样本直接上线”,而是“零样本搭骨架,少量标注精修”。

另一个经验是,用 CLIP 的项目一定要把 prompt 纳入版本管理。很多时候模型权重没有变,只是有人把模板从“a photo of a {label}”改成了“{label}”,线上效果就跌了。这个坑非常隐蔽,因为代码没有报错,只是悄悄掉点。我习惯在评估脚本里固定一份模板配置文件,任何改动都走评审,避免“文件被同事顺手改掉然后全组排查”的悲剧。

如果你也想在项目里试 CLIP,我的建议是别一上来就追求 ViT-L/14@336,先用 ViT-B/32 把流程跑通,确认需求能否被零样本范式包住,再上大模型。模型架构的进步当然重要,但自然语言监督这种“换个学习目标”的思路,才是这篇论文真正打开的一扇门。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询