PyTorch 深度学习专题【左扬精讲】—— 注意力机制与 Transformer:在视觉任务中超越 CNN

PyTorch 深度学习专题【左扬精讲】—— 注意力机制与 Transformer:在视觉任务中超越 CNN

从 ResNet 到 Faster R-CNN,我们见证了 CNN 在视觉任务中的强大能力。但近年来,注意力机制(Attention Mechanism)和 Vision Transformer(ViT)正在逐步超越传统 CNN,成为新的主流架构。

本文将系统讲解 Transformer 在计算机视觉中的核心应用:ViT、Swin Transformer、DETR、SegFormer 和 CLIP,帮助你理解从卷积世界到注意力世界的范式转变。

torchvision.models.vit_b_16                              ← torchvision 官方 ViT 实现(ViT-B/16)
timm.create_model('swin_base_patch4_window7_224')        ← timm 加载 Swin Transformer
torch.hub.load('facebookresearch/detr', 'detr_resnet50') ← DETR(PyTorch Hub)
transformers.AutoModelForSemanticSegmentation.from_pretrained("nvidia/segformer-b0-finetuned-ade-512-512") ← SegFormer(HuggingFace)
transformers.CLIPModel.from_pretrained("openai/clip-vit-base-patch32") ← CLIP(双编码器)

PyTorchTransformerViTSwin TransformerDETRSegFormerCLIP注意力机制HuggingFacetimm

学习重点

  • 必须掌握
  • 自注意力机制(Self-Attention)的原理:Q/K/V 矩阵与缩放点积注意力
  • ViT 的核心设计:Patch Embedding、CLS Token、位置编码
  • Swin Transformer 的分层架构与 Shifted Window 机制
  • DETR 的端到端检测:无 Anchor、无 NMS 的 Transformer 编码器-解码器
  • 理解即可
  • SegFormer 的 MLP 解码器与无位置编码设计
  • CLIP 的对比学习与双编码器架构
  • 混合架构(CNN+Transformer)的发展趋势

目录


一、从 CNN 到 Transformer:视觉模型的范式转变

Why — 为什么 Transformer 能在视觉任务中超越 CNN?

CNN 通过局部感受野和权重共享提取特征,天然适合处理图像的层次化结构。但 CNN 的局限也很明显:每个卷积核只能捕捉局部信息,需要堆叠很多层才能建模长距离依赖(Long-range Dependency),而这对理解图像中分散但相关的区域(如一只手和一只脚属于同一个人)至关重要。Transformer 的自注意力机制允许每个位置直接关注序列中所有其他位置,能高效建模任意距离的依赖关系,突破了 CNN 的感受野限制。

CNN vs Transformer 核心区别

维度CNN(ResNet 等)Transformer(ViT 等)
特征交互 局部感受野,层层堆叠扩大 全局自注意力,直接建模任意位置关系
权重共享 空间域卷积核权重共享 Query/Key/Value 投影权重共享
长距离依赖 需要深层堆叠(如 ResNet-152) 单层即可建模全局依赖
位置感知 隐式(卷积天然编码空间位置) 显式(需添加位置编码)
计算复杂度 O(HW × k²)(局部,k 为核大小) O((HW)²)(全局自注意力)
数据依赖 小数据集即可有效训练 大规模预训练数据效果更佳

视觉 Transformer 发展时间线

  • 2017 年:《Attention Is All You Need》—— Transformer 首次提出,用于 NLP 任务
  • 2020 年:ViT 论文《An Image is Worth 16×16 Words》—— 首次将标准 Transformer 直接应用于图像
  • 2021 年:Swin Transformer 论文—— 提出分层窗口注意力机制
  • 2020 年:DETR 论文—— Transformer 端到端目标检测
  • 2021 年:SegFormer 论文—— 高效 Transformer 语义分割
  • 2021 年:CLIP 论文—— 对比学习统一视觉与语言

本节小结

  • 注意力机制:允许直接建模任意距离的依赖关系,突破 CNN 局部感受野的限制
  • 范式转变:从"层次化局部滤波"到"全局自注意力建模"
  • 数据依赖:Transformer 在大规模预训练数据上收益更大

二、自注意力机制:Transformer 的核心

What — 自注意力机制是什么?

自注意力(Self-Attention,也称缩放点积注意力,Scaled Dot-Product Attention)是 Transformer 的核心组件。它通过 Query(查询)、Key(键)和 Value(值)三个向量,在序列内部建立任意两个位置之间的依赖关系。与 CNN 的局部滤波不同,自注意力的每个输出位置都能关注到输入序列的所有位置,因此天然适合建模长距离依赖。

Self-Attention 的数学表达

对于输入序列 X = [x₁, x₂, ..., x_N],首先通过三个线性投影生成 Q、K、V:

  • Q = X · W_Q(Query:当前位置想要查询的信息)
  • K = X · W_K(Key:每个位置存储的"索引键")
  • V = X · W_V(Value:每个位置存储的"内容值")

注意力输出为:

Attention(Q, K, V) = softmax(Q · Kᵀ / √d_k) · V
# √d_k:缩放因子,防止点积过大导致 softmax 梯度消失
# softmax(Q·Kᵀ):计算 Query 对每个 Key 的相似度,归一化为注意力权重

Multi-Head Attention(多头注意力)

将 Q、K、V 分别投影到 h 个不同的子空间(每个头独立学习不同的注意力模式),然后拼接:

MultiHead(Q, K, V) = Concat(head₁, ..., head_h) · W_O
head_i = Attention(Q·W_Qᵢ, K·W_Kᵢ, V·W_Vᵢ)
# h 个头并行计算,最终拼接后投影
# 每个头关注不同的语义层面(如一个头关注物体颜色,一个关注纹理,一个关注空间关系)
PyTorch 多头自注意力从零实现
import torch
import torch.nn as nn
import torch.nn.functional as F
import math

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model=512, num_heads=8):
        super().__init__()
        assert d_model % num_heads == 0
        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads  # 每个头的维度

        # 三个线性投影:Q, K, V
        self.W_Q = nn.Linear(d_model, d_model)
        self.W_K = nn.Linear(d_model, d_model)
        self.W_V = nn.Linear(d_model, d_model)
        # 最终输出投影
        self.W_O = nn.Linear(d_model, d_model)

    def forward(self, query, key, value, mask=None):
        batch_size = query.size(0)

        # 线性投影后分头:[B, N, d_model] → [B, num_heads, N, d_k]
        Q = self.W_Q(query).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        K = self.W_K(key).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        V = self.W_V(value).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)

        # 缩放点积注意力:[B, h, N, N]
        scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
        if mask is not None:
            scores = scores.masked_fill(mask == 0, -1e9)
        attn_weights = F.softmax(scores, dim=-1)
        # 加权求和:[B, h, N, d_k]
        context = torch.matmul(attn_weights, V)

        # 合并多头:[B, h, N, d_k] → [B, N, d_model]
        context = context.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
        return self.W_O(context), attn_weights

