ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

CLIP模型精读:自然语言监督如何实现零样本视觉分类

CLIP模型精读:自然语言监督如何实现零样本视觉分类 如果你做过一段时间的视觉算法工作对下面这条流程应该再熟悉不过甲方抛过来一个新品类识别需求你的第一反应大概率不是改网络结构而是问对方“标注数据有多少”。传统监督分类范式下标注数量和质量直接决定模型上限而 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 能到 32768CLIP 的训练配置也值得单独说。Batch size 是 32768作为对比当时常见的图像分类训练 batch 大多在 256 到 1024 之间。为什么 CLIP 要这么大的 batch原因在对比学习的机制里负样本来自 batch 内其他图文对batch 越大负样本多样性越高对齐信号越强。但这引出一堆工程问题显存放不下就用混合精度用梯度分片用模型并行。文本塔和图像塔放在不同 GPU 上把投影层放到同一张卡上统一计算对比损失。论文里最大规模的模型用了几百块 GPU 也训练了接近二十天。这个成本说明一个问题CLIP 的能力是拿巨大算力和数据“喂”出来的不是网络结构凭空长出来的。复现时可以先用小 batch 验证流程但要心里有数小 batch 训练出来的对比模型效果会明显差一截。3. 零样本能力从哪来数据规模、训练策略与 prompt 设计的合力3.1 WIT 数据集4 亿图文对撑起语义先验CLIP 的零样本能力不是无源之水它来自一个训练数据规模远超常规的数据集 WITWebImageText包含约 4 亿个图文对。这些图文对主要来自网络上的替代文本以及图片周边文本质量参差甚至有不少噪声但量非常足。量变带来质变的逻辑在于只有当模型在几亿个“图 描述”样本上见过足够多概念和表达方式它才能对“fox狐狸”这种词建立稳定的视觉对应。如果只有一两百万数据语言描述的高维语义空间根本学不满。我自己做过一个小实验把 CLIP 的数据规模砍到十分之一零样本效果立刻掉到不可用这充分说明数据规模是零样本的地基。需要提醒的是OpenAI 开源了 CLIP 的模型权重和推理代码但 WIT 完整数据集并没有开源。想复现论文里的原始结果目前只能基于公开图文对数据或重新构建自己的图文数据集这是一个真实的工程门槛。3.2 模型容量与数据规模要匹配论文里有张非常直观的图横轴是训练计算量纵轴是零样本准确率不同大小的模型排成一条上升曲线。这告诉我们零样本迁移能力显著依赖于模型容量小模型即使数据够也很难把语义空间刻画完整。实际使用中ViT-B/32 是效率与效果比较均衡的起点ViT-L/14 效果更好但显存和推理时间也上去了ViT-L/14336 把输入分辨率提到 336对细节识别有明显增益。如果做资源受限的边缘端项目B/32 往往更现实如果对精度要求高且 GPU 充足直接上 L/14336 最省心。别指望小模型复用大模型的 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 githttps://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, devicedevice)这里有个容易踩的坑首次运行会自动下载 ViT-B/32 权重体积约 350MB。国内网络环境下下载可能比较慢建议预先下好权重文件放到 huggingface 缓存目录或者 torch hub 缓存目录里避免每次实验都卡在下载这一步。如果机器上没有 GPUCPU 也能跑但同一张图片的推理耗时会长很多。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, devicedevice) 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/14336先用 ViT-B/32 把流程跑通确认需求能否被零样本范式包住再上大模型。模型架构的进步当然重要但自然语言监督这种“换个学习目标”的思路才是这篇论文真正打开的一扇门。
返回列表