ViT 与 CLIP:让 Transformer 看图
把图像切成 patch,喂给 Transformer——视觉领域 2020 年最大的范式转变。
L3-06 我们看到 CNN 统治了视觉领域 8 年(2012-2020)。 L3-08 看到 Transformer 在 NLP 横扫一切。
2020 年一个自然的问题:能不能把 Transformer 也用在图像上?
答案是:能,而且效果惊人。
第一站:ViT 的核心想法
Transformer 处理的是序列——但图像是 2D 网格。怎么办?
ViT(Vision Transformer,2020)的招数极其简单:
把图像切成小 patch,每个 patch 当 token。
一张 224×224 的图
↓ 切成 16×16 的 patch(共 196 个)
↓ 每个 patch 展平成 256 维向量(16×16)
↓ 过一个线性层映射到 768 维
↓ 加位置编码
↓ 喂给标准 Transformer
完全照搬 NLP 的 Transformer 架构——只是把”词”换成”patch”。
为什么这能工作
CNN 的归纳偏好(inductive bias):
- 局部性(neighbors matter)
- 平移不变性(位置无关)
- 层次性(low-level → high-level)
ViT 把这些全扔了——纯粹靠数据学。
问题:没有了归纳偏好,模型应该更难学才对——为什么能赢?
答:数据足够多时,没有归纳偏好反而更好——模型能学到比 CNN 设计的偏好更精细的模式。
经典发现
| 数据量 | CNN 表现 | ViT 表现 |
|---|---|---|
| ImageNet(130 万张) | 强 | 弱 |
| JFT-300M(3 亿张) | 强 | 强 + 反超 |
ViT 在大数据上反超 CNN——是后续视觉 Transformer 的核心理由。
第二站:用 PyTorch 看 ViT
import torch
import torch.nn as nn
class PatchEmbedding(nn.Module):
def __init__(self, img_size=224, patch_size=16, in_channels=3, dim=768):
super().__init__()
self.n_patches = (img_size // patch_size) ** 2 # 196
# 用 Conv2d 实现 patch 切分 + 投影(一举两得)
self.proj = nn.Conv2d(in_channels, dim, kernel_size=patch_size, stride=patch_size)
def forward(self, x):
# x: (B, 3, 224, 224)
x = self.proj(x) # (B, 768, 14, 14)
x = x.flatten(2) # (B, 768, 196)
x = x.transpose(1, 2) # (B, 196, 768) ← 这是 Transformer 输入
return x
class ViT(nn.Module):
def __init__(self, n_classes=1000, dim=768, depth=12, n_heads=12):
super().__init__()
self.patch_embed = PatchEmbedding()
self.cls_token = nn.Parameter(torch.zeros(1, 1, dim)) # 借鉴 BERT 的 [CLS]
self.pos_embed = nn.Parameter(torch.zeros(1, 197, dim)) # 196 patches + 1 CLS
encoder_layer = nn.TransformerEncoderLayer(
d_model=dim, nhead=n_heads, dim_feedforward=4*dim, batch_first=True
)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=depth)
self.head = nn.Linear(dim, n_classes)
def forward(self, x):
x = self.patch_embed(x) # (B, 196, 768)
cls = self.cls_token.expand(x.size(0), -1, -1)
x = torch.cat([cls, x], dim=1) # (B, 197, 768)
x = x + self.pos_embed
x = self.transformer(x)
return self.head(x[:, 0]) # 用 CLS token 分类
整个 ViT 就这么简单——20-30 行代码。
第三站:CLIP 的革命
2021 年 OpenAI 发了一篇更”震撼”的论文:CLIP(Contrastive Language-Image Pre-training)。
核心思路
不是分类——而是让”图像”和”它的文字描述”靠近。
共享的向量空间
↓
图像 ──→ ViT ─────→ 图像向量 ←─────── 同一概念
↑
文本 ──→ Transformer ─→ 文本向量 ←─── 同一概念
训练数据
**4 亿张”图 + 描述”**对——从互联网抓取。
不需要人工标注——alt 文本和 caption 自带标签。
训练目标:对比学习
一个 batch 有 N 对(图,文):
图 1: 一只橘猫坐在窗台
图 2: 三只小狗在玩
图 3: 海边日落
...
文 1: "An orange cat on a window sill"
文 2: "Three puppies playing"
文 3: "Sunset at the beach"
...
训练目标:
- (图 1, 文 1) 向量靠近
- (图 1, 文 2/3/…) 向量远离
- 同理 (图 2, 文 2) 等
数学上:最大化对角线、最小化非对角线的相似度矩阵。
训完能干啥(零样本!)
CLIP 训完后,能做任何分类任务而不需要再训练:
classes = ["a photo of a cat", "a photo of a dog", "a photo of a car"]
text_features = [clip.encode_text(c) for c in classes]
image_features = clip.encode_image(my_image)
similarities = [cos_sim(image_features, t) for t in text_features]
predicted = classes[argmax(similarities)]
用任意文本描述当类别——零样本分类。
这是 ImageNet 之后视觉领域的第二次范式革命。
第四站:CLIP 的下游应用
CLIP 的 encoder 极其有用:
1. 文搜图 / 图搜文
"夕阳下的金毛" → CLIP text encoder → 向量
所有图片 → CLIP image encoder → 向量库
→ 余弦相似度找最匹配的图
Pinterest 风格搜索、相册自动整理——都基于这。
2. Stable Diffusion 的”耳朵”
Stable Diffusion 怎么”听懂”你的 prompt? 它用 CLIP text encoder 把 prompt 变成向量,喂给扩散模型作为”条件”。
没有 CLIP,文生图无法工作。
3. 多模态大模型
GPT-4V / Claude 3.5 等多模态 LLM 的 vision encoder——底层都是 ViT 或 CLIP 衍生品。
4. 零样本检测、分割
把 CLIP 的能力扩展到”找出图中所有猫的位置”—— GroundingDINO、SAM 等更先进的视觉模型基于这一思路。
第五站:ViT 和 CLIP 的局限
ViT 的问题
- 数据饥渴:小数据集上不如 CNN
- 计算贵:O(N²) 注意力,高分辨率图爆炸
- 没有 inductive bias:失去 CNN 的”翻译不变性”等天然属性
CLIP 的问题
- 训练数据偏见:网络数据带各种偏见(性别、种族、文化)
- 细粒度差:分得清猫和狗,分不清两种猫
- 依赖描述质量:alt 文本经常质量很差
- 英文为主:非英语效果差
第六站:ViT/CLIP 之后
Swin Transformer(2021)
把 CNN 的”层次”思想加回 ViT——逐层降采样。 解决了 ViT 高分辨率慢的问题。
MAE(Masked Autoencoders, 2021)
何凯明的工作。像 BERT 一样掩码 patch,让 ViT 自监督学。 不需要 CLIP 那样的图文对——更便宜。
SAM(Segment Anything, 2023)
Meta 的工作。通用图像分割——用 prompt(点、框、文本)就能分割任何物体。 基础架构:ViT。
DINO / DINOv2
Self-supervised ViT——完全不需要标签。 DINOv2 已经是当前视觉表征学习的 SOTA。
第七站:今天的视觉 AI 栈
Foundation: ViT / CLIP (encoder)
↓
Multimodal LLM: GPT-4V / Claude 3.5 / Gemini
↓
Specific Tasks:
- 检测: GroundingDINO
- 分割: SAM, Mask2Former
- 生成: Stable Diffusion, Imagen
- 编辑: InstructPix2Pix
- 视频: Sora
整个栈都建立在 ViT/CLIP 之上。
2020-2021 这两篇论文奠定了现代视觉 AI 的基础——影响和 Transformer 在 NLP 上一样大。
配套代码
用 OpenCLIP 试一下:
import open_clip
import torch
from PIL import Image
model, _, preprocess = open_clip.create_model_and_transforms('ViT-L-14', pretrained='laion2b_s32b_b82k')
tokenizer = open_clip.get_tokenizer('ViT-L-14')
image = preprocess(Image.open("photo.jpg")).unsqueeze(0)
text = tokenizer(["a photo of a cat", "a photo of a dog", "a sunset"])
with torch.no_grad():
image_features = model.encode_image(image)
text_features = model.encode_text(text)
similarity = (image_features @ text_features.T).softmax(dim=-1)
print(similarity) # [0.05, 0.92, 0.03] - 是狗
几行代码做”任意类别图像分类”——3 年前完全无法想象。
Transformer 已经吞噬了所有模态:
- 文本 ✓
- 图像 ✓ (ViT)
- 语音 ✓ (Whisper / SeamlessM4T)
- 视频 ✓ (Video Transformer, Sora)
- 蛋白质 ✓ (AlphaFold 2)
- 决策 ✓ (Decision Transformer)
- 机器人 ✓ (RT-2)
“Attention is all you need” 这个标题成了预言。
下一篇推荐:L5-04 CLIP 详解 或 L4-04 Agent 构建。
读到这里说明你认真在学 🎯
订阅每周精选 —— 下一篇新文章 / 新可视化第一时间送到邮箱。
讨论区
· 用 GitHub 账号登录评论src/components/Comments.astro 顶部填入
仓库 ID 和分类 ID(见组件注释里的配置步骤)。