# 示例
attn = MultiHeadAttention(d_model=512, num_heads=8)
x = torch.randn(2, 10, 512)  # [batch=2, seq_len=10, d_model=512]
output, weights = attn(x, x, x)  # 自注意力
print(f"输出尺寸: {output.shape}")  # torch.Size([2, 10, 512])
print(f"注意力权重尺寸: {weights.shape}")  # torch.Size([2, 8, 10, 10])

多头注意力的核心优势在于每个头可以关注不同的语义特征:一个头关注物体的颜色模式,一个头关注纹理边缘,一个头关注空间位置关系。8 个头的输出拼接后通过 W_O 投影融合,使模型能同时从多个角度理解输入。

本节小结

  • Q/K/V 投影:Query 查找、Key 索引、Value 取值,三者分离使注意力更灵活
  • 缩放因子 √d_k:防止点积过大导致 softmax 梯度消失
  • 多头注意力:并行 h 个独立的注意力头,拼接后投影,每个头关注不同语义层面
  • O(N²) 复杂度:序列长度 N 的二次方,是 Transformer 的主要计算瓶颈

三、Vision Transformer(ViT):将图像视为序列

What — ViT 是什么?

ViT(Vision Transformer)由 Google Brain 团队在 2020 年提出(论文《An Image is Worth 16×16 Words》),是首次将标准 Transformer 编码器直接应用于图像分类的工作。ViT 的核心思想与 NLP 中的标准 Transformer 完全一致:将图像切分为固定大小的 Patch,将每个 Patch 视为一个"词 token",然后用标准 Transformer 编码器处理这些 Patch 序列。

Why — ViT 为什么需要大规模预训练?

问题:Transformer 缺乏 CNN 的局部归纳偏置,需要更多数据来学习视觉模式

CNN 的卷积操作天然具有平移不变性和局部性(每个卷积核只在局部窗口内操作),这使得 CNN 在相对较小的数据集(如 ImageNet-1K,约 130 万张图像)上也能有效学习。而 ViT 将图像视为无结构的 Patch 序列,模型需要从头学习图像的 2D 空间结构——Patch 之间的相对位置、相邻 Patch 的连续性等都需要从数据中统计。Google 的实验表明:在 ImageNet-1K(约 130 万张)上,ViT 效果不如 ResNet;但在 ImageNet-21K(约 1400 万张)或 JFT-300M(3 亿张)大规模数据上预训练后,ViT 大幅超越 CNN。因此,ViT 的成功高度依赖大规模预训练。

ViT 架构的四步流程

  1. Patch Embedding:将 224×224×3 图像切分为 16×16×3 的 Patch,共 14×14=196 个。每个 Patch 展平为 768 维向量(16×16×3=768),通过线性投影映射到 D 维嵌入空间
  2. 添加特殊 Token(CLS Token):在序列最前面插入一个可学习的 [CLS] token(class token),最终用 [CLS] token 的输出作为图像级别的分类表示(类似 BERT 的 [CLS])
  3. 添加位置编码:为每个 Patch 添加可学习的位置嵌入(1D 位置编码),使模型感知空间位置关系
  4. 标准 Transformer 编码器:N 个 Transformer Block(标准架构:LayerNorm → MSA → Add → LayerNorm → MLP → Add)
ViT 流水线图解
输入图像 224×224×3
        │
        ▼
┌─────────────────────────────────────────────────────────┐
│  Patch Embedding(16×16×3 Patch,步长 16)              │
│  224×224 → 14×14 = 196 个 Patch                       │
│  每个 Patch 展平为 768 维 → 线性投影为 D 维            │
│  输出:[196, D] 序列                                   │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────────┐
│  [CLS] Token(可学习的特殊分类 token)                 │
│  拼接在序列最前面:[1, D]                              │
│  最终序列长度:197 = 196 Patch + 1 [CLS]               │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────────┐
│  位置编码(可学习的 1D 位置嵌入,加到每个 Patch 上)   │
│  pos ∈ R^(197 × D)                                    │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────────┐
│  Transformer 编码器(N 个 Block)                       │
│  Block = LayerNorm → Multi-Head Attention → Add          │
│          → LayerNorm → MLP → Add                        │
│  MLP = GELU(Linear(D, 4D)) → Linear(4D, D)            │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────────┐
│  取 [CLS] Token 的输出                                 │
│  → LayerNorm → Linear(D, num_classes) → 分类预测      │
└─────────────────────────────────────────────────────────┘
ViT PyTorch 官方加载方式(torchvision)
import torch
import torchvision.models as models

# torchvision 官方 ViT 实现(ViT-B/16,224×224 输入)
model = models.vit_b_16(weights=models.ViT_B_16_Weights.DEFAULT)
model.eval()

# 输入预处理(权重自带 transforms)
preprocess = models.ViT_B_16_Weights.DEFAULT.transforms()
x = torch.randn(1, 3, 224, 224)
x_processed = preprocess(x).unsqueeze(0)

# 前向传播
with torch.no_grad():
    output = model(x_processed)
print(f"输出尺寸: {output.shape}")  # torch.Size([1, 1000])

# 其他变体(patch size 不同)
vit_b_32 = models.vit_b_32(weights=models.ViT_B_32_Weights.DEFAULT)  # Patch 32×32
vit_l_16 = models.vit_l_16(weights=models.ViT_L_16_Weights.DEFAULT)  # ViT-L/16,更大模型

# 注意:torchvision 的 ViT 不包含 Detection/Segmentation 等下游任务头
# 如需更丰富的 ViT 变体,推荐使用 timm 库
# pip install timm

ViT 与 CNN 的关键数值对比

模型参数量ImageNet Top-1训练数据
ViT-B/16(从头训练) 86M ~68% ImageNet-1K
ViT-B/16(预训练) 86M 84.2% ImageNet-21K
ViT-L/16(预训练,JFT-300M) 307M 87.1% JFT-300M
ViT-L/16(预训练,ImageNet-21K) 307M 85.1% ImageNet-21K
ResNet-152(标准) 60M 82.0% ImageNet-1K

在 ImageNet-1K 小数据集上,ViT 不如同等计算量的 CNN;但在大规模预训练后,ViT 大幅超越 CNN,证明 Transformer 在大规模数据上的 Scalability 优势。

本节小结

  • Patch Embedding:16×16 Patch → 展平 → 线性投影,将图像转为序列
  • CLS Token:可学习的特殊 token,用作图像级分类表示
  • 1D 位置编码:可学习的位置嵌入,ViT 论文发现 2D 位置编码无显著收益
  • 大规模预训练:ViT 的成功依赖 ImageNet-21K 或更大数据集的预训练
  • torchvision API:models.vit_b_16(weights=...)

