Skip to content

视觉Transformer ViT

视觉 Transformer(Vision Transformer,ViT)将 NLP 中的 Transformer 直接搬进图像领域,用”图像切块 + 自注意力”替代卷积,在数据量足够大时超越了 CNN。ViT 不仅是一种新架构,更是一种新范式——证明了 Transformer 是通用序列建模工具,可以跨模态使用。本页是理解当代视觉模型的入口。前置阅读:CNN 主线、Transformer 架构、注意力机制。

把一张图片想象成一本图画书,CNN 的做法是拿着放大镜从左到右、从上到下逐像素扫描——视野始终被放大镜的镜片大小(卷积核)限制。ViT 的做法完全不同:

  • 切块 = 把书撕成一页页小卡片:把 224×224 的图片切成 16×16 的小块(patch),每块就像一张邮票。整张图变成 196 张邮票排成一排。
  • 线性嵌入 = 给每张邮票写一个编号:用线性变换把每块像素压缩成一个向量(比如 768 维),就像给每张邮票贴上身份标签。
  • 位置编码 = 记住邮票的原始位置:撕碎后邮票之间丢了位置信息,位置编码把”你原来在第几行第几列”补回来。
  • Transformer 编码器 = 让所有邮票互相”交流”:自注意力让每张邮票都去看其他所有邮票,判断”我这块和那块有没有关系”。全局视野一步到位,不需要像 CNN 那样一层层堆叠才能看到远处。

理解 ViT 和 CNN 的根本区别,关键在于归纳偏置(Inductive Bias)——模型设计中内置的先验假设:

特性CNNViT
归纳偏置强:平移不变性(Translation Invariance,物体在图像中的位置不影响识别)+ 局部性(Locality,每个神经元只看局部区域)弱:几乎没有空间先验假设
全局建模需要多层卷积堆叠才能获得大感受野第一层就能看到全局(自注意力)
数据效率小数据表现好(强先验帮忙)小数据表现差(先验少,需更多数据学规律)
大数据上限先验限制了上限无先验约束,数据越多潜力越大

核心洞见:ViT 的”缺点”(缺少归纳偏置)在数据足够多时反而成为优势——模型不被先验束缚,可以从数据中学到比”平移不变性 + 局部性”更丰富的模式。这就是为什么 ViT 在 ImageNet(130 万张图)上不如 CNN,但在 JFT-300M(3 亿张图)上超越 CNN。

给定一张图像 H×W×CH \times W \times C(高×宽×通道数),设 patch 大小为 P×PP \times P,则图像被切分为 N=(H/P)×(W/P)N = (H/P) \times (W/P) 个小块。例如 224×224 的图像取 P=16P=16,得到 N=14×14=196N = 14 \times 14 = 196 个 patch。

每个 patch 被展平为长度 P×P×CP \times P \times C 的向量,再通过一个可训练的线性层投影到维度 DD(即一个全连接层 E∈R(P2C)×DE \in \mathbb{R}^{(P^2 C) \times D})。最终得到 NN 个 DD 维向量,构成一个序列,和 NLP 中的 token 序列在结构上完全一样。

等价视角:这个线性投影等价于一个卷积核大小等于步幅等于 PP 的卷积层——nn.Conv2d(C, D, kernel_size=P, stride=P)。实现上很多代码用 Conv2d 代替手动切块 + 线性投影,数学上完全等价。

ViT 借鉴 BERT 的做法,在序列最前面插入一个特殊的可学习向量 CLS(Classification Token)。经过 Transformer 编码后,这个 token 聚合了全局信息,接一个 MLP 分类头即可输出类别概率:

p=Softmax(MLP(CLSout))p = \text{Softmax}(\text{MLP}(\text{CLS}_{\text{out}}))

为什么用 CLS token 而非全局池化? 原始论文发现 CLS token 和全局平均池化(GAP)效果相近。CLS token 的优势是模型可以学习如何聚合全局信息(而非简单平均),在复杂任务上略优。后续工作发现 GAP 在微调时更稳健,两者都常见。

由于自注意力本身不含位置信息(打乱输入顺序结果不变),必须额外加位置编码。ViT 原始论文使用标准可学习的 1D 位置编码——一个 (N+1)×D(N+1) \times D 的可训练矩阵(+1+1 是 CLS token),直接加到 patch 嵌入上。

一个有趣的发现:ViT 学到的 1D 位置编码在可视化后,表现出网格状 2D 结构——虽然模型只被给了一维编号,但它自己学到了二维空间排列。这说明即使没有显式的 2D 先验,Transformer 也能从数据中恢复空间结构。

