CLIP 与开放词表视觉 本节摘要:同时训练一个图像编码器和一个文本编码器,让匹配的(图,描述)对落在同一个共享空间里的同一点——这就是 CLIP 的全部戏法。本节讲清双塔架构与对比训练目标(对角线高相似度、非对角低),实现零样本分类的完整流程(编码类别提示、算余弦相似度、取 argmax),并区分 CLIP、SigLIP、OpenCLIP、LLaVA 等 VLM 各自的用途。读完本节,你理解了为什么 2026 年几乎每个视觉系统——检测、分割、检索、内容审核、文生图——都从 CLIP 系检查点起步。 对应原课程:Phase 4 · Lesson 18 · (原英文 )。 学习目标 阅读完本节,你应当能够: 解释 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)。
阅读完本节,你应当能够:
传统分类器是闭词表的: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(Zhai 等,2023)用每对的 sigmoid 替代 softmax:
loss = 对所有对取均值 log(1 + exp(-y_ij * sim_ij)) y_ij = +1 若匹配,否则 -1
逐对损失去掉了 CLIP 需要的批级归一化。SigLIP 在小批上训练更好,等数据量下匹敌或超越 CLIP。
给定一个训好的 CLIP:
T 形状 (C, d)。I 形状 (1, d)。I @ T.T,形状 (1, C)。提示工程要紧。OpenAI 为 ImageNet 发布了 80 个提示模板(「a photo of a {}」「a blurry photo of a {}」「a sketch of a {}」……)。每类把所有模板的嵌入取平均,能再加 1~3% top-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 一致。
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 越尖锐,越自信但不稳定风险升高。
@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 检查点用的零样本流程完全一致。
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 检查点建图像嵌入索引,支持以文搜图和以图搜图。下一节进入 OCR 与文档理解——把图像里的文字读出来,再理解版式、表格、表单结构。