Phase 04 - Lesson 25
Modelos de Visión-Lenguaje — El Patrón ViT-MLP-LLM
Un codificador de visión convierte una imagen en tokens. Un proyector MLP mapea esos tokens al espacio de embeddings del LLM. Un modelo de lenguaje hace el resto. Ese patrón — ViT-MLP-LLM — es todo VLM de producción en 2026.
Tipo: Aprender + Usar Lenguajes: Python Prerequisitos: Fase 4 Lección 14 (ViT), Fase 4 Lección 18 (CLIP), Fase 7 Lección 02 (Self-Attention) Tiempo: ~75 minutos
Objetivos de Aprendizaje
- Enunciar la arquitectura ViT-MLP-LLM y explicar qué aporta cada uno de los tres componentes
- Comparar Qwen3-VL, InternVL3.5, LLaVA-Next y GLM-4.6V en cantidad de parámetros, longitud de contexto y rendimiento en benchmarks
- Explicar DeepStack: por qué las características multinivel del ViT mejoran la alineación visión-lenguaje más que una sola característica de la última capa
- Medir la alucinación de VLM en producción con la Cross-Modal Error Rate (CMER) y actuar sobre la señal
El Problema
CLIP (Fase 4 Lección 18) te da un espacio de embeddings compartido para imágenes y texto, lo cual es suficiente para clasificación zero-shot y recuperación. No puede responder "¿cuántos autos rojos hay en esta imagen?" porque CLIP no genera texto — solo puntúa similitudes.
Los Modelos de Visión-Lenguaje (VLMs) — Qwen3-VL, InternVL3.5, LLaVA-Next, GLM-4.6V — acoplan un codificador de imagen de la familia CLIP a un modelo de lenguaje completo. El modelo ve una imagen más una pregunta y genera una respuesta. En 2026 los VLMs open-source rivalizan o superan a GPT-5 y Gemini-2.5-Pro en benchmarks multimodales (MMMU, MMBench, DocVQA, ChartQA, MathVista, OSWorld).
El trío de piezas (ViT, proyector, LLM) es el estándar. Las diferencias entre modelos están en cuál ViT, cuál proyector, cuál LLM, los datos de entrenamiento y la receta de alineación. Una vez que entiendes el patrón, cambiar cualquier componente es mecánico.
El Concepto
La arquitectura ViT-MLP-LLM
flowchart LR
IMG["Imagen<br/>(H x W x 3)"] --> ViT["Codificador de vision<br/>(ViT, CLIP-L,<br/>SigLIP, DINOv3)"]
ViT --> FEATS["Tokens de imagen<br/>(N, d_vit)"]
FEATS --> PROJ["Proyector<br/>(MLP de 2-4 capas<br/>o Q-former)"]
PROJ --> VTOK["Tokens de imagen<br/>en espacio del LLM<br/>(N, d_llm)"]
TXT["Prompt de texto"] --> TOK["Tokenizador del LLM"]
TOK --> TTOK["Tokens de texto<br/>(M, d_llm)"]
VTOK --> CONCAT["Intercalar<br/>o concatenar"]
TTOK --> CONCAT
CONCAT --> LLM["LLM decoder<br/>(Qwen3, LLaMA, etc.)"]
LLM --> OUT["Respuesta en texto"]
style ViT fill:#dbeafe,stroke:#2563eb
style PROJ fill:#fef3c7,stroke:#d97706
style LLM fill:#dcfce7,stroke:#16a34a
- Codificador de visión — un ViT preentrenado (CLIP-L/14, SigLIP, DINOv3 o una variante ajustada). Produce tokens de patch.
- Proyector — un módulo pequeño (MLP de 2-4 capas, o un Q-former) que mapea los tokens de visión a la dimensión de embedding del LLM. Aquí ocurre la mayor parte del fine-tuning.
- LLM — un modelo de lenguaje decoder-only (Qwen3, Llama, Mistral, GLM, InternLM). Lee los tokens de visión + texto en secuencia y genera texto.
Las tres piezas son entrenables en principio. En la práctica, el codificador de visión y el LLM permanecen mayormente congelados mientras el proyector se entrena — unos cuantos miles de millones de parámetros de señal por poco costo.
DeepStack
La proyección convencional usa solo la última capa del ViT. DeepStack (Qwen3-VL) muestrea características de múltiples profundidades del ViT y las apila. Las capas más profundas portan semántica de alto nivel; las capas más superficiales portan información espacial y de textura de grano fino. Alimentar ambas al LLM cierra la brecha entre "qué contiene la imagen" (semántica) y "dónde exactamente" (anclaje espacial).
Tres etapas de entrenamiento
Los VLMs modernos entrenan en etapas:
- Alineación — congela el ViT y el LLM. Entrena solo el proyector con pares imagen-leyenda. Le enseña al proyector a mapear el espacio de visión al espacio de lenguaje.
- Preentrenamiento — descongela todo. Entrena con datos imagen-texto intercalados a gran escala (más de 500M de pares). Construye el conocimiento visual del modelo.
- Instruction tuning — haz fine-tune sobre tripletas curadas de (imagen, pregunta, respuesta). Enseña comportamiento conversacional y formatos de tarea. Esto es lo que convierte un "LM con conciencia visual" en un asistente utilizable.
La mayoría de los fine-tunes con LoRA apuntan a la etapa 3 con un conjunto de datos etiquetado pequeño.
Comparación de la familia de modelos (inicios de 2026)
| Modelo | Params | Codificador de visión | LLM | Contexto | Fortalezas |
|---|---|---|---|---|---|
| Qwen3-VL-235B-A22B (MoE) | 235B (22B activos) | ViT custom + DeepStack | Qwen3 | 256K | SOTA general, agente de GUI |
| Qwen3-VL-30B-A3B (MoE) | 30B (3B activos) | ViT custom + DeepStack | Qwen3 | 256K | Alternativa MoE más pequeña |
| Qwen3-VL-8B (dense) | 8B | ViT custom | Qwen3 | 128K | Default dense de producción |
| InternVL3.5-38B | 38B | InternViT-6B | Qwen3 + GPT-OSS | 128K | Fuerte en MMBench / MMVet |
| InternVL3.5-241B-A28B | 241B (28B activos) | InternViT-6B | Qwen3 | 128K | Competitivo con GPT-4o |
| LLaVA-Next 72B | 72B | SigLIP | Llama-3 | 32K | Abierto, fácil de hacer fine-tune |
| GLM-4.6V | ~70B | custom | GLM | 64K | Open-source, OCR fuerte |
| MiniCPM-V-2.6 | 8B | SigLIP | MiniCPM | 32K | Amigable para edge |
Agentes visuales
Qwen3-VL-235B alcanza un rendimiento global de primer nivel en OSWorld — un benchmark para agentes visuales que operan GUIs (escritorio, móvil, web). El modelo ve una captura de pantalla, entiende la UI y emite acciones (clic, escribir, desplazar). Combinado con herramientas, cierra el ciclo en tareas comunes de escritorio. Esto es lo que ejecuta por debajo la mayoría de los demos de "AI PC" de 2026.
Capacidades agénticas + variantes de RoPE
Los VLMs necesitan saber cuándo ocurre un fotograma en un video. Qwen3-VL evolucionó de T-RoPE (temporal rotary position embeddings) a la alineación temporal basada en texto — tokens de texto de timestamp explícitos intercalados con fotogramas de video. El modelo ve "<timestamp 00:32> fotograma, prompt" y puede razonar sobre relaciones temporales.
El problema de alineación
El 12% de los pares imagen-texto en un dataset rastreado de la web contienen descripciones no totalmente ancladas en la imagen. Un VLM entrenado con esto aprende silenciosamente a alucinar — fabricar objetos, leer números de forma incorrecta, inventar relaciones. En producción, este es el modo de falla dominante.
Skywork.ai introdujo la Cross-Modal Error Rate (CMER) para rastrearla:
CMER = fraccion de salidas donde la confianza del texto es alta pero la similitud imagen-texto (via un verificador de la familia CLIP) es baja
Una CMER alta significa que el modelo está afirmando con confianza cosas no ancladas en la imagen. Monitorear la CMER y tratarla como un KPI de producción redujo la tasa de alucinación en ~35% en su despliegue. El truco no es "arreglar el modelo" sino "enrutar las salidas con CMER alta a revisión humana."
Fine-tuning con LoRA / QLoRA
El fine-tuning completo de un VLM de 70B está fuera del alcance de la mayoría de los equipos. LoRA (rank 16-64) en las capas de atención + proyector, o QLoRA con pesos base de 4 bits, cabe en una sola A100 / H100. Costo: 5.000-50.000 ejemplos,
El razonamiento espacial sigue siendo débil
Los VLMs actuales puntúan 50-60% en benchmarks de razonamiento espacial (arriba-abajo, izquierda-derecha, conteo, distancia). Si tu caso de uso depende de "qué objeto está encima de cuál", valida intensamente — el rendimiento de un VLM genérico está por debajo del humano. Alternativas mejores que un VLM para tareas puramente espaciales: un estimador especializado de keypoint / pose, un modelo de profundidad, o un modelo de detección con geometría de bounding box posprocesada.
Constrúyelo
Paso 1: El proyector
La parte que entrenarás con más frecuencia. MLP de 2-4 capas con GELU.
import torch
import torch.nn as nn
class Projector(nn.Module):
def __init__(self, vit_dim=768, llm_dim=4096, hidden=4096):
super().__init__()
self.net = nn.Sequential(
nn.Linear(vit_dim, hidden),
nn.GELU(),
nn.Linear(hidden, llm_dim),
)
def forward(self, x):
return self.net(x)
La entrada es un tensor de tokens (N_patches, d_vit). La salida es (N_patches, d_llm). El LLM trata cada fila de salida como un token más.
Paso 2: Ensamblar el ViT-MLP-LLM de extremo a extremo
Esqueleto del forward pass para un VLM mínimo. El código real usa transformers; este es el layout conceptual.
class MinimalVLM(nn.Module):
def __init__(self, vit, projector, llm, image_token_id):
super().__init__()
self.vit = vit
self.projector = projector
self.llm = llm
self.image_token_id = image_token_id # placeholder token in text prompt
def forward(self, image, input_ids, attention_mask):
# 1. vision features
vision_tokens = self.vit(image) # (B, N_patches, d_vit)
vision_embeds = self.projector(vision_tokens) # (B, N_patches, d_llm)
# 2. text embeddings
text_embeds = self.llm.get_input_embeddings()(input_ids) # (B, M, d_llm)
# 3. replace image placeholder tokens with vision embeds
merged = self._merge(text_embeds, vision_embeds, input_ids)
# 4. run LLM
return self.llm(inputs_embeds=merged, attention_mask=attention_mask)
def _merge(self, text_embeds, vision_embeds, input_ids):
out = text_embeds.clone()
expected = vision_embeds.size(1)
for b in range(input_ids.size(0)):
positions = (input_ids[b] == self.image_token_id).nonzero(as_tuple=True)[0]
if len(positions) != expected:
raise ValueError(
f"batch item {b} has {len(positions)} image tokens but vision_embeds has {expected} patches."
" Every sample in the batch must be pre-padded to the same number of image placeholder tokens.")
out[b, positions] = vision_embeds[b]
return out
El token placeholder <image> en el texto es reemplazado por embeddings reales de imagen — el mismo patrón que usan LLaVA, Qwen-VL e InternVL.
Paso 3: Cálculo de la CMER
Una verificación ligera en tiempo de ejecución.
import torch.nn.functional as F
def cross_modal_error_rate(image_emb, text_emb, text_confidence, sim_threshold=0.25, conf_threshold=0.8):
"""
image_emb, text_emb: embeddings of image and generated text (normalised internally)
text_confidence: mean per-token probability in [0, 1]
Returns: fraction of high-confidence outputs with low image-text alignment
"""
image_emb = F.normalize(image_emb, dim=-1)
text_emb = F.normalize(text_emb, dim=-1)
sim = (image_emb * text_emb).sum(dim=-1) # cosine similarity
high_conf_low_sim = (text_confidence > conf_threshold) & (sim < sim_threshold)
return high_conf_low_sim.float().mean().item()
Trata la CMER como un KPI de producción. Monitoréala por endpoint, por tipo de prompt, por cliente. Una CMER creciente indica que el modelo está empezando a alucinar sobre alguna distribución de entrada.
Paso 4: Clasificador VLM de juguete (ejecutable)
Demuestra que el proyector entrena. "Características de ViT" falsas entran; un pequeño token estilo LLM predice una clase.
class ToyVLM(nn.Module):
def __init__(self, vit_dim=32, llm_dim=64, num_classes=5):
super().__init__()
self.projector = Projector(vit_dim, llm_dim, hidden=64)
self.head = nn.Linear(llm_dim, num_classes)
def forward(self, vision_tokens):
projected = self.projector(vision_tokens)
pooled = projected.mean(dim=1)
return self.head(pooled)
Se puede ajustar esto sobre pares sintéticos (característica, clase) en menos de 200 pasos — suficiente para mostrar que el patrón del proyector funciona.
Úsalo
Tres maneras en que los equipos de producción usan VLMs en 2026:
- API alojada — OpenAI Vision, Anthropic Claude Vision, Google Gemini Vision. Cero infraestructura, riesgo de proveedor.
- Self-host open-source — Qwen3-VL o InternVL3.5 vía
transformersyvllm. Control total, mayor esfuerzo inicial. - Fine-tune en el dominio — carga Qwen2.5-VL-7B o LLaVA-1.6-7B, haz LoRA sobre 5k-50k ejemplos custom, sírvelo con
vllmoTGI.
from transformers import AutoProcessor, AutoModelForVision2Seq
import torch
from PIL import Image
model_id = "Qwen/Qwen3-VL-8B-Instruct"
processor = AutoProcessor.from_pretrained(model_id)
model = AutoModelForVision2Seq.from_pretrained(model_id, torch_dtype=torch.bfloat16, device_map="auto")
messages = [{
"role": "user",
"content": [
{"type": "image", "image": Image.open("plot.png")},
{"type": "text", "text": "What does this chart show?"},
],
}]
inputs = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt").to("cuda")
generated = model.generate(**inputs, max_new_tokens=256)
answer = processor.decode(generated[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)
apply_chat_template oculta la tokenización del placeholder <image>; el modelo maneja el merge internamente.
Entrégalo
Esta lección produce:
outputs/prompt-vlm-selector.md— elige Qwen3-VL / InternVL3.5 / LLaVA-Next / API dadas la precisión, latencia, longitud de contexto y presupuesto.outputs/skill-cmer-monitor.md— emite el código para instrumentar un endpoint de VLM de producción con cross-modal error rate, dashboards por endpoint y umbrales de alerta.
Ejercicios
- (Fácil) Ejecuta tres prompts ("¿qué es esto?", "cuenta los objetos", "describe la escena") a través de cualquier VLM abierto sobre cinco imágenes. Puntúa cada respuesta como correcta / parcialmente correcta / alucinada a mano. Calcula una tasa de primera pasada similar a la CMER.
- (Medio) Haz fine-tune de Qwen2.5-VL-3B o LLaVA-1.6-7B con LoRA (rank 16) sobre 500 imágenes de un dominio objetivo con leyendas. Compara la precisión estilo MMBench zero-shot vs. con fine-tune.
- (Difícil) Reemplaza el codificador de imagen del VLM con DINOv3 en lugar de su SigLIP/CLIP por defecto. Reentrena solo el proyector (LLM congelado + DINOv3 congelado). Mide si las tareas de predicción densa (conteo, razonamiento espacial) mejoran.
Términos Clave
| Término | Lo que la gente dice | Lo que realmente significa |
|---|---|---|
| ViT-MLP-LLM | "El patrón VLM" | Codificador de visión + proyector + modelo de lenguaje; todo VLM de 2026 |
| Proyector | "El puente" | MLP de 2-4 capas (o Q-former) que mapea tokens de visión al espacio de embedding del LLM |
| DeepStack | "El truco de características de Qwen3-VL" | Características multinivel del ViT apiladas en lugar de solo la última capa |
| Token de imagen | "Placeholder |
Token especial en el flujo de texto reemplazado por embeddings de visión proyectados |
| CMER | "KPI de alucinación" | Cross-Modal Error Rate; alta cuando la confianza del texto es alta pero la similitud imagen-texto es baja |
| Agente visual | "VLM que hace clic" | VLM operando GUIs (OSWorld, móvil, web) con llamadas a herramientas |
| Q-former | "Puente de tokens de conteo fijo" | Proyector estilo BLIP-2 que produce un número fijo de tokens de consulta visual |
| Alineación / preentrenamiento / instruction tuning | "Tres etapas" | Pipeline estándar de entrenamiento de VLM |