后续工作探索了更丰富的位置编码:

  • 2D 位置编码(DeiT, CaiT):直接用行列编号,更自然
  • 相对位置编码(Swin Transformer):编码 patch 之间的相对偏移
  • 插值外推:推理时图像更大 → patch 更多 → 位置编码矩阵不够大 → 双三次插值扩展

编码器由 LL 层堆叠,每层包含:

  1. LayerNorm → 多头自注意力 → 残差连接(Pre-LN 结构)
  2. LayerNorm → MLP 前馈层 → 残差连接
zl′=MSA(LN(zl−1))+zl−1z'_l = \text{MSA}(\text{LN}(z_{l-1})) + z_{l-1} zl=MLP(LN(zl′))+zl′z_l = \text{MLP}(\text{LN}(z'_l)) + z'_l

其中 MLP 通常是 GELU 激活的两层全连接,隐藏维度为 4D4D。详细的自注意力计算流程见注意力机制。

DeiT(Touvron et al., 2021)解决了 ViT 最大的痛点——需要海量数据。关键技术:

  • 强数据增强:RandAugment、Mixup、CutMix,弥补缺少 CNN 先验的劣势
  • 知识蒸馏:用一个 CNN 教师模型(RegNet)做”软标签”蒸馏,把 CNN 的局部性先验传递给 ViT
  • Distillation Token:额外插入一个蒸馏 token(类似 CLS token),专门用于接收教师模型的输出

DeiT 使得 ViT 在 ImageNet-1k(仅 130 万张图)上从零训练也能达到 SOTA。

Swin Transformer(Liu et al., ICCV 2021 最佳论文)解决了 ViT 的两个问题:计算量随图像分辨率平方增长、不适合密集预测任务。核心创新:

  • 层级结构:类似 CNN 的金字塔(patch merging),逐层降低分辨率、增加通道数
  • 移位窗口注意力(Shifted Window Attention):将自注意力限制在局部窗口内,大幅降低计算量;通过窗口移位实现跨窗口连接

Swin 是第一个在目标检测、图像分割等密集预测任务上全面优于 CNN 的 ViT 变体。它后来被集成到 YOLOv12 等检测框架中。

MAE(He et al., CVPR 2022)是何恺明团队的 ViT 自监督预训练方法:

  • 随机遮挡 75% 的 patch,只保留 25%
  • 编码器只处理可见的 25%(大幅节省计算)
  • 解码器从可见 patch + mask token 重建被遮挡的区域

MAE 的洞察:图像的信息密度比文本低得多——文本遮一个词就很难猜,但图像遮一块 16×16 的区域,周围的像素就提供了足够线索。因此可以遮 75% 这么高。MAE 预训练的 ViT 在下游任务上全面超越有监督预训练。详见自监督学习。

DINOv2(Oquab et al., Meta, 2023-2024)将自监督对比学习 + 掩码图像建模结合,在 1.42 亿张图上训练通用视觉特征提取器。其输出的 patch 级特征可以直接用于分类、分割、深度估计、检索——无需微调。DINOv2 被视为视觉领域的”基础模型”。

2024 年视觉领域最重要的趋势是视觉基础模型的成熟:

  • DINOv2(Meta):通用视觉编码器,patch 级特征开箱即用
  • SigLIP(Google):用 sigmoid 替代 softmax 做图像-文本对比学习,效率更高
  • EVA-02(BAAI):高性能 ViT 预训练,多任务 SOTA
  • SAM 2(Meta, 2024):Segment Anything Model 2,支持图像和视频的通用分割,基于 ViT 编码器

CLIP(Radford et al., 2021)用 ViT 作为图像编码器与文本对齐。2024 年的发展:

  • SigLIP:改进对比学习目标,训练更高效
  • EVA-CLIP:更大规模、更强性能
  • OpenCLIP:开源社区维护的 CLIP 复现,提供各种规模的预训练权重

ConvNeXt(Liu et al., 2022)通过借鉴 ViT 的设计选择(大卷积核、LayerNorm、GELU、Pre-LN 结构),使纯 CNN 架构也能达到 ViT 级别的性能。这表明 ViT 的成功部分来自更好的训练策略和架构配置,而非自注意力本身。2024 年实践中,ViT 和现代 CNN(如 ConvNeXt-V2)的性能差距已经很小,选择哪种更多取决于具体任务和工程考量。

PyTorch:用 timm 库加载预训练 ViT 做图像分类

