Ir para o conteúdo

13. Vision Transformers

O capítulo anterior construiu um encoder para sequências de tokens de texto. Em 2021, Dosovitskiy et al. fizeram uma pergunta deliberadamente crua: e se você alimentar esse mesmo encoder, sem mudar nada, com uma imagem?1 A resposta — "An Image is Worth 16×16 Words" — foi que, com dados suficientes, um Transformer quase puro bate uma CNN em classificação de imagens, sem nenhuma convolução em lugar nenhum.

O resultado importou menos como número de classificação e mais como demonstração: a arquitetura não precisa saber que está olhando para uma imagem. É por isso que o ViT é o capítulo-ponte. Uma vez que você o tenha, os encoders de imagem dentro do CLIP, dentro de todo modelo de visão-linguagem, dentro do Stable Diffusion e do DiT deixam de ser coisas separadas a aprender.

O trade-off de viés indutivo, com o preço certo

O capítulo 10 chamou a convolução de um prior forte, barato e fixo. Uma camada de auto-atenção não tem nada disso: cada patch pode atender a qualquer outro patch desde a primeira camada e qualquer noção de que pixels vizinhos têm relação precisa ser aprendida dos dados.

Isso é uma troca, não uma melhoria e o artigo original mediu os dois lados dela:

Dados de pré-treino Resultado
Só ImageNet-1k (~1,3M de imagens) O ViT perde para uma ResNet comparável
ImageNet-21k (~14M) Aproximadamente empatados
JFT-300M (~300M) O ViT vence e transfere melhor

Leia a tabela como uma única frase: o prior convolucional é um piso em escala pequena e um teto em escala grande. Abaixo de um certo limiar de dados, ele dá de graça o que o Transformer precisa comprar; acima dele, proíbe relações que o Transformer fica livre para descobrir.

Esse limiar não é lei da natureza e ele se moveu

O DeiT2 mostrou que boa parte da afirmação "o ViT precisa de 300M de imagens" era, na verdade, "o ViT precisa de uma receita de treino que ninguém tinha escrito ainda" — com a augmentation, a regularização e um token de destilação certos, um ViT treina de forma competitiva só com o ImageNet-1k. O ConvNeXt8 depois fez o argumento simétrico do outro lado. A leitura moderna é que receita e escala explicam a maior parte do buraco que os artigos de 2021 atribuíram à arquitetura.

O pipeline

O único mecanismo genuinamente novo é o primeiro passo. Tudo depois dele é o encoder que você já conhece.

Uma imagem \(x \in \mathbb{R}^{H \times W \times C}\) é cortada em patches \(P \times P\) sem sobreposição, cada um achatado e projetado por uma única camada linear compartilhada:

\[ x \in \mathbb{R}^{H \times W \times C} \;\xrightarrow{\text{patchify}}\; x_p \in \mathbb{R}^{N \times (P^2 C)} \;\xrightarrow{\;E\;}\; z \in \mathbb{R}^{N \times d}, \qquad N = \frac{HW}{P^2} \]

Para \(224 \times 224\) e \(P = 16\), são \(N = 196\) tokens. Embeddings posicionais são somados, porque a atenção sozinha não distingue o patch do canto superior esquerdo do canto inferior direito e a sequência atravessa \(L\) blocos de encoder pré-norm padrão.

O patch embedding é uma convolução

Uma projeção linear sobre patches \(P \times P\) sem sobreposição é exatamente Conv2d(C, d, kernel_size=P, stride=P) e é assim que toda implementação faz — uma operação que divide em patches e projeta ao mesmo tempo. Ou seja, a afirmação "sem convoluções" tem um asterisco: há exatamente uma, no início e é o único lugar por onde um prior espacial entra no modelo.

O tamanho do patch é toda a decisão de projeto

\(P\) controla duas coisas ao mesmo tempo, em direções opostas e não há mais nada num ViT com tanta alavancagem.

Tudo que está dentro de um patch é comprimido em um vetor de dimensão \(d\) antes de a atenção sequer rodar. Nenhuma camada posterior recupera o que a projeção descartou. Arraste o tamanho do patch até 32 e veja um rosto desaparecer dentro de quatro tokens.

Puxe para o outro lado e a contagem explode: reduzir \(P\) pela metade quadruplica \(N\) e o termo de atenção cresce com \(N^2\). Dobrar a resolução faz o mesmo. Essa única quadrática é a razão pela qual:

  • 14 e 16 são os tamanhos de patch quase universais, há cinco anos;
  • modelos de visão-linguagem em alta resolução ladrilham uma imagem grande em vários recortes de 224 ou 336 pixels em vez de alimentar o encoder com uma grade enorme;
  • o patch-and-pack no estilo NaViT9 existe — empacotar imagens de resolução variável numa única sequência, manter a proporção nativa e pular os tokens de que não se precisa.