四、Swin Transformer:分层注意力替代全局注意力

What — Swin Transformer 是什么?

Swin Transformer(Shifted Windows Transformer)由微软团队在 2021 年提出(ICCV 2021 最佳论文),是针对视觉任务专门优化的分层 Transformer。其核心创新是:不在整个特征图上做全局自注意力,而是在非重叠的局部窗口内计算注意力,并通过 Shifted Window(窗口偏移)机制实现跨窗口信息交互。这使计算复杂度从全局注意力的 O((HW)²) 降低到 O(HW·M²)(M 为窗口大小,通常 M=7),同时保持对全局信息的建模能力。

Why — ViT 的全局注意力有什么问题?

问题:ViT 的全局自注意力在图像分辨率上计算量巨大,难以高效处理高分辨率图像

对于 224×224 图像,ViT 处理 196 个 Patch,全局注意力矩阵大小为 196×196。但对于 1280×800 的高分辨率图像(如检测/分割任务),Patch 数会急剧增加到 4000+(以 16×16 为单位),注意力矩阵达到 4000×4000,计算量和显存都无法承受。Swin Transformer 通过分层(Hierarchical)结构和窗口注意力,在保持对大物体建模能力的同时,将计算量控制在 O(HW) 级别,可以自然处理高分辨率图像。

分层设计(Hierarchical Representation)

Swin Transformer 通过类似 CNN 的分层结构,在每个 Stage 内部将特征图空间分辨率减半、通道数翻倍:

  • Stage 1:H/4 × W/4 分辨率,C₁ 通道(如 96)
  • Stage 2:H/8 × W/8 分辨率,C₂ 通道(如 192)
  • Stage 3:H/16 × W/16 分辨率,C₃ 通道(如 384)
  • Stage 4:H/32 × W/32 分辨率,C₄ 通道(如 768)

这种分层结构使 Swin Transformer 可以像 ResNet 一样直接作为 FPN 等检测/分割任务的 Backbone。

Shifted Window 机制图解
Layer l(常规窗口注意力):
┌─────────────────────────┐
│  [a][a][a][a]│[b][b][b][b] │
│  [a][a][a][a]│[b][b][b][b] │
│  [a][a][a][a]│[b][b][b][b] │
│  [a][a][a][a]│[b][b][b][b] │
├──────────┼──────────────────┤
│  [c][c][c][c]│[d][d][d][d] │
│  [c][c][c][c]│[d][d][d][d] │
│  [c][c][c][c]│[d][d][d][d] │
│  [c][c][c][c]│[d][d][d][d] │
└──────────┴──────────────────┘
  窗口内自注意力(每个窗口独立计算,无跨窗口交互)

Layer l+1(偏移窗口注意力):
┌─────────────────────────┐
│  [d]│[c][c][c][c]│[c][d]│
│  [d]│[c][c][c][c]│[c][d]│
│  [d]│[c][c][c][c]│[c][d]│
│  [d]│[c][c][c][c]│[c][d]│
├──────────┼──────────────────┤
│  [b]│[a][a][a][a]│[a][b]│
│  [b]│[a][a][a][a]│[a][b]│
│  [b]│[a][a][a][a]│[a][b]│
│  [b]│[a][a][a][a]│[a][b]│
└──────────┴──────────────────┘
  偏移 (⌊M/2⌋, ⌊M/2⌋) 后,窗口重新划分
  跨越原窗口边界的注意力 → 实现跨窗口信息传递
  零填充区域用 attention mask 遮蔽

Shifted Window 的工作原理

相邻的两个 Swin Transformer Block 交替使用两种窗口划分策略:

  • Block l(W-MSA):使用常规窗口划分(从左上角开始,等分为 M×M 的不重叠窗口),每个窗口内独立计算自注意力
  • Block l+1(SW-MSA):窗口向右下角偏移 (⌊M/2⌋, ⌊M/2⌋) 像素,重新划分窗口。这样新窗口会跨越原窗口的边界,从而实现跨窗口的信息传递

偏移后产生的非规则窗口(包含部分填充零的区域),通过注意力掩码(Attention Mask)动态遮蔽不相关区域,保持计算量不变。这种巧妙的交替设计在控制计算复杂度的同时,实现了类似全局注意力的跨区域信息流动。

Swin Transformer 加载方式(timm 库)
# timm 库提供完整的 Swin Transformer 系列模型
# pip install timm
import timm

# Swin-B(基础版):patch_size=4,window_size=7,224×224 输入
model = timm.create_model(
    'swin_base_patch4_window7_224.ms_in22k_ft_in1k',  # ImageNet-22K 预训练 + 1K 微调
    pretrained=True
)
model.eval()
print(f"Swin-B 参数量: {sum(p.numel() for p in model.parameters()):,}")

# 用于下游任务:移除分类头,获取分层特征
model_feat = timm.create_model(
    'swin_base_patch4_window7_224.ms_in22k_ft_in1k',
    pretrained=True,
    num_classes=0,  # 移除分类头
    features_only=True  # 获取所有 Stage 的特征图
)
# model_feat 输出 4 个 Stage 的特征图(类似 ResNet)
print(model_feat.feature_info.info)  # 查看各 Stage 的分辨率和通道数

# Swin-S / Swin-T(更小版本)
swin_small = timm.create_model('swin_small_patch4_window7_224.ms_in22k_ft_in1k', pretrained=True)
swin_tiny  = timm.create_model('swin_tiny_patch4_window7_224.ms_in22k_ft_in1k', pretrained=True)

# timm 同样支持 Swin Transformer 的分割/检测变体
# swin_base_patch4_window7_224_in22k(ImageNet-22K 预训练)
# swin_large_patch4_window7_224(更大模型)

Swin Transformer 各变体对比(ImageNet-1K Top-1)

模型窗口大小参数量Top-1 准确率
Swin-T 7×7 28M 81.3%
Swin-S 7×7 50M 83.0%
Swin-B 7×7 88M 83.5%
Swin-L 7×7 196M 87.0%

本节小结

  • 分层设计:每个 Stage 分辨率减半、通道数翻倍,适配检测/分割等多尺度任务
  • Shifted Window:窗口内局部注意力 + 偏移实现跨窗口交互,O(HW·M²) 复杂度
  • 计算高效:M=7 固定窗口大小,图像分辨率增加时计算量线性增长
  • timm 加载:timm.create_model('swin_base_patch4_window7_224.ms_in22k_ft_in1k')

五、DETR:端到端目标检测,无需 Anchor 和 NMS

What — DETR 是什么?

DETR(DEtection TRansformer)由 Facebook AI(现 Meta)团队在 2020 年提出(ECCV 2020),是首个将 Transformer 应用于目标检测的端到端方法。DETR 的核心创新是:将目标检测重新定义为一个直接的集合预测(Set Prediction)问题,通过 Transformer 编码器-解码器架构和二分匹配损失,实现了无需预定义 Anchor、无需 NMS 后处理的目标检测。