Section titled “PyTorch:用 timm 库加载预训练 ViT 做图像分类”
import torch
from PIL import Image
from torchvision import transforms
from timm import create_model # pip install timm
# 图像预处理:缩放到 224×224,归一化到 ImageNet 统计量
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]),
])
# 加载图片并预处理
img = Image.open("cat.jpg").convert("RGB")
x = transform(img).unsqueeze(0) # 增加 batch 维 → 1×3×224×224
# 加载预训练 ViT-Base/16(196 个 patch,每块 16×16)
model = create_model("vit_base_patch16_224", pretrained=True)
model.eval()
# 推理:输出 1000 维 logits,取最大值即预测类别
with torch.no_grad():
pred = model(x).argmax(dim=1).item()
print(f"预测类别索引: {pred}") # 如 281 = tabby cat
# 查看 patch 数量和模型结构
print(f"Patch 数量: {model.patch_embed.num_patches}") # 196
print(f"模型参数量: {sum(p.numel() for p in model.parameters()) / 1e6:.1f}M")
import torch
import torch.nn as nn
class PatchEmbedding(nn.Module):
"""将图像切分为 patch 并线性投影,等价于 stride=kernel 的卷积"""
def __init__(self, img_size=224, patch_size=16, in_channels=3, embed_dim=768):
super().__init__()
self.num_patches = (img_size // patch_size) ** 2 # 196
# 用 Conv2d 等价实现 patch 切分 + 线性投影
self.proj = nn.Conv2d(in_channels, embed_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).transpose(1, 2) # (B, 196, 768)
return x
# 测试
patch_embed = PatchEmbedding()
x = torch.randn(2, 3, 224, 224)
patches = patch_embed(x)
print(f"输入: {x.shape} → Patch 序列: {patches.shape}")
# 输入: torch.Size([2, 3, 224, 224]) → Patch 序列: torch.Size([2, 196, 768])
import numpy as np
# 假设有一张 28×28 的灰度图(如 MNIST)
img = np.random.randn(28, 28, 1)
P = 7 # patch 大小 7×7
# 切分:28/7 = 4,得到 4×4 = 16 个 patch
patches = []
for i in range(0, 28, P):
for j in range(0, 28, P):
patch = img[i:i+P, j:j+P, :] # 取出一个 7×7 小块
patches.append(patch.flatten()) # 展平为一维向量
patches = np.stack(patches) # 16 个 patch,每个 49 维
print(patches.shape) # (16, 49)
import torch
from transformers import AutoImageProcessor, AutoModel
# DINOv2:Meta 的自监督视觉基础模型,特征可直接用于下游任务
processor = AutoImageProcessor.from_pretrained("facebook/dinov2-base")
model = AutoModel.from_pretrained("facebook/dinov2-base")
from PIL import Image
img = Image.open("scene.jpg").convert("RGB")
inputs = processor(images=img, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
# CLS token 特征(768 维):可直接用于分类、检索
cls_features = outputs.last_hidden_state[:, 0, :] # (1, 768)
print(f"DINOv2 CLS 特征维度: {cls_features.shape}")
# Patch 级特征(196 × 768):可用于分割、密集预测
patch_features = outputs.last_hidden_state[:, 1:, :] # (1, 196, 768)
print(f"Patch 级特征: {patch_features.shape}")
  • patch 大小是关键超参数:常见的 P=16(ViT-Base/16)和 P=32(ViT-Base/32)。patch 越小,序列越长,精度越高但计算量越大(自注意力复杂度为序列长度的平方)。
  • 大规模预训练几乎必须:从头在 ImageNet-1k 上训练 ViT 容易过拟合;通常先用 MAE 或 DINO 自监督预训练,或在 JFT/ImageNet-21k 上有监督预训练,再微调。
  • 数据增强很关键:DeiT 的成功很大程度归功于 RandAugment、Mixup、CutMix 等增强策略——缺少归纳偏置的 ViT 需要更强的数据增强来弥补。
  • 位置编码的外推:标准 1D 位置编码在推理时如果输入分辨率变大(patch 更多)就会超出训练范围。常用做法是双三次插值或使用 2D 相对位置编码。
  • CLS token vs 全局池化:ViT 原始论文用 CLS token 分类,后续发现全局平均池化(GAP)效果接近且更稳健,尤其在小数据微调场景。
  • timm 是视觉 ViT 的瑞士军刀:timm.create_model() 支持 500+ 种预训练 ViT 变体,是视觉任务的首选库。
  • 2025 年实践建议:对于通用视觉特征提取,优先考虑 DINOv2 或 SigLIP 的预训练模型——它们在大量数据上自监督预训练,特征质量优于有监督 ImageNet 预训练。对于密集预测(检测、分割),Swin Transformer 或现代 CNN(ConvNeXt-V2)仍是强选择。
  • 图像分类:ImageNet 等标准基准上,ViT 及其变体(Swin、BEiT)长期占据榜首。详见CNN 主线了解 CNN 与 ViT 的对比。
  • 目标检测与分割:Swin Transformer 作为 DETR、Mask R-CNN 等检测框架的骨干网络。详见目标检测与 YOLO和图像分割。
  • CLIP / 图文检索:OpenAI CLIP 用 ViT 作为图像编码器,与文本编码器对齐,支撑了 DALL-E、Stable Diffusion 等生成模型。详见多模态模型。
  • 自监督预训练:MAE、DINO、BEiT 等基于 ViT 的自监督方法,无需标签即可学到强大的视觉表示。详见自监督学习。
  • 医学影像分析:ViT 在病理切片、X 光、MRI 等医学图像分类和分割中逐步替代 CNN,因其全局建模能力强。
  • 通用视觉编码器:DINOv2 的特征被用于深度估计、全景分割、图像检索等多种下游任务——一个预训练模型解决所有任务。
  • 视频理解:VideoMAE、TimeSformer 将 ViT 扩展到视频,在动作识别、视频检索等任务上取得 SOTA。
类库语言说明
timmPythonRoss Wightman 的 PyTorch 图像模型库,收录数百种 ViT 变体,预训练权重齐全
transformersPythonHuggingFace 库,支持 ViT、Swin、DeiT、BEiT、DINOv2、SigLIP 等,接口统一
vit-pytorchPythonPhil Wang 的轻量 ViT 实现,代码简洁,适合学习和魔改
mmsegmentationPythonOpenMMLab 的分割库,内置 Swin Transformer 等视觉骨干
jaxPythonGoogle 的 ViT 原始实现基于 JAX/Flax,BigVision 库包含官方复现
segment-anything-2PythonMeta SAM 2,基于 ViT 的通用分割模型,支持图像和视频
术语英文解释
视觉TransformerVision Transformer, ViT将图像切分为 patch 序列后用 Transformer 编码的视觉模型
图像块Patch图像被切分的小方块(如 16×16 像素),是 ViT 的基本处理单元
线性投影Linear Projection / Embedding将展平的 patch 像素向量映射到固定维度 D 的可训练线性层
分类标记CLS Token序列开头插入的可学习向量,负责聚合全局信息用于分类
位置编码Positional Encoding加到 patch 嵌入上的向量,注入空间位置信息
归纳偏置Inductive Bias模型设计内置的先验假设,如 CNN 的平移不变性和局部性
自注意力Self-Attention让序列中每个元素与其他所有元素交互的机制
掩码自编码器Masked Autoencoder, MAE随机遮挡部分 patch 并训练模型重建,是一种自监督方法
分层TransformerHierarchical Transformer如 Swin,通过合并 patch 逐层降低分辨率,类似 CNN 的金字塔结构
滑动窗口注意力Shifted Window AttentionSwin 的核心机制,将自注意力限制在局部窗口内并交替移位,大幅降低计算量
数据高效训练Data-Efficient TrainingDeiT 的核心目标,通过增强和蒸馏让 ViT 在中小数据集上也能训练好
知识蒸馏Knowledge Distillation用教师模型的输出指导学生模型训练,DeiT 用 CNN 教 ViT
视觉基础模型Visual Foundation Model在大规模数据上预训练的通用视觉编码器(如 DINOv2),可零样本用于多种下游任务
  • Dosovitskiy et al.,「An Image is Worth 16x16 Words: Transformers for Visual Recognition at Scale」(ICLR 2021):ViT 原始论文,首次证明纯 Transformer 在大规模图像识别上可以超越 CNN,里程碑之作。
  • Touvron et al.,「Training data-efficient image transformers & distillation through attention」(ICLR 2022):DeiT 论文,通过数据增强和知识蒸馏让 ViT 在 ImageNet-1k 上也能高效训练。
  • Liu et al.,「Swin Transformer: Hierarchical Vision Transformer using Shifted Windows」(ICCV 2021 Best Paper):Swin Transformer,引入分层结构和滑动窗口注意力,获得 ICCV 2021 最佳论文。
  • He et al.,「Masked Autoencoders Are Scalable Vision Learners」(CVPR 2022):MAE 论文,何恺明团队的 ViT 自监督预训练方法,简单且效果惊人。
  • Caron et al.,「Emerging Properties in Self-Supervised Vision Transformers」(ICCV 2021):DINO 论文,无需标签的 ViT 自监督训练方法,展示了 attention map 的语义分割能力。
  • Oquab et al.,「DINOv2: Learning Robust Visual Features Without Supervision」(TMLR 2024):DINOv2,Meta 的自监督视觉基础模型,在亿级数据上训练,零样本多任务能力。
  • Liu et al.,「A ConvNet for the 2020s」(CVPR 2022):ConvNeXt 论文,用 ViT 的设计选择改造 CNN,证明了架构配置而非自注意力本身是关键差异。
  • Zhai et al.,「Sigmoid Loss for Language Image Pre-Training」(ICCV 2023):SigLIP 论文,改进 CLIP 的对比学习目标。