# Modelo de lenguaje y visión Qwen2.5-VL

Qwen2.5-VL de Alibaba (diciembre de 2024) es el modelo visión-texto (VLM) de peso abierto con mejor rendimiento. Disponible en tamaños de 3B, 7B y 72B de parámetros, entiende imágenes, fotogramas de video, PDFs, gráficos y diseños visuales complejos. La variante de 7B encuentra el punto óptimo: supera a muchos modelos más grandes en benchmarks mientras funciona cómodamente en una sola GPU de 24 GB.

En [Clore.ai](https://clore.ai/) puedes alquilar la GPU exacta que necesitas — desde una RTX 3090 para el modelo 7B hasta configuraciones multi-GPU para la variante de 72B — y comenzar a analizar contenido visual en minutos.

## Características clave

* **Entrada multimodal** — imágenes, video, PDFs, capturas de pantalla, gráficos y diagramas en un único modelo.
* **Tres escalas** — 3B (edge/móvil), 7B (punto óptimo para producción), 72B (calidad SOTA).
* **Resolución dinámica** — procesa imágenes en su resolución nativa; sin forzar redimensionamiento a 224×224.
* **Comprensión de video** — acepta entrada de video con múltiples fotogramas y razonamiento temporal.
* **OCR de documentos** — extrae texto de documentos escaneados, recibos y notas manuscritas.
* **Multilingüe** — rendimiento sólido en inglés, chino y más de 20 idiomas adicionales.
* **Soporte Ollama** — ejecútalo localmente con `ollama run qwen2.5vl:7b` para despliegue sin código.
* **Integración con Transformers** — `Qwen2_5_VLForConditionalGeneration` en HuggingFace `transformers`.

## Requisitos

| Componente      | 3B    | 7B       | 72B                |
| --------------- | ----- | -------- | ------------------ |
| VRAM de GPU     | 8 GB  | 16–24 GB | 80+ GB (multi-GPU) |
| RAM del sistema | 16 GB | 32 GB    | 128 GB             |
| Disco           | 10 GB | 20 GB    | 150 GB             |
| Python          | 3.10+ | 3.10+    | 3.10+              |
| CUDA            | 12.1+ | 12.1+    | 12.1+              |

**Recomendación de GPU de Clore.ai:** Para el **modelo 7B**, un **RTX 4090** (24 GB, \~0,5–2 $/día) o **RTX 3090** (24 GB, \~0,3–1 $/día) es ideal. Para **72B**, filtra el mercado por **A100 80 GB** o configuraciones multi-GPU.

## Inicio rápido

### Opción A: Ollama (La más simple)

```bash
# Instalar ollama
curl -fsSL https://ollama.ai/install.sh | sh

# Descargar y ejecutar el modelo de visión 7B
ollama run qwen2.5vl:7b
```

Luego en el prompt de ollama:

```
>>> Describe esta imagen: /path/to/photo.jpg
```

### Opción B: Python / Transformers

```bash
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu124
pip install transformers accelerate qwen-vl-utils pillow
```

## Ejemplos de uso

### Comprensión de imágenes con Transformers

```python
import torch
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
from qwen_vl_utils import process_vision_info

model_name = "Qwen/Qwen2.5-VL-7B-Instruct"

model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)
processor = AutoProcessor.from_pretrained(model_name)

messages = [
    {
        "role": "user",
        "content": [
            {"type": "image", "image": "https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg"},
            {"type": "text", "text": "¿Qué especie es este insecto? Describe sus características identificativas clave."},
        ],
    }
]

text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
image_inputs, video_inputs = process_vision_info(messages)

inputs = processor(
    text=[text],
    images=image_inputs,
    videos=video_inputs,
    padding=True,
    return_tensors="pt",
).to(model.device)

output_ids = model.generate(**inputs, max_new_tokens=512)
response = processor.batch_decode(
    output_ids[:, inputs.input_ids.shape[1]:],
    skip_special_tokens=True,
)[0]

print(response)
```

### Análisis de video

```python
import torch
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
from qwen_vl_utils import process_vision_info

model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
    "Qwen/Qwen2.5-VL-7B-Instruct",
    torch_dtype=torch.bfloat16,
    device_map="auto",
)
processor = AutoProcessor.from_pretrained("Qwen/Qwen2.5-VL-7B-Instruct")

messages = [
    {
        "role": "user",
        "content": [
            {"type": "video", "video": "file:///workspace/clip.mp4", "max_pixels": 360 * 420, "fps": 1.0},
            {"type": "text", "text": "Resume lo que sucede en este video. Enumera los eventos clave en orden."},
        ],
    }
]

text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
image_inputs, video_inputs = process_vision_info(messages)

inputs = processor(
    text=[text],
    images=image_inputs,
    videos=video_inputs,
    padding=True,
    return_tensors="pt",
).to(model.device)

output_ids = model.generate(**inputs, max_new_tokens=1024)
print(processor.batch_decode(output_ids[:, inputs.input_ids.shape[1]:], skip_special_tokens=True)[0])
```

### OCR y extracción de documentos

```python
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image", "image": "file:///workspace/receipt.jpg"},
            {"type": "text", "text": "Extrae todos los artículos, cantidades y precios de este recibo. Devuélvelo en formato JSON."},
        ],
    }
]

# Procesar usando la misma configuración de modelo/procesador anterior
text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
image_inputs, video_inputs = process_vision_info(messages)
inputs = processor(text=[text], images=image_inputs, videos=video_inputs, padding=True, return_tensors="pt").to(model.device)
output_ids = model.generate(**inputs, max_new_tokens=2048)
print(processor.batch_decode(output_ids[:, inputs.input_ids.shape[1]:], skip_special_tokens=True)[0])
```

### API de Ollama para procesamiento por lotes

```python
import ollama
import base64
from pathlib import Path

def analyze_image(image_path: str, question: str) -> str:
    """Enviar una imagen a Qwen2.5-VL a través de la API de Ollama."""
    image_data = base64.b64encode(Path(image_path).read_bytes()).decode()
    response = ollama.chat(
        model="qwen2.5vl:7b",
        messages=[{
            "role": "user",
            "content": question,
            "images": [image_data],
        }],
    )
    return response["message"]["content"]

# Procesar por lotes una carpeta de imágenes
from pathlib import Path
for img in sorted(Path("./photos").glob("*.jpg")):
    result = analyze_image(str(img), "Describe esta imagen en una frase.")
    print(f"{img.name}: {result}")
```

## Consejos para usuarios de Clore.ai

1. **Ollama para despliegue rápido** — `ollama run qwen2.5vl:7b` es la vía más rápida hacia un VLM funcionando. No se necesita código Python para uso interactivo.
2. **7B es el punto óptimo** — la variante 7B Instruct cabe en 16 GB de VRAM con cuantización a 4 bits y ofrece una calidad competitiva con modelos mucho más grandes.
3. **La resolución dinámica importa** — Qwen2.5-VL procesa imágenes en resolución nativa. Para imágenes grandes (>4K), redimensiona a un ancho máximo de 1920 px para evitar uso excesivo de VRAM.
4. **Configuración de fps de video** — para entrada de video, establece `fps=1.0` para muestrear 1 fotograma por segundo. Valores más altos consumen VRAM rápidamente; 1 fps es suficiente para la mayoría de las tareas de análisis.
5. **Almacenamiento persistente** — establece `HF_HOME=/workspace/hf_cache`; el modelo 7B ocupa \~15 GB. Para ollama, los modelos se ubican en `~/.ollama/models/`.
6. **Salida estructurada** — Qwen2.5-VL sigue bien las instrucciones de formato JSON. Pide "Devolver como JSON" y obtendrás una salida parseable la mayoría de las veces.
7. **Comparación de múltiples imágenes** — puedes pasar varias imágenes en un solo mensaje para tareas de comparación (por ejemplo, "¿Cuál de estos dos productos parece más premium?").
8. **tmux** — siempre ejecútalo dentro de `tmux` en los alquileres de Clore.ai.

## Solución de problemas

| Problema                                  | Solucionar                                                                                            |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `OutOfMemoryError` con 7B                 | Usa `load_in_4bit=True` en `from_pretrained()` con `bitsandbytes`; o usa la variante 3B               |
| Modelo de Ollama no encontrado            | `ollama pull qwen2.5vl:7b` — asegúrate de tener la etiqueta correcta                                  |
| Procesamiento de video lento              | Reducir `fps` a 0.5 y `max_pixels` a `256 * 256`; menos fotogramas = inferencia más rápida            |
| Salida garbled o vacía                    | Aumenta `max_new_tokens`; el valor por defecto puede ser demasiado bajo para descripciones detalladas |
| `ImportError: qwen_vl_utils`              | `pip install qwen-vl-utils` — requerido para `process_vision_info()`                                  |
| El modelo 72B no cabe                     | Usa 2× A100 80 GB con `device_map="auto"` o aplica cuantización AWQ                                   |
| Ruta de imagen no encontrada              | Para archivos locales en mensajes, usa `file:///absolute/path` formato                                |
| Chino en la salida al solicitar en inglés | Agrega "Responde solo en inglés." a tu prompt                                                         |
