CLIP 与开放词表视觉


文档摘要

CLIP 与开放词表视觉 本节摘要:同时训练一个图像编码器和一个文本编码器,让匹配的(图,描述)对落在同一个共享空间里的同一点——这就是 CLIP 的全部戏法。本节讲清双塔架构与对比训练目标(对角线高相似度、非对角低),实现零样本分类的完整流程(编码类别提示、算余弦相似度、取 argmax),并区分 CLIP、SigLIP、OpenCLIP、LLaVA 等 VLM 各自的用途。读完本节,你理解了为什么 2026 年几乎每个视觉系统——检测、分割、检索、内容审核、文生图——都从 CLIP 系检查点起步。 对应原课程:Phase 4 · Lesson 18 · (原英文 )。 学习目标 阅读完本节,你应当能够: 解释 CLIP 的双塔架构与对比训练目标。

CLIP 与开放词表视觉

本节摘要:同时训练一个图像编码器和一个文本编码器,让匹配的(图,描述)对落在同一个共享空间里的同一点——这就是 CLIP 的全部戏法。本节讲清双塔架构与对比训练目标(对角线高相似度、非对角低),实现零样本分类的完整流程(编码类别提示、算余弦相似度、取 argmax),并区分 CLIP、SigLIP、OpenCLIP、LLaVA 等 VLM 各自的用途。读完本节,你理解了为什么 2026 年几乎每个视觉系统——检测、分割、检索、内容审核、文生图——都从 CLIP 系检查点起步。

对应原课程:Phase 4 · Lesson 18 · open-vocab-clip(原英文 phases/04-computer-vision/18-open-vocab-clip/docs/en.md)。

学习目标

阅读完本节,你应当能够:

  1. 解释 CLIP 的双塔架构与对比训练目标。
  2. 用预训练 CLIP(或 SigLIP)做零样本分类,无需任何任务特定训练。
  3. 从零实现零样本分类:编码类别提示、算余弦相似度、取 argmax。
  4. 区分 CLIP、SigLIP、OpenCLIP、LLaVA/LLaMA-vision 模型——2026 年各自用途。

一、问题与直觉

传统分类器是闭词表的:1000 类的 ImageNet 模型只能预测 1000 个标签。每加一个类别都要标注数据和重训头。

CLIP(Radford 等,OpenAI 2021)证明:在从网页爬取的 4 亿(图,描述)对上训练,得到的模型能在推理时对任意类别集合分类,类别纯粹用自然语言描述。给一个新类,只要写一句话。

这个能力——零样本迁移——是每个现代视觉系统都从 CLIP 系检查点起步的原因。检测(Grounding DINO、OWL-ViT)、分割(CLIPSeg、SAM)、检索、内容审核、VLM、文生图都建立在 CLIP 式联合嵌入之上。

双塔

两个编码器末尾都有一个线性投影到同一嵌入维(CLIP-B/32 是 512,CLIP-L/14 是 1024),L2 归一化后算余弦相似度。

目标

给定一批 N 个(图,描述)对,构建 N×N 相似度矩阵。训练两个编码器,让对角线(匹配对)相似度高、非对角(不匹配)相似度低。

sim_matrix = image_embeddings @ text_embeddings.T / tau loss_i2t = cross_entropy(sim_matrix, targets=arange(N)) loss_t2i = cross_entropy(sim_matrix.T, targets=arange(N)) loss = (loss_i2t + loss_t2i) / 2

对称,因为图到文、文到图检索都该能用。tau(温度)通常作为标量参数学习,初始化为 0.07。

SigLIP:更好的损失

SigLIP(Zhai 等,2023)用每对的 sigmoid 替代 softmax:

loss = 对所有对取均值 log(1 + exp(-y_ij * sim_ij)) y_ij = +1 若匹配,否则 -1

逐对损失去掉了 CLIP 需要的批级归一化。SigLIP 在小批上训练更好,等数据量下匹敌或超越 CLIP。

零样本分类

给定一个训好的 CLIP:

  1. 对每个类,组织提示:「a photo of a {类别}」。
  2. 用文本编码器编码所有类别提示 → T 形状 (C, d)。
  3. 编码测试图 → I 形状 (1, d)。
  4. 相似度 = I @ T.T,形状 (1, C)。
  5. argmax → 预测类别。

提示工程要紧。OpenAI 为 ImageNet 发布了 80 个提示模板(「a photo of a {}」「a blurry photo of a {}」「a sketch of a {}」……)。每类把所有模板的嵌入取平均,能再加 1~3% top-1 精度。

2026 年 CLIP 系模型用在哪

  • 零样本分类——直接用。
  • 图像检索——一次性编码所有图,推理时编码查询。
  • 文本条件检测——Grounding DINO、OWL-ViT 把 CLIP 文本塔接到检测器上。
  • 文本条件分割——CLIPSeg;SAM 经 CLIP 接受文本提示输入。
  • VLM——LLaVA、Qwen-VL、InternVL 把 CLIP 系视觉编码器接到 LLM 上。
  • 文生图——Stable Diffusion、DALL-E 3 用 CLIP 文本嵌入做条件。

一旦有了共享嵌入空间,每个视觉+语言任务都变成一次距离计算。

二、从零实现