Why — DETR 为什么能去掉 Anchor 和 NMS?

问题:传统检测器依赖 Anchor 枚举尺度和长宽比,NMS 处理重复检测,计算流程复杂且包含许多手工设计的组件

Faster R-CNN 和 SSD 等传统检测器需要精心设计 Anchor 的尺度和比例(Anchor-box engineering),以及复杂的 NMS 后处理来去除重复检测框。这些手工设计的组件增加了系统的复杂度。DETR 的解决方案是:直接让 Transformer 解码器输出固定数量的预测框(N=100),每个预测框包含类别和边界框坐标,通过二分匹配(匈牙利算法)将预测框与真实框一一对应,训练损失直接作用于这个对应关系。因此 DETR 天然不需要 Anchor 和 NMS。

DETR 的三个核心组件

  • CNN Backbone:ResNet-50(或 ResNet-101),将输入图像 H×W×3 转换为更小的特征图(如 d×(H/32)×(W/32))
  • Transformer 编码器:对 Backbone 特征图做全局自注意力,捕捉图像内不同区域之间的关系
  • Transformer 解码器:接收固定数量的可学习 Object Queries(如 100 个),每个 Query attend 到编码器输出的图像特征,输出对应的类别和边界框
DETR 流水线图解
输入图像 (H×W×3)
        │
        ▼
┌─────────────────────────────────────────────────────┐
│  CNN Backbone(ResNet-50)                            │
│  → 输出特征图 d×(H/32)×(W/32),展平为序列          │
│  → 添加空间位置编码(2D 正弦编码)                  │
└─────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────┐
│  Transformer 编码器(标准 Encoder)                    │
│  序列长度 = (H/32)×(W/32),如 7×7=49               │
│  → 全局自注意力:每个 Patch 关注图像内所有区域       │
└─────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────┐
│  Transformer 解码器                                  │
│  输入:N=100 个可学习 Object Queries                 │
│  → Cross-Attention:Query attend 到编码器特征       │
│  输出:N 个预测 [class, bbox]                       │
│  → 无需 NMS,直接输出最终检测结果                  │
└─────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────┐
│  FFN 检测头(Feed-Forward Network)                  │
│  每个 Query → 91 类分类 + 边界框回归(x,y,w,h)    │
│  加上 "no object" 类用于无物体 Query               │
└─────────────────────────────────────────────────────┘
        │
        ▼
   输出:N 个预测(其中大部分为 "no object",非重复)
DETR 加载方式(PyTorch Hub / HuggingFace)
# 方式一:PyTorch Hub(Facebook 官方)
import torch
model = torch.hub.load(
    'facebookresearch/detr:main',
    'detr_resnet50',
    pretrained=True
)
model.eval()

# 推理
from PIL import Image
img = Image.open("image.jpg")
from torchvision import transforms
transform = transforms.Compose([
    transforms.Resize(800),
    transforms.ToTensor(),
])
img_tensor = transform(img).unsqueeze(0)

with torch.no_grad():
    output = model(img_tensor)
# output['pred_boxes']: [batch, 100, 4] (归一化坐标)
# output['pred_logits']: [batch, 100, 91] (COCO 91 类)
# output['pred_labels']: 预测类别索引

# 方式二:HuggingFace Transformers
# pip install transformers
from transformers import DetrImageProcessor, DetrForObjectDetection
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
model_hf = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
model_hf.eval()

inputs = processor(images=img, return_tensors="pt")
outputs = model_hf(**inputs)
# 后处理:转换到原始图像坐标
target_sizes = torch.tensor([img.size[::-1]])
results = processor.post_process_object_detection(
    outputs, target_sizes=target_sizes, threshold=0.9
)[0]
for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
    print(f"类别={label}, 置信度={score:.3f}, 框={box}")

DETR vs Faster R-CNN 核心区别

维度Faster R-CNNDETR
检测范式 两阶段(RPN → 检测头) 端到端集合预测
Anchor 机制 需要预设 Anchor(尺度和长宽比) 无需 Anchor(Object Queries 隐式学习)
NMS 后处理 需要(NMS 筛选重叠框) 不需要(集合预测无重复)
训练方式 每样本各自优化 二分匹配 + 匈牙利算法全局匹配
COCO mAP 约 42-48% 约 42-44%(收敛较慢)
小物体检测 较强(RPN 候选区精修) 较弱(缺少多尺度特征融合)

本节小结

  • 端到端集合预测:固定 N=100 个 Object Queries,直接输出检测结果
  • 二分匹配损失:匈牙利算法将预测与真实框一一对应,避免重复检测
  • 无 Anchor / 无 NMS:简化检测流程,消除手工设计的组件
  • 收敛慢:DETR 训练需要更长时间收敛(通常需要更长的训练计划)
  • PyTorch Hub API:torch.hub.load('facebookresearch/detr', 'detr_resnet50')

六、SegFormer:轻量级 Transformer 语义分割

What — SegFormer 是什么?

SegFormer 由 NVIDIA 团队在 2021 年提出(论文《SegFormer: Simple and Efficient Design for Semantic Segmentation with Transformers》),是一种结合分层 Transformer 编码器和轻量级全 MLP(多层感知机)解码器的语义分割框架。SegFormer 的核心优势在于:编码器使用分层 Transformer(类似 Swin),提供多尺度特征;解码器使用简单的 MLP(无卷积),避免了复杂的上采样和 Skip Connection 设计;同时,SegFormer 移除了传统 Transformer 中的位置编码,避免了推理分辨率变化时需要重新插值位置编码的问题。

Why — SegFormer 为什么高效?

问题:传统语义分割网络(如 FCN、DeepLabV3)的解码器结构复杂,需要大量手工设计;传统 Transformer 需要位置编码,推理分辨率变化时性能下降

SegFormer 通过两个关键设计解决上述问题:

  • 轻量级 MLP 解码器:不做复杂的转置卷积或 Concat 拼接,而是将 Transformer 编码器输出的多尺度特征图分别用 MLP 映射到统一维度后,做简单的加权融合(All-MLP Decoder)。参数量极小(如 SegFormer-B0 仅约 3.4M 参数),但融合了局部和全局特征
  • 无位置编码(Positional-Encoding-Free):SegFormer 的编码器(MiT)在每个阶段使用重叠的 Patch Embedding(Overlapping Patch Embedding),隐式地编码位置信息,无需可学习或正弦位置编码。这样在不同推理分辨率下不需要重新插值,性能不会下降

MiT(Mix Transformer)编码器

SegFormer 的编码器 MiT 是对 PVT(Pyramid Vision Transformer)的改进,Stage 1-4 逐步降低分辨率、提高通道数,提供多尺度特征(对应 CNN 的 C1-C4 层级)。与 Swin 的 Shifted Window 不同,MiT 使用局部注意力 + 重叠 Patch Embedding 的组合,在保持高效的同时建模局部和全局特征。

