ViT, DeiT, and Transformer Architectures for Vision
Module: Computer Vision | Difficulty: Premium
Patch Embedding
where is the embedding projection.
Multi-Head Self-Attention
Computational Complexity
- Standard attention: where
- Swin attention:
| Model | ImageNet | Params | FLOPs | Patch Size |
|---|---|---|---|---|
| ViT-B/16 | 84.2% | 86M | 17.6G | 16 |
| DeiT-B | 83.4% | 86M | 17.6G | 16 |
| Swin-B | 86.4% | 88M | 15.4G | 4 |
| Swin-L | 87.3% | 197M | 34.5G | 4 |
| ViT-G/14 | 90.2% | 1.8B | 248G | 14 |
import torch
import torch.nn as nn
import math
class PatchEmbedding(nn.Module):
def __init__(self, img_size=224, patch_size=16, in_c=3, embed_dim=768):
super().__init__()
self.num_patches = (img_size // patch_size) ** 2
self.proj = nn.Conv2d(in_c, embed_dim,
kernel_size=patch_size, stride=patch_size)
def forward(self, x):
x = self.proj(x)
x = x.flatten(2).transpose(1, 2)
return x
class TransformerBlock(nn.Module):
def __init__(self, embed_dim, num_heads, mlp_ratio=4.0, drop=0.1):
super().__init__()
self.norm1 = nn.LayerNorm(embed_dim)
self.attn = nn.MultiheadAttention(
embed_dim, num_heads, dropout=drop, batch_first=True)
self.norm2 = nn.LayerNorm(embed_dim)
self.mlp = nn.Sequential(
nn.Linear(embed_dim, int(embed_dim * mlp_ratio)),
nn.GELU(), nn.Dropout(drop),
nn.Linear(int(embed_dim * mlp_ratio), embed_dim),
nn.Dropout(drop),
)
def forward(self, x):
h = self.norm1(x)
h, _ = self.attn(h, h, h)
x = x + h
x = x + self.mlp(self.norm2(x))
return x
class ViT(nn.Module):
def __init__(self, img_size=224, patch_size=16, in_c=3,
num_classes=1000, embed_dim=768, depth=12, num_heads=12):
super().__init__()
self.patch_embed = PatchEmbedding(
img_size, patch_size, in_c, embed_dim)
num_patches = self.patch_embed.num_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.Sequential(
*[TransformerBlock(embed_dim, num_heads) 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 = self.cls_token.expand(B, -1, -1)
x = torch.cat([cls, x], dim=1)
x = x + self.pos_embed
x = self.blocks(x)
x = self.norm(x)
return self.head(x[:, 0])
Research Insight: Vision Transformers have fundamentally changed computer vision by demonstrating that NLP-style architectures can achieve state-of-the-art visual recognition. The key insight is that self-attention provides a flexible inductive bias that can learn long-range dependencies without the locality constraints of convolutions. Swin Transformer introduced hierarchical shifted windows, enabling dense prediction tasks while maintaining linear complexity. The scaling laws for vision transformers are still being discovered, with some evidence that ViTs benefit more from data scaling than CNNs.