步骤 1:微型双塔模型

真 CLIP 是 ViT + transformer。本节塔用预提取特征上的小 MLP,让 CPU 上能看见训练信号。

import torch import torch.nn as nn import torch.nn.functional as F class TwoTower(nn.Module): def __init__(self, img_in=128, txt_in=64, emb=64): super().__init__() self.image_proj = nn.Sequential(nn.Linear(img_in, 128), nn.ReLU(), nn.Linear(128, emb)) self.text_proj = nn.Sequential(nn.Linear(txt_in, 128), nn.ReLU(), nn.Linear(128, emb)) self.logit_scale = nn.Parameter(torch.ones([]) * 2.6592) # ln(1/0.07) def forward(self, img_feats, txt_feats): i = F.normalize(self.image_proj(img_feats), dim=-1) t = F.normalize(self.text_proj(txt_feats), dim=-1) return i, t, self.logit_scale.exp()

两个投影、共享维输出、可学温度,形状与真 CLIP API 一致。

步骤 2:对比损失

def clip_loss(image_emb, text_emb, logit_scale): N = image_emb.size(0) sim = logit_scale * image_emb @ text_emb.T targets = torch.arange(N, device=sim.device) l_i = F.cross_entropy(sim, targets) l_t = F.cross_entropy(sim.T, targets) return (l_i + l_t) / 2

对称。logit_scale 越大,softmax 越尖锐,越自信但不稳定风险升高。

步骤 3:零样本分类器

@torch.no_grad() def zero_shot_classify(model, image_feats, class_text_feats, class_names): """ image_feats: (N, img_in) class_text_feats: (C, txt_in) 每类一个平均嵌入 """ i = F.normalize(model.image_proj(image_feats), dim=-1) t = F.normalize(model.text_proj(class_text_feats), dim=-1) sim = i @ t.T pred = sim.argmax(dim=-1) return [class_names[p] for p in pred.tolist()]

每步一行,与生产 CLIP 检查点用的零样本流程完全一致。

步骤 4:健全性检查

torch.manual_seed(0) model = TwoTower() img = torch.randn(8, 128) txt = torch.randn(8, 64) i, t, scale = model(img, txt) loss = clip_loss(i, t, scale) print(f"批大小: {i.size(0)} 损失: {loss.item():.3f}")

随机初始化模型损失应接近 log(N) = log(8) = 2.08——还没学到结构时的对称交叉熵目标。

三、框架对比

OpenCLIP 是 2026 年的社区默认:

import open_clip import torch from PIL import Image model, _, preprocess = open_clip.create_model_and_transforms("ViT-B-32", pretrained="laion2b_s34b_b79k") tokenizer = open_clip.get_tokenizer("ViT-B-32") image = preprocess(Image.open("dog.jpg")).unsqueeze(0) text = tokenizer(["a photo of a dog", "a photo of a cat", "a photo of a car"]) with torch.no_grad(): image_features = model.encode_image(image) text_features = model.encode_text(text) image_features = image_features / image_features.norm(dim=-1, keepdim=True) text_features = text_features / text_features.norm(dim=-1, keepdim=True) probs = (100.0 * image_features @ text_features.T).softmax(dim=-1) print(probs)

SigLIP 更新、小规模训练更好、新项目首选:google/siglip-base-patch16-224。Hugging Face 两者都提供。

四、可复用产物

本节产出两个可复用文件(位于原课程 outputs/):

  • prompt-zero-shot-class-picker.md:一个提示词——给定类别列表和领域,为零样本 CLIP 设计类别模板。
  • skill-image-text-retriever.md:一个技能——用任意 CLIP 检查点建图像嵌入索引,支持以文搜图和以图搜图。

五、练习

  1. (简单) 用预训练 OpenCLIP ViT-B/32,以 80 模板提示集在 CIFAR-10 上做零样本分类。报告 top-1 精度,应约 85~90%。
  2. (中等) 在同一 CIFAR-10 任务上对比单模板(「a photo of a {}」)与 80 模板平均嵌入。量化差距,解释模板为何有用。
  3. (困难) 搭一个零样本图像检索索引:用 CLIP 编码 1000 张图、建 FAISS 索引、用自然语言描述查询。对你手写的 20 个留出查询报告 recall@5。

本节要点回顾

  1. CLIP = 双塔 + 对比——图文编码器投影到共享空间,匹配对靠近、不匹配对远离。
  2. 目标是对称交叉熵——图到文、文到图都要work;温度 tau 通常可学,初始化 0.07。
  3. SigLIP 用 sigmoid 替 softmax——逐对损失去掉批级归一化,小批训练更好。
  4. 零样本分类五步——组提示、编码类、编码图、算相似度、argmax;无需碰标签。
  5. 提示工程要紧——80 模板平均比单模板再加 1~3% top-1。
  6. 零样本迁移是命门——检测、分割、检索、审核、VLM、文生图全建立在 CLIP 嵌入上。
  7. 共享空间让视语任务变距离计算——一次编码、到处查询。
  8. 2026 工具链:OpenCLIP(开源生产默认)、SigLIP(新项目首选)、Hugging Face 两者都有。

下一节进入 OCR 与文档理解——把图像里的文字读出来,再理解版式、表格、表单结构。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U