O que mudou desde 2021

O ViT de 2021 ainda é reconhecível, mas um modelo que você baixaria hoje difere em cinco pontos e todos valem a pena porque aparecem no encoder de visão de todo modelo multimodal.

  • O token [CLS] praticamente saiu de cena


    Ler a classe de um token especial era um hábito herdado do BERT. A maioria dos encoders atuais usa global average pooling ou uma pequena cabeça de attention-pooling sobre os tokens de patch — tão bom ou melhor e remove um token estranho que precisa ser treinado para ser um resumo.

    E num modelo de visão-linguagem a cabeça de classificação sumiu por completo: o que é passado ao modelo de linguagem são os tokens de patch, projetados no espaço de embedding do LLM.

  • Posições aprendidas → RoPE 2-D


    Embeddings posicionais absolutos aprendidos precisam ser interpolados sempre que a resolução muda e essa interpolação custa acurácia. A RoPE 2-D — a rotação do capítulo 11, aplicada separadamente aos eixos de linha e coluna — é relativa por construção e absorve mudança de resolução sem cirurgia.

  • Tokens de registro


    ViTs treinados colocam atenção enorme em alguns patches de fundo sem significado — usando-os como rascunho, o que destrói os mapas de atenção e prejudica tarefas densas. Acrescentar um punhado de tokens de registro10 sem uso dá ao modelo onde guardar esse estado. Os artefatos somem, os mapas de atenção voltam a ser interpretáveis e as métricas de predição densa melhoram. Uma correção de uma linha para um bug de cinco anos.

  • Hierarquia, onde ela é necessária


    Um ViT simples mantém uma resolução do começo ao fim, o que é desperdício para detecção e segmentação. O Swin3 reintroduziu atenção em janelas e uma pirâmide; o ViTDet mostrou que um ViT simples também pode ser adaptado com uma pirâmide de features por cima. Os dois estão vivos; o backbone simples venceu para pré-treino, o hierárquico para tarefas densas downstream.

Para que serve um ViT, de fato, em 2026

Muito pouco do uso em produção é "classifique esta imagem em 1000 classes". O ViT venceu ao se tornar a forma padrão de transformar pixels em tokens para outra coisa:

Uso O que o ViT fornece
Modelos de visão-linguagem O encoder de imagem. Tokens de patch são projetados e prefixados à sequência de texto — é assim que modelos da classe GPT-4o, Claude e Gemini enxergam.
Contrastivo imagem-texto A torre de imagem do CLIP e do SigLIP (capítulo 19) e portanto o condicionamento de texto de todo gerador de imagens.
Features auto-supervisionadas O DINOv2/v37 produz features densas de propósito geral sem rótulos, que batem as supervisionadas em segmentação, profundidade e correspondência — usadas congeladas, como extrator, em robótica e imagem médica.
Backbones generativos DiT e MMDiT são ViTs operando sobre patches latentes em vez de patches de pixel (capítulo 22).
Pré-treino mascarado MAE6 — mascare 75% dos patches e reconstrua. Barato (o encoder só vê os 25% visíveis) e um forte inicializador.

A razão pela qual ele venceu não é acurácia

Um ViT e uma ConvNet moderna pontuam praticamente igual no ImageNet. O ViT está em toda parte mesmo assim, porque ele emite uma sequência de tokens no mesmo formato que o texto usa. Concatenar tokens de patch com tokens de palavra e rodar um único Transformer sobre os dois é trivial; fazer o equivalente com um mapa de features convolucional, não. O argumento é multimodalidade, não classificação.

CNN vs. ViT, atualizado

CNN Vision Transformer
Operação central Convolução (local, fixa) Auto-atenção (global, aprendida)
Viés indutivo Forte Fraco — comprado com dados
Campo receptivo Cresce com a profundidade Global na camada 1
Custo \(O(\text{pixels})\) \(O(N^2)\) em patches
Poucos dados Vence Precisa de pré-treino ou de receita estilo DeiT
Dados em escala web Satura antes Continua melhorando
Uso multimodal Desajeitado Nativo — ele já emite tokens
Ainda padrão em Autoencoders latentes, segmentação médica, dispositivo Tudo que fica antes de um LLM

Referência de implementação

import torch, torch.nn as nn

