引言
Transformer架构最初在2017年由Vaswani等人提出,主要用于自然语言处理任务。然而,近年来这一架构在计算机视觉领域展现出惊人的潜力,彻底改变了传统卷积神经网络(CNN)主导的局面。
Vision Transformer(ViT)的出现标志着视觉领域的一个重要转折点:
- 打破了CNN在视觉任务中的垄断地位
- 提供了全局感受野的建模能力
- 实现了跨模态的统一架构设计
本文将深入探讨Transformer在计算机视觉中的应用原理、技术细节和实践方法。
Transformer基础
Transformer的核心思想是基于自注意力机制,它能够捕捉序列中元素之间的长距离依赖关系。原始Transformer包含编码器和解码器两部分,但在视觉任务中主要使用编码器部分。
自注意力机制
自注意力机制通过计算查询(Query)、键(Key)和值(Value)之间的关系来建模依赖:
其中,\( d_k \)是键向量的维度,用于缩放点积结果。
多头注意力
多头注意力允许模型同时关注不同位置的子空间表示:
每个注意力头学习不同的表示模式,增强了模型的表达能力。
视觉Transformer
Vision Transformer(ViT)将图像分割成固定大小的图像块(patches),将这些图像块线性嵌入后加上位置编码,然后输入到标准的Transformer编码器中。
图像块处理
给定输入图像 \( x \in \mathbb{R}^{H \times W \times C} \),将其分割为 \( N \) 个图像块:
其中 \( P \) 是图像块大小,\( N = HW/P^2 \) 是图像块数量。
位置编码
由于Transformer本身不包含位置信息,ViT使用可学习的位置编码来保留空间信息:
其中 \( E \) 是图像块嵌入矩阵,\( E_{\text{pos}} \) 是位置编码。
优缺点
- 优点:全局感受野,无需手工设计卷积核,在大数据集上表现优异
- 缺点:需要大量训练数据,计算复杂度随序列长度平方增长
注意力机制
注意力机制是Transformer的核心,它允许模型在处理每个图像块时关注所有其他图像块,从而建立全局依赖关系。
注意力可视化
通过可视化注意力权重,我们可以理解模型关注的重点区域:
图1: Vision Transformer中不同注意力头关注的不同图像区域
不同的注意力头学习关注图像的不同方面,有些关注物体边界,有些关注纹理特征。
计算复杂度
自注意力的计算复杂度为 \( O(N^2d) \),其中 \( N \) 是序列长度,\( d \) 是特征维度。
应用场景
Transformer在计算机视觉中的成功应用已经扩展到多个领域:
- 图像分类:ViT在ImageNet等基准数据集上达到state-of-the-art性能
- 目标检测:DETR(Detection Transformer)使用Transformer进行端到端目标检测
- 语义分割:SETR等模型将分割任务转化为序列到序列的问题
- 图像生成:Transformer用于自回归图像生成,如Image GPT
图2: Vision Transformer在不同视觉任务中的应用架构
代码实现
下面我们使用PyTorch实现一个简化的Vision Transformer模型:
import torch
import torch.nn as nn
import math
class PatchEmbedding(nn.Module):
def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768):
super().__init__()
self.img_size = img_size
self.patch_size = patch_size
self.n_patches = (img_size // patch_size) ** 2
self.proj = nn.Conv2d(in_chans, embed_dim,
kernel_size=patch_size,
stride=patch_size)
def forward(self, x):
x = self.proj(x) # (B, E, H/P, W/P)
x = x.flatten(2) # (B, E, N)
x = x.transpose(1, 2) # (B, N, E)
return x
注意力模块实现
实现多头自注意力机制:
class MultiHeadAttention(nn.Module):
def __init__(self, dim, num_heads=8, qkv_bias=False):
super().__init__()
self.num_heads = num_heads
head_dim = dim // num_heads
self.scale = head_dim ** -0.5
self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
self.proj = nn.Linear(dim, dim)
def forward(self, x):
B, N, C = x.shape
qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads)
qkv = qkv.permute(2, 0, 3, 1, 4)
q, k, v = qkv[0], qkv[1], qkv[2]
attn = (q @ k.transpose(-2, -1)) * self.scale
attn = attn.softmax(dim=-1)
x = (attn @ v).transpose(1, 2).reshape(B, N, C)
x = self.proj(x)
return x
完整ViT模型
组合各个模块构建完整的Vision Transformer:
class VisionTransformer(nn.Module):
def __init__(self, img_size=224, patch_size=16, in_chans=3,
num_classes=1000, embed_dim=768, depth=12,
num_heads=12, mlp_ratio=4.0):
super().__init__()
self.patch_embed = PatchEmbedding(img_size, patch_size,
in_chans, embed_dim)
num_patches = self.patch_embed.n_patches
self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))
self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim))
self.blocks = nn.ModuleList([
TransformerBlock(embed_dim, num_heads, mlp_ratio)
for _ in range(depth)
])
self.norm = nn.LayerNorm(embed_dim)
self.head = nn.Linear(embed_dim, num_classes)
def forward(self, x):
B = x.shape[0]
x = self.patch_embed(x)
cls_tokens = self.cls_token.expand(B, -1, -1)
x = torch.cat((cls_tokens, x), dim=1)
x = x + self.pos_embed
for block in self.blocks:
x = block(x)
x = self.norm(x)
cls_token_final = x[:, 0]
return self.head(cls_token_final)
与传统CNN对比
Transformer和CNN在计算机视觉中各有优势,理解它们的差异有助于在实际项目中做出合适的选择。
架构差异
- 感受野:ViT具有全局感受野,CNN的感受野受卷积核大小限制
- 归纳偏置:CNN内置平移不变性和局部性,ViT需要从数据中学习
- 计算效率:CNN在小数据集上更高效,ViT在大数据集上表现更好
性能对比
在ImageNet数据集上的表现:
图3: Vision Transformer与传统CNN在ImageNet数据集上的性能对比
随着数据量的增加,ViT的优势变得更加明显。
结论
Transformer架构在计算机视觉领域的成功应用标志着视觉理解技术的一个重要里程碑。从最初的NLP领域迁移到视觉任务,Transformer展现出了强大的适应能力和卓越的性能。
关键要点总结:
- ViT通过图像块分割和位置编码成功将图像转化为序列
- 自注意力机制提供了全局上下文建模能力
- 在大规模数据集上,ViT超越了传统CNN的性能
- 计算复杂度是需要优化的关键问题
未来,我们可以期待更多混合架构的出现,结合CNN的局部性和Transformer的全局建模能力,为计算机视觉带来新的突破。同时,效率优化和在小数据集上的应用将是重要的研究方向。