SegFormer 加载方式(HuggingFace Transformers)
# pip install transformers
from transformers import AutoImageProcessor, AutoModelForSemanticSegmentation
import torch
from PIL import Image

# SegFormer-B0(最小版,实时分割)
model = AutoModelForSemanticSegmentation.from_pretrained(
    "nvidia/segformer-b0-finetuned-ade-512-512"
)
processor = AutoImageProcessor.from_pretrained("nvidia/segformer-b0-finetuned-ade-512-512")
model.eval()

# 推理
img = Image.open("image.jpg")
inputs = processor(images=img, return_tensors="pt")
with torch.no_grad():
    outputs = model(**inputs)
    logits = outputs.logits  # [1, num_classes, H/4, W/4]
print(f"分割 logits 尺寸: {logits.shape}")  # torch.Size([1, 150, 128, 128])

# 上采样到原始分辨率并取 argmax
pred = logits.argmax(dim=1)
print(f"预测分割图尺寸: {pred.shape}")  # torch.Size([1, 512, 512])

# SegFormer-B0 ~ B5 精度/速度权衡(B0 最快,B5 最准)
# B0: 约 3.4M 参数,实时
# B3: 约 47.3M 参数,高精度
# B5: 约 84.7M 参数,最高精度

# 多尺度特征融合原理
# Stage 1 输出: [B, C1, H/4, W/4]  → MLP → [B, 256, H/4, W/4]  (高分辨率,局部特征)
# Stage 2 输出: [B, C2, H/8, W/8]  → MLP → [B, 256, H/8, W/8]  (中分辨率)
# Stage 3 输出: [B, C3, H/16, W/16] → MLP → [B, 256, H/16, W/16]
# Stage 4 输出: [B, C4, H/32, W/32] → MLP → [B, 256, H/32, W/32]
# → 全部上采样到 H/4×W/4 → 加权求和 → 1×1 卷积 → 分割 logits

SegFormer 性能对比(ADE20K 验证集 mIoU)

模型参数量mIoUGFLOPS
SegFormer-B0 3.4M 37.4% 0.6
SegFormer-B1 13.7M 42.5% 2.1
SegFormer-B4 64.1M 50.3% 10.1
SegFormer-B5 84.7M 53.2% 11.8
DeepLabV3+(传统 CNN) 59.7M 48.0% 37.9

本节小结

  • All-MLP 解码器:轻量级 MLP 加权融合多尺度特征,无复杂上采样设计
  • 无位置编码:Overlapping Patch Embedding 隐式编码位置,避免分辨率变化时的插值问题
  • MiT 编码器:分层 Transformer,输出 4 个 Stage 的多尺度特征
  • HuggingFace API:AutoModelForSemanticSegmentation.from_pretrained("nvidia/segformer-b0-finetuned-ade-512-512")

七、CLIP:视觉-语言统一建模

What — CLIP 是什么?

CLIP(Contrastive Language-Image Pre-training)由 OpenAI 在 2021 年提出(论文《Learning Transferable Visual Models From Natural Language Supervision》),是一种通过自然语言监督学习可迁移视觉模型的方法。CLIP 的核心创新是:训练一个视觉编码器和一个文本编码器,使配对的图像-文本样本在联合嵌入空间中距离更近,不配对的样本距离更远。这种对比学习(Contrastive Learning)方式使 CLIP 在没有任何 ImageNet 类别标签的情况下,通过自然语言描述即可进行零样本分类(Zero-Shot Classification)。

Why — 为什么 CLIP 能实现零样本分类?

问题:传统视觉模型只能在预定义的固定类别集合上做分类(如 ImageNet 1000 类),无法泛化到开放词汇

CLIP 的解决思路是"语言-视觉对齐":在训练时,CLIP 同时看到图像和描述这些图像的自然语言文本(如"A photo of a cat"),学习将图像和对应文本映射到同一嵌入空间。推理时,给定一张图像和任意文本描述(如"A photo of a dog"、"A photo of a car"),计算图像嵌入与所有文本嵌入的余弦相似度,选择相似度最高的文本作为分类结果。这意味着 CLIP 可以对任意文本描述的类别进行分类,真正实现了开放词汇(Open-Vocabulary)分类。

CLIP 的双编码器架构

  • 视觉编码器:两种选择——(1)改进版 ResNet(RN50、RN101 等),或(2)ViT(ViT-B/32、ViT-L/14 等)
  • 文本编码器:标准 Transformer(12 层,512 宽,8 头),输入为句子 token 序列(Byte Pair Encoding 编码,词汇表 49152),输出文本嵌入
  • 训练目标:InfoNCE 对比损失,最大化配对图像-文本的余弦相似度,最小化不配对的相似度
CLIP 流水线图解
训练阶段:
┌──────────────────────┐     ┌──────────────────────┐
│  图像批次(N 张)    │     │  文本批次(N 句)    │
│  224×224×3          │     │  "A photo of a cat"  │
└──────────┬───────────┘     └──────────┬───────────┘
           ▼                                  ▼
┌──────────────────────┐     ┌──────────────────────┐
│  视觉编码器          │     │  文本编码器          │
│  (ViT / RN50)       │     │  (Transformer)       │
│  → I₁, I₂, ..., I_N │     │  → T₁, T₂, ..., T_N │
└──────────┬───────────┘     └──────────┬───────────┘
           │                                  │
           ▼                                  ▼
     [I₁·T₁]  [I₁·T₂]  ...  [I₁·T_N]  ← 计算余弦相似度矩阵 N×N
     [I₂·T₁]  [I₂·T₂]  ...  [I₂·T_N]     对角线为配对(正样本)
     [ ...  ]  [ ...  ]  ...  [ ...  ]     其余为不配对(负样本)
     [IN·T₁]  [IN·T₂]  ...  [IN·TN]
           │
           ▼
     InfoNCE 损失:对角线 softmax 交叉熵

推理阶段(零样本分类):
  图像 → 视觉编码器 → I_embed (512维)
                    │
  ["A photo of a cat", "A photo of a dog", ...]  ← 任意文本类别
        ↓
  文本 → 文本编码器 → T_embed₁, T_embed₂, ...
                    │
  计算余弦相似度 I_embed · T_embed₁ / (||I||·||T||)
                    │
              取 argmax → 最高相似度对应的文本类别
CLIP 加载方式(官方 pip 包)
# pip install clip
import clip
import torch
from PIL import Image

# 加载模型和预处理(ViT-B/32 或 ViT-L/14)
model, preprocess = clip.load("ViT-B/32", device="cuda" if torch.cuda.is_available() else "cpu")
model.eval()