class PatchEmbed(nn.Module):
    """Imagem -> sequência de tokens de patch. Um Conv2d faz patchify E projeção."""
    def __init__(self, patch=16, in_ch=3, dim=768):
        super().__init__()
        self.proj = nn.Conv2d(in_ch, dim, kernel_size=patch, stride=patch)

    def forward(self, x):                    # (B, C, H, W)
        x = self.proj(x)                     # (B, dim, H/p, W/p)
        return x.flatten(2).transpose(1, 2)  # (B, N, dim)
class ViT(nn.Module):
    """Registros no lugar do token CLS, mean pooling no lugar da cabeça no CLS."""
    def __init__(self, dim=768, depth=12, heads=12, n_classes=1000,
                 n_patches=196, n_registers=4):
        super().__init__()
        self.patch_embed = PatchEmbed(dim=dim)
        self.reg = nn.Parameter(torch.zeros(1, n_registers, dim))
        self.pos = nn.Parameter(torch.zeros(1, n_patches, dim))
        layer = nn.TransformerEncoderLayer(dim, heads, dim * 4, activation='gelu',
                                           norm_first=True, batch_first=True)
        self.encoder, self.norm = nn.TransformerEncoder(layer, depth), nn.LayerNorm(dim)
        self.head = nn.Linear(dim, n_classes)
        self.n_reg = n_registers

    def forward(self, x):
        x = self.patch_embed(x) + self.pos
        x = torch.cat([self.reg.expand(x.size(0), -1, -1), x], dim=1)
        x = self.encoder(x)[:, self.n_reg:]      # descarta os registros; eram rascunho
        return self.head(self.norm(x).mean(dim=1))
import timm
# um ViT supervisionado, ajustado para suas classes
model = timm.create_model('vit_base_patch16_224', pretrained=True, num_classes=10)

# features do DINOv2, congeladas — em geral a opção mais forte quando há poucos rótulos
dino = torch.hub.load('facebookresearch/dinov2', 'dinov2_vitb14')
feats = dino.forward_features(img)['x_norm_patchtokens']   # (B, N, 768)

Pontos principais

  1. Um ViT é o encoder de texto aplicado a patches de imagem. A única parte nova é o patchify — e isso é uma convolução com passo.
  2. O prior convolucional é um piso em escala pequena e um teto em escala grande. É toda a troca.
  3. O limiar de dados de 2021 era em grande parte um problema de receita. DeiT e ConvNeXt fecharam o buraco pelos dois lados.
  4. O tamanho do patch é a decisão de projeto: a informação dentro de um patch é destruída antes de a atenção rodar, e \(N\) cresce quadraticamente quando \(P\) encolhe ou a resolução sobe. 14–16 é onde o meio-termo cai.
  5. Um encoder atual usa pooling no lugar do [CLS], RoPE 2-D no lugar de posições aprendidas e tokens de registro para absorver os artefatos de atenção.
  6. ViTs venceram porque emitem tokens, que é o que um modelo de linguagem come. A pontuação de classificação nunca foi o ponto.
  7. Em produção, um ViT costuma ser o encoder de visão de outra coisa: um VLM, CLIP/SigLIP, features do DINOv2, ou um backbone de difusão.


  1. Dosovitskiy, A., et al. (2021). An Image is Worth 16×16 Words: Transformers for Image Recognition at Scale — ICLR. ↩

  2. Touvron, H., et al. (2021). Training data-efficient image transformers & distillation through attention (DeiT) — ICML. A receita que removeu a exigência do JFT-300M. ↩

  3. Liu, Z., et al. (2021). Swin Transformer: Hierarchical Vision Transformer using Shifted Windows — ICCV. ↩

  4. Vaswani, A., et al. (2017). Attention Is All You Need — NeurIPS. (O bloco de encoder que o ViT reaproveita, sem mudanças.) ↩

  5. Steiner, A., et al. (2021). How to train your ViT? Data, Augmentation, and Regularization in Vision Transformers — TMLR. ↩

  6. He, K., et al. (2022). Masked Autoencoders Are Scalable Vision Learners — CVPR. Mascare 75%, codifique só o que está visível. ↩

  7. Oquab, M., et al. (2024). DINOv2: Learning Robust Visual Features without Supervision — TMLR. Features auto-supervisionadas boas o bastante para usar congeladas. ↩

  8. Liu, Z., et al. (2022). A ConvNet for the 2020s (ConvNeXt) — CVPR. ↩

  9. Dehghani, M., et al. (2023). Patch n' Pack: NaViT, a Vision Transformer for any Aspect Ratio and Resolution — NeurIPS. ↩

  10. Darcet, T., Oquab, M., Mairal, J., & Bojanowski, P. (2024). Vision Transformers Need Registers — ICLR. Os tokens-artefato de norma alta, diagnosticados e corrigidos. ↩