# Llama 3.2 Vision

Ejecute los modelos multimodales Llama 3.2 Vision de Meta para comprensión de imágenes en las GPU de CLORE.AI.

{% hint style="success" %}
Todos los ejemplos se pueden ejecutar en servidores GPU alquilados a través de [CLORE.AI Marketplace](https://clore.ai/marketplace).
{% endhint %}

## ¿Por qué Llama 3.2 Vision?

* **Multimodal** - Comprende tanto texto como imágenes
* **Múltiples tamaños** - Versiones de 11B y 90B parámetros
* **Versátil** - OCR, preguntas y respuestas visuales, generación de subtítulos de imágenes, análisis de documentos
* **Pesos abiertos** - Completamente de código abierto por Meta
* **Ecosistema Llama** - Compatible con Ollama, vLLM, transformers

## Variantes de modelo

| Modelo                        | Parámetros | VRAM (FP16) | Contexto | Mejor para             |
| ----------------------------- | ---------- | ----------- | -------- | ---------------------- |
| Llama-3.2-11B-Vision          | 11B        | 24GB        | 128K     | Uso general, GPU única |
| Llama-3.2-90B-Vision          | 90B        | 180GB       | 128K     | Calidad máxima         |
| Llama-3.2-11B-Vision-Instruct | 11B        | 24GB        | 128K     | Chat/asistente         |
| Llama-3.2-90B-Vision-Instruct | 90B        | 180GB       | 128K     | Producción             |

## Despliegue rápido en CLORE.AI

**Imagen Docker:**

```
vllm/vllm-openai:latest
```

**Puertos:**

```
22/tcp
8000/http
```

**Comando:**

```bash
python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3.2-11B-Vision-Instruct \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 8192
```

## Accediendo a tu servicio

Después del despliegue, encuentra tu `http_pub` URL en **Mis Pedidos**:

1. Ir a **Mis Pedidos** página
2. Haz clic en tu pedido
3. Encuentra la `http_pub` URL (por ejemplo, `abc123.clorecloud.net`)

Usa `https://TU_HTTP_PUB_URL` en lugar de `localhost` en los ejemplos abajo.

## Requisitos de hardware

| Modelo     | GPU mínima    | Recomendado  | Óptimo    |
| ---------- | ------------- | ------------ | --------- |
| 11B Vision | RTX 4090 24GB | A100 40GB    | A100 80GB |
| 90B Vision | 4x A100 40GB  | 4x A100 80GB | 8x H100   |

## Instalación

### Usando Ollama (Más fácil)

```bash
# Descargar el modelo
ollama pull llama3.2-vision:11b

# Ejecutar interactivo
ollama run llama3.2-vision:11b
```

### Usando vLLM

```bash
pip install vllm

python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3.2-11B-Vision-Instruct \
    --host 0.0.0.0 \
    --port 8000
```

### Usando Transformers

```python
import torch
from transformers import MllamaForConditionalGeneration, AutoProcessor

model_id = "meta-llama/Llama-3.2-11B-Vision-Instruct"

model = MllamaForConditionalGeneration.from_pretrained(
    model_id,
    torch_dtype=torch.bfloat16,
    device_map="auto"
)
processor = AutoProcessor.from_pretrained(model_id)
```

## Uso básico

### Comprensión de imágenes

```python
import torch
from transformers import MllamaForConditionalGeneration, AutoProcessor
from PIL import Image
import requests

model_id = "meta-llama/Llama-3.2-11B-Vision-Instruct"

model = MllamaForConditionalGeneration.from_pretrained(
    model_id,
    torch_dtype=torch.bfloat16,
    device_map="auto"
)
processor = AutoProcessor.from_pretrained(model_id)

# Cargar imagen
url = "https://example.com/image.jpg"
image = Image.open(requests.get(url, stream=True).raw)

# Crear prompt
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": "¿Qué hay en esta imagen? Describe en detalle."}
        ]
    }
]

input_text = processor.apply_chat_template(messages, add_generation_prompt=True)
inputs = processor(image, input_text, return_tensors="pt").to(model.device)

output = model.generate(**inputs, max_new_tokens=500)
print(processor.decode(output[0], skip_special_tokens=True))
```

### Con Ollama

```bash
# Describir una imagen
ollama run llama3.2-vision:11b "Describe esta imagen: /ruta/a/imagen.jpg"

# O usa la API
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2-vision:11b",
  "prompt": "¿Qué hay en esta imagen?",
  "images": ["imagen_codificada_en_base64_aquí"]
}'
```

### Con la API de vLLM

```python
from openai import OpenAI
import base64

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="no-necesaria"
)

# Codificar imagen a base64
with open("image.jpg", "rb") as f:
    image_base64 = base64.b64encode(f.read()).decode()

response = client.chat.completions.create(
    model="meta-llama/Llama-3.2-11B-Vision-Instruct",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "¿Qué hay en esta imagen?"},
                {
                    "type": "image_url",
                    "image_url": {"url": f"data:image/jpeg;base64,{image_base64}"}
                }
            ]
        }
    ],
    max_tokens=500
)

print(response.choices[0].message.content)
```

## Casos de uso

### OCR / Extracción de texto

```python
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": "Extrae todo el texto de esta imagen. Formatea como markdown."}
        ]
    }
]
```

### Análisis de documentos

```python
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": "Analiza este documento. Resume los puntos clave."}
        ]
    }
]
```

### Preguntas y respuestas visuales

```python
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": "¿Cuántas personas hay en esta foto? ¿Qué están haciendo?"}
        ]
    }
]
```

### Generación de subtítulos para imágenes

```python
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": "Escribe un subtítulo detallado para esta imagen adecuado para redes sociales."}
        ]
    }
]
```

### Código a partir de capturas de pantalla

```python
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": "Convierte esta captura de pantalla de la interfaz en código HTML/CSS."}
        ]
    }
]
```

## Múltiples imágenes

```python
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "image"},
            {"type": "text", "text": "Compara estas dos imágenes. ¿Cuáles son las diferencias?"}
        ]
    }
]

# Procesar con múltiples imágenes
inputs = processor(
    images=[image1, image2],
    text=input_text,
    return_tensors="pt"
).to(model.device)
```

## Procesamiento por lotes

```python
import os
from PIL import Image

def process_images(image_paths, prompt):
    results = []

    for path in image_paths:
        image = Image.open(path)

        messages = [
            {
                "role": "user",
                "content": [
                    {"type": "image"},
                    {"type": "text", "text": prompt}
                ]
            }
        ]

        input_text = processor.apply_chat_template(messages, add_generation_prompt=True)
        inputs = processor(image, input_text, return_tensors="pt").to(model.device)

        output = model.generate(**inputs, max_new_tokens=300)
        result = processor.decode(output[0], skip_special_tokens=True)

        results.append({"file": path, "description": result})

        # Limpiar caché entre imágenes
        torch.cuda.empty_cache()

    return results

# Procesar carpeta
images = [f"./images/{f}" for f in os.listdir("./images") if f.endswith(('.jpg', '.png'))]
results = process_images(images, "Describe esta imagen en un párrafo.")
```

## Interfaz Gradio

```python
import gradio as gr
import torch
from transformers import MllamaForConditionalGeneration, AutoProcessor
from PIL import Image

model_id = "meta-llama/Llama-3.2-11B-Vision-Instruct"
model = MllamaForConditionalGeneration.from_pretrained(
    model_id, torch_dtype=torch.bfloat16, device_map="auto"
)
processor = AutoProcessor.from_pretrained(model_id)

def analyze_image(image, question):
    messages = [
        {
            "role": "user",
            "content": [
                {"type": "image"},
                {"type": "text", "text": question}
            ]
        }
    ]

    input_text = processor.apply_chat_template(messages, add_generation_prompt=True)
    inputs = processor(image, input_text, return_tensors="pt").to(model.device)

    output = model.generate(**inputs, max_new_tokens=500)
    return processor.decode(output[0], skip_special_tokens=True)

demo = gr.Interface(
    fn=analyze_image,
    inputs=[
        gr.Image(type="pil", label="Subir imagen"),
        gr.Textbox(label="Pregunta", placeholder="¿Qué hay en esta imagen?")
    ],
    outputs=gr.Textbox(label="Response"),
    title="Llama 3.2 Vision - Análisis de imágenes",
    description="Sube una imagen y hazle preguntas. Ejecutándose en CLORE.AI."
)

demo.launch(server_name="0.0.0.0", server_port=7860)
```

## Rendimiento

| Tarea                       | Modelo | GPU       | Tiempo |
| --------------------------- | ------ | --------- | ------ |
| Descripción de imagen única | 11B    | RTX 4090  | \~3s   |
| Descripción de imagen única | 11B    | A100 40GB | \~2s   |
| OCR (1 página)              | 11B    | RTX 4090  | \~5s   |
| Análisis de documentos      | 11B    | A100 40GB | \~8s   |
| Lote (10 imágenes)          | 11B    | A100 40GB | \~25s  |

## Cuantización

### 4-bit con bitsandbytes

```python
from transformers import BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16
)

model = MllamaForConditionalGeneration.from_pretrained(
    model_id,
    quantization_config=quantization_config,
    device_map="auto"
)
```

### GGUF con Ollama

```bash
# Cuantizado a 4 bits (cabe en 8GB de VRAM)
ollama pull llama3.2-vision:11b-q4_K_M

# Cuantizado a 8 bits
ollama pull llama3.2-vision:11b-q8_0
```

## Estimación de costos

Tarifas típicas del mercado de CLORE.AI:

| GPU           | Tarifa por hora | Mejor para             |
| ------------- | --------------- | ---------------------- |
| RTX 4090 24GB | \~$0.10         | Modelo 11B             |
| A100 40GB     | \~$0.17         | 11B con contexto largo |
| A100 80GB     | \~$0.25         | 11B óptimo             |
| 4x A100 80GB  | \~$1.00         | Modelo 90B             |

*Los precios varían. Consulta* [*CLORE.AI Marketplace*](https://clore.ai/marketplace) *para las tarifas actuales.*

**Ahorra dinero:**

* Usa **Spot** órdenes para procesamiento por lotes
* Paga con **CLORE** tokens
* Use modelos cuantizados (4 bits) para desarrollo

## Solución de problemas

### Memoria insuficiente

```python
# Usar cuantización de 4 bits
model = MllamaForConditionalGeneration.from_pretrained(
    model_id,
    load_in_4bit=True,
    device_map="auto"
)

# O reduzca max_new_tokens
output = model.generate(**inputs, max_new_tokens=256)
```

### Generación lenta

* Asegúrese de que se esté usando la GPU (verifique `nvidia-smi`)
* Use bfloat16 en lugar de float32
* Reduzca la resolución de la imagen antes de procesarla
* Use vLLM para mejor rendimiento

### Imagen no cargando

```python
from PIL import Image
import requests
from io import BytesIO

# Desde URL
response = requests.get(url)
image = Image.open(BytesIO(response.content)).convert("RGB")

# Desde archivo
image = Image.open("path/to/image.jpg").convert("RGB")

# Redimensionar si es demasiado grande
max_size = 1024
if max(image.size) > max_size:
    image.thumbnail((max_size, max_size))
```

### Token de HuggingFace requerido

```bash
# Establecer token para modelos con acceso restringido
export HUGGING_FACE_HUB_TOKEN=hf_xxxxx

# O iniciar sesión
huggingface-cli login
```

## Llama Vision vs Otros

| Función        | Llama 3.2 Vision | LLaVA 1.6  | GPT-4V       |
| -------------- | ---------------- | ---------- | ------------ |
| Parámetros     | 11B / 90B        | 7B / 34B   | Desconocido  |
| Código abierto | Sí               | Sí         | No           |
| Calidad de OCR | Excelente        | Bueno      | Excelente    |
| Contexto       | 128K             | 32K        | 128K         |
| Multi-imagen   | Sí               | Limitado   | Sí           |
| Licencia       | Llama 3.2        | Apache 2.0 | Proprietario |

**Usa Llama 3.2 Vision cuando:**

* Necesitas multimodal de código abierto
* OCR y análisis de documentos
* Integración con el ecosistema Llama
* Comprensión de contexto largo

## Próximos pasos

* [LLaVA](https://docs.clore.ai/guides/guides_v2-es/modelos-de-vision/llava-vision-language) - Modelo de visión alternativo
* [Florence-2](https://docs.clore.ai/guides/guides_v2-es/modelos-de-vision/florence2) - Modelo de visión de Microsoft
* [Ollama](https://docs.clore.ai/guides/guides_v2-es/modelos-de-lenguaje/ollama) - Despliegue sencillo
* [vLLM](https://docs.clore.ai/guides/guides_v2-es/modelos-de-lenguaje/vllm) - Servir en producción