# 准备图像和文本
image = preprocess(Image.open("image.jpg")).unsqueeze(0).to(device)
text = clip.tokenize([
    "a photo of a cat",
    "a photo of a dog",
    "a photo of a car",
    "a photo of a bird",
]).to(device)

# 编码
with torch.no_grad():
    image_features = model.encode_image(image)
    text_features = model.encode_text(text)

# 归一化后计算余弦相似度
image_features /= image_features.norm(dim=-1, keepdim=True)
text_features /= text_features.norm(dim=-1, keepdim=True)
similarity = (100.0 * image_features @ text_features.T).softmax(dim=-1)

# 输出各类别概率
labels = ["cat", "dog", "car", "bird"]
for i, label in enumerate(labels):
    print(f"{label}: {similarity[0, i].item():.4f}")

# 零样本检测示例(任意文本描述)
prompt = clip.tokenize(["a sports ball", "a traffic light", "a parking meter"]).to(device)
prompt_features = model.encode_text(prompt)
score = (image_features @ prompt_features.T).softmax(dim=-1)
print(f"零样本检测: {score.argmax().item()}")

# 注意:torchvision 不包含 CLIP 实现,需使用官方 clip 包
# pip install clip
# 另有 OpenCLIP(LAION 开源实现)提供更多 CLIP 变体

CLIP 模型变体对比

视觉编码器视觉层数视觉宽度Patch 大小参数量
RN50 - 64 - 约 38M
ViT-B/32 12 768 32×32 约 151M
ViT-B/16 12 768 16×16 约 151M
ViT-L/14 24 1024 14×14 约 428M
ViT-L/14@336px 24 1024 14×14 约 428M

本节小结

  • 双编码器架构:视觉编码器(ViT/RN)+ 文本编码器(Transformer)分别编码两个模态
  • 对比学习目标:InfoNCE 损失使配对图像-文本在联合嵌入空间中对齐
  • 零样本分类:推理时通过计算图像嵌入与任意文本嵌入的余弦相似度,选择最近似的类别
  • 开放词汇:不依赖固定类别标签,可对任意自然语言描述的类别做分类
  • pip clip 包:clip.load("ViT-B/32"),torchvision 不含 CLIP

八、FAQ(20 组)

FAQ — 精选 20 问,深入理解视觉 Transformer

Q1. 为什么 ViT 需要大量数据预训练,而 CNN 不需要?

CNN 的卷积操作天然具有局部性和平移不变性的归纳偏置(Inductive Bias),在相对较小的数据集上也能有效学习;ViT 将图像视为无结构的 Patch 序列,缺乏对图像 2D 空间结构的先验知识,必须从大规模数据中学习这些模式。 CNN 的每个卷积核只在局部窗口内操作,并随着网络加深逐步扩大感受野——这与图像的空间层次结构高度吻合。ViT 将 16×16 的 Patch 视为独立 token,不假设相邻 Patch 之间有任何结构关系,需要通过海量数据来统计学习 Patch 之间的空间关联。实验表明:在 ImageNet-1K(约 130 万张)上,ViT 效果不如 ResNet;但在 ImageNet-21K(约 1400 万张)上预训练后,ViT 明显超越 CNN。

Q2. Self-Attention 中的缩放因子 √d_k 有什么作用?

缩放因子防止点积值过大导致 softmax 梯度消失。当 d_k 较大时,Q·Kᵀ 的方差与 d_k 成正比,数值可能很大,使 softmax 接近 one-hot 分布,梯度趋近于零。 具体来说:如果 Q 和 K 的各分量是均值为 0、方差为 1 的独立随机变量,则 Q·Kᵀ 的点积均值仍为 0,但方差为 d_k。当 d_k=512 时,点积的方差是 512,会使 softmax 输入值过大。乘以 1/√d_k 将方差归一化回 1,确保 softmax 的梯度在合理范围内。d_k=64 时,缩放后方差为 1,这正是原始 Transformer 论文中选择 d_k=64 的原因之一。

Q3. Swin Transformer 的 Shifted Window 为什么能保持跨窗口信息流动?

Shifted Window 通过在相邻 Block 之间偏移窗口划分,使新窗口跨越原窗口边界,从而让原本属于不同窗口的 Patch 之间产生交互,实现跨窗口信息传递。 具体机制:Block l 的窗口从左上角开始划分(如 4 个不重叠的 M×M 窗口);Block l+1 的窗口向右下角偏移 ⌊M/2⌋ 像素,此时新窗口 A 会包含来自原窗口 1、2、3、4 的 Patch。注意力计算时,Patch A 中的 Query 可以 attend 到所有包含它的窗口中的 Key,从而实现跨窗口信息交换。这种偏移-常规交替设计在保持 O(HW·M²) 恒定计算量的同时,赋予了模型类似全局注意力的跨区域建模能力。

Q4. DETR 的二分匹配(Bipartite Matching)是如何工作的?

DETR 使用匈牙利算法(Hungarian Algorithm)在预测的 N 个框和真实的 M 个框(M ≤ N)之间找到最优的一一对应关系,使得总损失最小。 具体步骤:计算所有 N×M 对(预测框,真实框)的匹配成本(如类别负对数似然 + L1 边界框损失);运行匈牙利算法在 O(N²·M) 时间内找到最优匹配;只对匹配到的预测框计算检测损失,未匹配的预测框(对应"no object"类)损失为零。这与 Faster R-CNN 中每个 Anchor 独立计算损失不同,DETR 的匹配是全局最优的,确保每个真实框恰好对应一个预测框,因此自然不需要 NMS 去重。

Q5. 为什么 DETR 的收敛速度比 Faster R-CNN 慢很多?

DETR 需要更长时间训练的原因有两点:一是 Transformer 的随机初始化需要大量训练步数才能收敛到稳定状态;二是 DETR 的注意力机制在训练初期难以正确聚焦到物体区域,需要逐步学习。 Faster R-CNN 通过 RPN 提供高质量的候选区,降低了检测头的学习难度。DETR 则从零开始让 Object Queries 学习在图像中找到物体——前几个 epoch 中,Object Queries 可能漫无目的地 attend 到背景区域。只有经过充分的训练后,DETR 才能学会将不同 Query 分配给图像中不同的物体。实践中,DETR 通常需要训练 300-500 个 epoch(而 Faster R-CNN 只需 12-36 个 epoch)。

Q6. SegFormer 的 All-MLP 解码器相比 FCN/DeepLabV3 的解码器有什么优势?

All-MLP 解码器参数量极小(仅约 4M 参数),且通过简单的加权融合直接聚合多尺度特征,无需复杂的 Skip Connection 或转置卷积设计。 FCN/DeepLabV3 的解码器涉及转置卷积(反卷积)或空洞上采样,设计复杂且参数量较大。SegFormer 的 MLP 解码器将编码器输出的 4 个 Stage 特征分别通过各自的 MLP 映射到统一通道数(256 维),然后全部上采样到最高分辨率(H/4×W/4),最后逐像素加权求和得到分割 logits。这种设计避免了 decoder 中卷积核和复杂连接的学习,使模型更高效且更易训练。

