Phase 07 - Lesson 09
Vision Transformers (ViT)
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
Una imagen es una cuadrícula de parches. Una oración es una cuadrícula de tokens. El mismo transformer consume ambos.
Tipo: Build Lenguajes: Python Requisitos previos: Fase 7 · 05 (Transformer Completo), Fase 4 · 03 (CNNs), Fase 4 · 14 (Introducción a Vision Transformers) Tiempo: ~45 minutos
El Problema
Antes de 2020, la visión computacional significaba convoluciones. Cada SOTA en ImageNet, COCO y los benchmarks de detección utilizaba un backbone CNN. Los transformers eran para el lenguaje.
Dosovitskiy et al. (2020) — "An Image is Worth 16x16 Words" — demostraron que se pueden descartar las convoluciones por completo. Corta una imagen en parches de tamaño fijo, proyecta linealmente cada parche en un embedding y alimenta la secuencia a un encoder de transformer vanilla. A una escala suficiente (preentrenamiento en ImageNet-21k o superior), ViT iguala o supera a los modelos basados en ResNet.
ViT fue el inicio de un patrón más amplio en 2026: una arquitectura, múltiples modalidades. Whisper tokeniza audio. ViT tokeniza imágenes. Tokens de acción para robótica. Tokens de píxel para video. Al transformer no le importa — aliméntalo con una secuencia y aprenderá.
Para 2026, ViT y sus descendientes (DeiT, Swin, DINOv2, ViT-22B, SAM 3) dominan la mayor parte de la visión. Las CNN aún ganan en dispositivos de borde (edge) y tareas sensibles a la latencia. Todo lo demás tiene un ViT en alguna parte del stack.
El Concepto
Paso 1 — patchify (crear parches)
Divide una imagen de H × W × C en una secuencia N × (P·P·C) de parches aplanados. Configuración típica: imagen de 224 × 224, parches de 16 × 16 → 196 parches de 768 valores cada uno.
image (224, 224, 3) → 14 × 14 grid of 16x16x3 patches → 196 vectors of length 768
El tamaño del parche es la palanca. Parches más pequeños = más tokens, mejor resolución, costo de atención cuadrático. Parches más grandes = más gruesos, más económicos.
Paso 2 — linear embedding (embedding lineal)
Una única matriz aprendida proyecta cada parche aplanado a d_model. Equivalente a una convolución con un tamaño de kernel P y un stride P. En PyTorch, esto es literalmente nn.Conv2d(C, d_model, kernel_size=P, stride=P) — una implementación de 2 líneas.
Paso 3 — prepended del token [CLS], agregar embeddings posicionales
- Agrega al principio (prepend) un token
[CLS]aprendible. Su estado oculto final es la representación de la imagen utilizada para la clasificación. - Agrega embeddings posicionales aprendibles (ViT original) o sinusoidales 2D (variantes posteriores).
- En 2024+ RoPE se extendió a 2D para la posición, a veces sin embeddings explícitos.
Paso 4 — encoder de transformer estándar
Apila L bloques de LayerNorm → Self-Attention → + → LayerNorm → MLP → +. Idéntico a BERT. Sin capas específicas de visión. Este es el punto clave pedagógico del artículo.
Paso 5 — cabeza (head)
Para clasificación: toma el estado oculto de [CLS] → lineal → softmax. Para DINOv2 o SAM, descarta [CLS] y usa los embeddings de parches directamente.
Variantes que importaron
| Modelo | Año | Cambio |
|---|---|---|
| ViT | 2020 | El original. Tamaño de parche fijo, atención global completa. |
| DeiT | 2021 | Destilación; entrenable únicamente en ImageNet-1k. |
| Swin | 2021 | Jerárquico con ventanas desplazadas (shifted windows). Costo subcuadrático fijo. |
| DINOv2 | 2023 | Autossupervisado (sin etiquetas). Mejores características (features) generales de visión. |
| ViT-22B | 2023 | 22B de parámetros; se aplican las leyes de escala. |
| SigLIP | 2023 | ViT + par de lenguaje, pérdida contrastiva sigmoide. |
| SAM 3 | 2025 | Segment anything; ViT-Large + decoder de máscara basado en prompts. |
Por qué tomó un tiempo
ViT necesita muchos datos para igualar a las CNN porque no tiene ninguno de los sesgos inductivos de las CNN (invariancia de traslación, localidad). Sin más de 100M de imágenes etiquetadas o un fuerte preentrenamiento autossupervisado, las CNN siguen ganando con el mismo presupuesto de cómputo. DeiT solucionó esto en 2021 con trucos de destila-ción; DINOv2 lo solucionó de forma permanente en 2023 con autossupervisión.
Construye
Consulta code/main.py. Patchify puro con stdlib + linear embedding + controles de sanidad. Sin entrenamiento — ViT a cualquier escala realista necesita PyTorch y horas de GPU.
Paso 1: imagen falsa
Una imagen RGB de 24 × 24 como una lista de filas de tuplas (R, G, B). Usamos parches de 6×6 → 16 parches, con un vector de embedding de 108 dimensiones cada uno.
Paso 2: patchify
def patchify(image, P):
H = len(image)
W = len(image[0])
patches = []
for i in range(0, H, P):
for j in range(0, W, P):
patch = []
for di in range(P):
for dj in range(P):
patch.extend(image[i + di][j + dj])
patches.append(patch)
return patches
Orden raster: por filas (row-major) a lo largo de la cuadrícula. Todos los ViT utilizan este orden.
Paso 3: linear embed
Multiplica cada parche aplanado por una matriz aleatoria de (patch_flat_size, d_model). Verifica que la forma de salida sea (N_patches + 1, d_model) después de agregar el token [CLS] al principio.
Paso 4: contar parámetros para un ViT realista
Imprime el conteo de parámetros para ViT-Base: 12 capas, 12 cabezas, d=768, patch=16. Compáralo con ResNet-50 (~25M). ViT-Base se sitúa en ~86M. ViT-Large ~307M. ViT-Huge ~632M.
Úsalo
from transformers import ViTImageProcessor, ViTModel
import torch
from PIL import Image
processor = ViTImageProcessor.from_pretrained("google/vit-base-patch16-224-in21k")
model = ViTModel.from_pretrained("google/vit-base-patch16-224-in21k")
img = Image.open("cat.jpg")
inputs = processor(img, return_tensors="pt")
out = model(**inputs).last_hidden_state # (1, 197, 768): [CLS] + 196 patches
cls_emb = out[:, 0] # image representation
Los embeddings de DINOv2 son el estándar de 2026 para características de imagen. Congela el backbone, entrena una cabeza diminuta. Funciona para clasificación, recuperación (retrieval), detección y generación de leyendas (captioning). Los checkpoints de DINOv2 de Meta superan a CLIP en cada tarea de visión no textual.
Selección del tamaño de parche. Los modelos pequeños usan 16×16 (ViT-B/16). La predicción densa (segmentación) usa 8×8 o 14×14 (SAM, DINOv2). Los modelos muy grandes usan 14×14.
Entrégalo
Consulta outputs/skill-vit-configurator.md. La skill selecciona una variante de ViT y un tamaño de parche para una nueva tarea de visión según el tamaño del conjunto de datos, la resolución y el presupuesto de cómputo.
Ejercicios
- Fácil. Ejecuta
code/main.py. Verifica que el número de parches sea igual a(H/P) * (W/P)y que la dimensión del parche aplanado sea igual aP*P*C. - Medio. Implementa embeddings posicionales sinusoidales 2D — dos códigos sinusoidales independientes para la fila (
row) y la columna (col) de cada parche, concatenados. Aliméntalos a un ViT diminuto en PyTorch y compara la precisión vs. los embeddings posicionales aprendibles en CIFAR-10. - Difícil. Construye un ViT de 3 capas (PyTorch), entrénalo en 1,000 imágenes de MNIST con parches de 4×4. Mide la precisión de prueba. Ahora añade el preentrenamiento de DINOv2 en las mismas 1,000 imágenes (simplificado: solo entrena el encoder para predecir embeddings de parches a partir de parches enmascarados). ¿Mejora la precisión?
Términos Clave
| Término | Lo que la gente dice | Lo que realmente significa |
|---|---|---|
| Parche (Patch) | "El token del vision-transformer" | Vector plano de valores de píxeles para una región de P × P × C de la imagen. |
| Patchify | "Cortar + aplanar" | Cortar la imagen en parches que no se solapan y aplanar cada uno en un vector. |
Token [CLS] |
"El resumen de la imagen" | Token aprendible agregado al principio; su embedding final es la representación de la imagen. |
| Sesgo inductivo | "Lo que el modelo asume" | ViT tiene menos supuestos previos que las CNN; necesita más datos para compensar la diferencia. |
| DINOv2 | "ViT autossupervisado" | Entrenado sin etiquetas mediante aumento de imágenes + profesor de momentum (momentum teacher). Mejores características de imagen generales en 2026. |
| SigLIP | "El sucesor de CLIP" | ViT + encoder de texto entrenado con pérdida contrastiva sigmoide; mejor que CLIP con el mismo presupuesto de cómputo. |
| Swin | "ViT en ventanas" | ViT jerárquico con atención local + ventanas desplazadas (shifted windows); subcuadrático. |
| Tokens de registro | "Truque de 2023" | Algunos tokens aprendibles adicionales que absorben los sinks de atención; mejora las características de DINOv2. |
Lectura Adicional
- Dosovitskiy et al. (2020). An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale — el artículo de ViT.
- Touvron et al. (2021). Training data-efficient image transformers & distillation through attention — DeiT.
- Liu et al. (2021). Swin Transformer: Hierarchical Vision Transformer using Shifted Windows — Swin.
- Oquab et al. (2023). DINOv2: Learning Robust Visual Features without Supervision — DINOv2.
- Darcet et al. (2023). Vision Transformers Need Registers — la solución de tokens de registro para DINOv2.