Q7. CLIP 为什么使用对比学习而不是生成式方法(如描述生成)?

对比学习在配对图像-文本数据上的效率远高于生成式方法,OpenAI 的实验发现对比目标的零样本迁移效率比生成目标高 3-10 倍。 生成式方法(如 captioning)要求模型为每张图像生成精确的文本描述,需要逐字生成,难度远高于"判断图像和文本是否匹配"。CLIP 的 InfoNCE 目标只需判断配对关系,任务更简单、信号更直接。训练时每个 batch 有 N 个图像-文本对,需要 2N 次编码(而不是 N×T 次,假设每张图生成 T 个 token),计算效率也更高。

Q8. ViT 中的 [CLS] Token 能否用平均池化替代?

理论上可以,但 [CLS] Token 在实践中通常表现更好,主要原因是 [CLS] Token 可以通过注意力机制从所有 Patch 中选择性提取信息,而平均池化是对所有 Patch 的平等对待。 在 BERT 中,[CLS] Token 最终表示用作分类嵌入,其上方还有一个额外的分类层。ViT 直接使用 [CLS] Token 的输出做分类。如果使用平均池化(对所有 Patch 嵌入求平均),每个 Patch 对分类的贡献权重相同,而 [CLS] Token 通过自注意力的加权机制,可以学习哪些 Patch 对当前分类任务更重要。研究表明 [CLS] Token 的收敛速度和最终精度通常优于平均池化。

Q9. Swin Transformer 中 Window Size(M)如何选择?

Window Size M 控制局部注意力的范围:M 越大,建模的局部上下文越丰富,但计算量增加(M² 增长);M 越小,窗口越多,跨窗口通信需要更多 Shifted Window Block 来弥补。 Swin 论文默认使用 M=7(即每个窗口 7×7=49 个 Patch),这是一个在建模能力和计算效率之间的折中选择。如果任务需要更大的局部感受野(如大物体分割),可以选择更大的 M(如 14);如果需要在有限显存下处理更高分辨率的图像,可以选择更小的 M(如 7)。M 的选择与 Patch Size(决定序列长度)和图像分辨率有关。

Q10. Transformer 的位置编码(Positional Encoding)和位置嵌入(Positional Embedding)有什么区别?

位置编码是固定的数学函数(如正弦/余弦)直接加到输入上,不可学习;位置嵌入是可学习的参数表,通过查表获得,可随训练优化。ViT 默认使用可学习的位置嵌入。 在原始 Transformer 论文(NLP)中,使用的是正弦位置编码 PE(pos, 2i) = sin(pos/10000^(2i/d)),其中 pos 是位置,i 是维度索引。这种编码是确定性的、对任意长度序列都适用(通过外推)。在视觉 Transformer 中,可学习的位置嵌入更为常见(ViT 默认使用),参数在训练中学习。SegFormer 则通过 Overlapping Patch Embedding 隐式编码位置信息,完全移除了显式位置编码,使其可以处理任意分辨率的输入而不需要重新插值。

Q11. DETR 中的 Object Queries 是什么?它们是如何初始化的?

Object Queries 是解码器的一组可学习的位置嵌入(默认 N=100 个),每个 Query 代表一个"检测槽位",模型通过学习使不同 Query 关注图像中的不同物体。 Object Queries 是解码器的输入嵌入,与图像内容无关(无图像信息注入),完全通过训练从数据中学习。在训练初期,所有 Queries 的输出可能是相似的(模型不知道如何分配);经过充分训练后,不同 Query 会专注于不同类型/位置/尺度的物体。例如,Query 1 可能学会检测大尺寸物体,Query 2 检测小物体,Query 3 检测人,Query 4 检测车辆。这种"槽位分配"机制是 DETR 端到端学习的结果,无需手工设计 Anchor。

Q12. SegFormer 为什么能处理任意推理分辨率而不需要重新插值位置编码?

SegFormer 的 MiT 编码器通过 Overlapping Patch Embedding(重叠 Patch 嵌入)隐式编码位置信息,无需可学习或固定的位置编码,因此推理分辨率变化时不需要重新插值。 传统的 ViT 使用非重叠的 Patch Embedding(Patch 之间完全不重叠),位置信息完全依赖外部添加的位置编码。而 MiT 使用重叠的 Patch Embedding(相邻 Patch 之间有重叠区域),重叠本身就提供了位置线索。此外,SegFormer 的 MLP 解码器工作在低分辨率(H/4×W/4)上,不需要原始分辨率的特征。实验表明,SegFormer 在分辨率从训练时的 512×512 变化到 640×640 或更大时,性能不会显著下降。

Q13. 为什么说 Swin Transformer 比 ViT 更适合作为检测/分割任务的 Backbone?

Swin Transformer 的分层结构(Hierarchical)输出多尺度特征图(C1-C4),天然适配 FPN 等检测/分割头的多尺度特征融合需求;而 ViT 只有一个固定分辨率的特征输出(无分层),难以直接适配密集预测任务。 目标检测和语义分割都需要多尺度特征:小物体需要高分辨率浅层特征(如 C2),大物体需要低分辨率深层特征(如 C4)。Swin Transformer 通过 Stage 间的 Patch Merging(类似 CNN 的下采样)自然产生 C1/C2/C3/C4 四个分辨率级别的特征,可直接输入 FPN 或 U-Net 等检测/分割头部。ViT 只输出单一分辨率的特征图,若要做密集预测,需要额外的上采样路径或复杂的特征金字塔设计。

Q14. CLIP 的零样本分类和传统 ImageNet 分类有什么区别?

传统 ImageNet 分类只能在预定义的 1000 个类别上分类;CLIP 的零样本分类可以对任意自然语言描述的类别做分类,不受固定标签集限制。 举例:传统模型无法识别"一只橘色的猫趴在红色的沙发上"这样的细粒度描述,而 CLIP 可以直接接受这类文本描述作为查询。CLIP 实际上将分类问题转化为相似度匹配问题:给定图像嵌入 I 和文本嵌入集合 {T₁, T₂, ..., Tₖ},计算 argmax similarity(I, Tₖ)。这意味着 CLIP 可以动态扩展类别——只需提供新的文本描述即可,不需要重新训练模型。

Q15. DETR 的收敛慢问题有没有被后续工作解决?

是的,后续工作如 Deformable DETR(可变形注意力)、Conditional DETR、DAB-DETR 等通过改进注意力机制显著加速了收敛,同时提升了检测精度。 Deformable DETR 将全局注意力替换为稀疏的局部注意力(每个 Query 只 attend 到少量采样点),使收敛速度提升 10 倍(从 500 epoch 降到 50 epoch),同时将小物体检测 mAP 提升了 7.8%。Conditional DETR 通过引入条件空间查询(Conditional Query),使解码器在第一个 epoch 内就能产生有意义的检测框。Stable DETR 则引入了更稳定的训练策略。这些改进使 Transformer 检测器在收敛速度和精度上都达到了与 Faster R-CNN 相当的水平。

Q16. 为什么 Swin Transformer 使用 GELU 激活函数而不是 ReLU?

GELU(非线性高斯误差线性单元)是一个更平滑的激活函数,在 Transformer 中被广泛采用(BERT、GPT 等也使用 GELU),因为它的导数处处连续,有助于梯度流动。 ReLU(x) = max(0, x) 在 x < 0 时梯度恒为 0,可能导致"死神经元"问题。GELU(x) = x · Φ(x)(其中 Φ 是标准正态分布的累积分布函数)是一个连续且平滑的近似-ReLU 函数,在 Transformer 的 MLP 层中通常表现更好。Swin Transformer 和 ViT 都使用 GELU 作为 MLP 的激活函数。

Q17. 视觉语言模型(VLM)如 GPT-4V 和 CLIP 有什么本质区别?

CLIP 是双编码器模型(两个独立的编码器分别处理图像和文本),适合快速的零样本分类和检索任务;GPT-4V 等是多模态大语言模型(MLLM),将视觉编码器与大语言模型(LLM)深度融合,可以做复杂的视觉问答和指令跟随。 CLIP 的视觉编码器和文本编码器独立工作,推理时通过简单的余弦相似度比较,不需要生成文本。GPT-4V 等 VLM 将图像嵌入作为 LLM 的输入 token,与文本 token 一起联合处理,可以回答"图中发生了什么"、"如果把左边的物体移走会发生什么"等需要推理的问题,能力远超 CLIP。但 CLIP 的训练成本和推理速度远低于 VLM。

Q18. 混合 CNN-Transformer 架构(如 CoAtNet)相比纯 Transformer 有什么优势?

混合架构结合了 CNN 的局部建模效率和 Transformer 的全局建模能力,在中等规模数据集上也能取得优秀表现,弥补了 ViT 对大规模数据的依赖。 CoAtNet 通过 MBConv(MobileNetV2 的倒置残差块)提取局部特征后,接入 Transformer 编码器建模全局依赖。MBConv 的局部卷积天然编码了 2D 空间归纳偏置,使模型在相对较小的数据集(如 ImageNet-1K)上也能训练有效。这解决了纯 ViT 在小数据集上表现差的问题。实验表明:CoAtNet-3 在 ImageNet-1K(仅训练 ImageNet-1K)上达到 84.5% Top-1(168M 参数);若在 ImageNet-21K 上预训练后再微调至 ImageNet-1K,则达到 87.6% Top-1,与 ViT-L/16 在 JFT-300M 上预训练后的 87.1% 相近,但所需预训练数据量大幅减少。

Q19. 为什么说 Transformer 的 O(N²) 复杂度是视觉任务的主要瓶颈?

N 为序列长度(Patch 数),对于 224×224 图像、16×16 Patch,N=196;但对于更高分辨率(如 1024×1024)或更小 Patch(如 8×8),N 可达数千甚至数万,注意力矩阵 N×N 的存储和计算变得不可承受。 举例:对于 1024×1024 图像、16×16 Patch,N=4096,注意力矩阵有 4096×4096=1677 万个元素(FP32 约 64MB)。对于视频任务(多帧图像),序列长度进一步增加。Swin Transformer 通过固定窗口大小(M=7)将复杂度降到 O(HW·M²),使其与图像分辨率成线性关系。Longformer、Performer 等工作则探索了稀疏注意力和线性注意力等替代方案。

Q20. Vision Transformer 未来发展的主要方向有哪些?

ViT 的发展方向主要包括:更高效的注意力机制(降复杂度到 O(N log N 或 O(N))、大规模多模态预训练(视觉-语言-动作统一建模)、视频/3D 点云的专用 Transformer、更强的视觉基础模型(Foundation Model)。 具体趋势:Efficient ViT:通过分组注意力、局部-全局混合注意力降低计算量(如 Swin、Swin V2、PVT);多模态大模型:GPT-4V、Gemini、LLaVA 等将视觉理解深度整合到 LLM 中;3D Vision Transformer:Point Transformer、Voxel Transformer 处理点云和体素数据;视频理解:TimeSformer、Video Swin Transformer 处理时空序列;视觉基础模型:SAM(Segment Anything Model)、DINOv2 等证明大规模自监督预训练的 ViT 可作为强大的通用视觉特征提取器。

FAQ 总结

  • ViT 数据依赖:CNN 有局部归纳偏置,ViT 需要大规模数据来学习空间结构
  • Q/K/V 注意力:Query 查找、Key 索引、Value 取值的分离设计,使注意力灵活可塑
  • Shifted Window:局部窗口注意力 + 偏移交替,实现跨窗口信息传递,O(HW·M²) 复杂度
  • DETR 端到端:Object Queries + 二分匹配,无需 Anchor 和 NMS,但收敛慢
  • SegFormer MLP 解码器:All-MLP 加权融合多尺度特征,无位置编码设计
  • CLIP 对比学习:双编码器对齐,零样本分类,开放词汇能力
  • Swin 分层 Backbone:C1-C4 多尺度输出,自然适配检测/分割任务

九、Roadmap 预告

从 CNN 到 Transformer,我们完成了计算机视觉核心架构的巡礼!

从 LeNet 的卷积滤波,到 ResNet 的残差连接,再到 ViT 的全局注意力、DETR 的端到端集合预测、Swin 的分层窗口注意力——我们见证了视觉模型十年间的范式演进。Transformer 已在分类、检测、分割、图文对齐等几乎所有视觉任务上取得或超越了 CNN 的最优表现。

但这只是开始。未来的视觉 AI 将走向何方?值得关注的下一个里程碑方向:

  • 视觉-语言-动作统一模型:将视觉感知、语言理解和机器人动作规划统一到单一的大模型中(如 RT-2、OpenVLA)
  • 视觉基础模型(Vision Foundation Model):DINOv2、SA-1B(Segment Anything)证明了大规模自监督预训练的 ViT 能作为通用的视觉特征提取器,一个模型支持检测、分割、深度估计等多种任务
  • 高效视觉 Transformer:EfficientViT、MobileViT 等将 Transformer 引入移动端,在延迟敏感的设备上实现高效推理
  • 扩散模型与视觉生成:Stable Diffusion、DiT(Diffusion Transformer)将 Transformer 与扩散过程结合,革新了图像生成任务

掌握本文的 Transformer 基础,你已经站在了视觉 AI 发展的前沿。持续关注这些前沿方向,一起探索视觉智能的无限可能!


posted @ 2026-07-19 01:09  左扬  阅读(58)  评论(0)    收藏  举报