FastVLM: el modelo visual de Apple que podemos ejecutar en local

Modelo IA para procesado de imágenes
Solucionex
09
Feb 26

Durante los últimos meses han surgido numerosos modelos multimodales capaces de interpretar imágenes y generar descripciones de forma automática. Uno de los desarrollos más interesantes es FastVLM, presentado por Apple como una alternativa optimizada y rápida a las arquitecturas visuales tradicionales.

Este modelo destaca por su velocidad de inferencia y por funcionar correctamente sin necesidad de enviar datos a servicios externos, algo especialmente útil para quienes valoran un enfoque “local-first”, privacidad y control total sobre el ciclo de inferencia.

🔍 ¿Qué es FastVLM?

FastVLM forma parte de la familia de Vision Language Models, orientados a procesar contenido visual y generar texto en lenguaje natural. A diferencia de otros sistemas multimodales, su objetivo principal es ofrecer rapidez y eficiencia, incluso con recursos hardware limitados.

Entre sus mejoras destacan:

  • FastViT HD: encoder visual optimizado con baja latencia.
  • PagedAttention y FlashAttention: reducción de consumo de memoria y tiempo de acceso.
  • Variantes ligeras: modelos desde 0.5B parámetros para uso en local.

⚙️ Ventajas principales

  • Ejecución sin conexión
  • Privacidad garantizada, las imágenes no salen del sistema
  • Latencia reducida, adecuada para interfaces web en tiempo real
  • Compatibilidad con Transformers

💻 Implementación en local con Streamlit y Docker

Una forma sencilla de probar FastVLM consiste en desarrollar una aplicación web mínima con Streamlit, y cargar el modelo desde un directorio local. Para ello es suficiente con descargar los pesos una única vez durante el build de Docker.

A continuación se presenta un ejemplo práctico dividido en bloques comentados.

Perfecto, gracias por compartir tus versiones definitivas. A continuación te dejo solo las dos secciones, reescritas con tu contenido real (sin inventar valores), y acompañadas de una explicación clara y breve para integrarlas en el post.

🐳 Docker Compose: orquestando el entorno

El siguiente docker-compose.yml levanta un servicio con Streamlit y FastVLM con soporte para GPU NVIDIA. Incluye variables de entorno relevantes para Streamlit y configuración necesaria para acceder al hardware acelerado desde dentro del contenedor.

services:
  fastvlm-app:
    build: .
    container_name: fastvlm-streamlit
    ports:
      - "8501:8501"
    environment:
      - STREAMLIT_SERVER_ENABLECORS=false
      - STREAMLIT_SERVER_ENABLEXsrfProtection=false
      - CUDA_VISIBLE_DEVICES=0
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=compute,utility
    deploy:
      resources:
        reservations:
          devices:
            - capabilities: ["gpu"]
    runtime: nvidia
    restart: unless-stopped

🛠️ Dockerfile: instalando dependencias y descargando el modelo

Este Dockerfile está preparado para producción con descarga automática del modelo durante el build y con soporte CUDA integrado gracias a la imagen base de PyTorch con drivers y librerías NVIDIA incluidas.

# Imagen base con PyTorch y CUDA (GPU). Si usas CPU, cambia a pytorch/pytorch:2.2.2-cpu
FROM pytorch/pytorch:2.2.2-cuda12.1-cudnn8-runtime

# Evita prompts interactivos durante apt-get y warnings de HF
ENV DEBIAN_FRONTEND=noninteractive \
    HF_HUB_DISABLE_SYMLINKS_WARNING=1

# Carpeta de trabajo
WORKDIR /app

# Instalamos dependencias de sistema
RUN apt-get update && apt-get install -y --no-install-recommends \
    git \
    && rm -rf /var/lib/apt/lists/*

# Copiamos requirements primero, para cache de Docker
COPY requirements.txt .

# Instalamos dependencias Python (torch ya viene en esta imagen)
RUN pip install --no-cache-dir -r requirements.txt

# ======================================================
# DESCARGA DEL MODELO LOCAL DE HUGGING FACE
# ======================================================
# Se descargará en /app/models/FastVLM-0.5B
# y ya NO necesitaremos Internet durante ejecución
RUN mkdir -p /app/models/FastVLM-0.5B
RUN huggingface-cli download \
    apple/FastVLM-0.5B \
    --local-dir /app/models/FastVLM-0.5B \
    --local-dir-use-symlinks False

# Copiamos la app completa
COPY app.py .

# Exponemos el puerto de streamlit
EXPOSE 8501

# Comando de ejecución del contenedor
CMD ["streamlit", "run", "app.py", "--server.address=0.0.0.0", "--server.port=8501"]

🧩 Ejemplo de código: app.py

Importaciones y configuración inicial

import torch
import streamlit as st
from PIL import Image
from transformers import AutoTokenizer, AutoModelForCausalLM

MODEL_PATH = "/app/models/FastVLM-0.5B"   # Ruta local al modelo
IMAGE_TOKEN_INDEX = -200                  # Token especial utilizado por FastVLM

En este bloque se importan las librerías necesarias y se definen las constantes básicas para la aplicación. MODEL_PATH indica la ubicación del modelo dentro del contenedor, mientras que IMAGE_TOKEN_INDEX representa el valor especial utilizado por FastVLM para identificar dónde debe insertarse la información visual dentro del prompt.

Carga del modelo y del procesador de imagen

@st.cache_resource
def load_model():
    tokenizer = AutoTokenizer.from_pretrained(
        MODEL_PATH,
        trust_remote_code=True,
        local_files_only=True
    )

    model = AutoModelForCausalLM.from_pretrained(
        MODEL_PATH,
        torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
        device_map="auto",
        trust_remote_code=True,
        local_files_only=True
    )

    vision_tower = model.get_vision_tower()
    image_processor = vision_tower.image_processor
    device = model.device

    return tokenizer, model, image_processor, device


tokenizer, model, image_processor, device = load_model()

Este fragmento define una función que carga el modelo y el tokenizador desde los archivos almacenados localmente. El parámetro local_files_only=True garantiza que durante la ejecución no se intente descargar nada desde Hugging Face. La instrucción get_vision_tower() permite acceder al componente responsable de procesar imágenes, y la anotación @st.cache_resource hace que la carga del modelo se realice una única vez, optimizando el rendimiento de la aplicación.

Construcción del prompt y generación

def describe_image(image: Image.Image) -> str:
    pixel_values = image_processor(images=image, return_tensors="pt")["pixel_values"]
    pixel_values = pixel_values.to(device, dtype=model.dtype)

    messages = [{"role": "user", "content": "<image>\nDescribe esta imagen en español."}]
    rendered = tokenizer.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
    pre, post = rendered.split("<image>", 1)

    pre_ids = tokenizer(pre, return_tensors="pt", add_special_tokens=False).input_ids
    post_ids = tokenizer(post, return_tensors="pt", add_special_tokens=False).input_ids
    img_tok = torch.tensor([[IMAGE_TOKEN_INDEX]], dtype=pre_ids.dtype)

    input_ids = torch.cat([pre_ids, img_tok, post_ids], dim=1).to(device)
    attention_mask = torch.ones_like(input_ids)

    with torch.no_grad():
        output = model.generate(
            inputs=input_ids,
            attention_mask=attention_mask,
            images=pixel_values,
            max_new_tokens=128,
        )

    return tokenizer.decode(output[0], skip_special_tokens=True)

En este bloque se prepara la imagen y el texto para que FastVLM pueda generar una descripción. El objeto image_processor convierte la imagen en tensores aptos para el modelo. El marcador <image> indica el punto exacto en el prompt donde debe integrarse la información visual, utilizando para ello el valor de IMAGE_TOKEN_INDEX. Las partes anterior y posterior al marcador se tokenizan y se fusionan con el token especial, formando una entrada única compuesta por texto e imagen. Finalmente, la llamada a model.generate() produce la salida en lenguaje natural; en este caso, una descripción en español de la imagen subida por el usuario.

Interfaz en Streamlit

st.title("FastVLM - Generador de descripciones de imágenes")

uploaded_file = st.file_uploader("Sube una imagen", type=["jpg", "jpeg", "png"])

if uploaded_file:
    image = Image.open(uploaded_file).convert("RGB")
    st.image(image, caption="Imagen cargada", use_column_width=True)
    caption = describe_image(image)
    st.subheader("Descripción generada:")
    st.write(caption)

Se muestra un componente file_uploader para permitir al usuario subir una imagen.

Se muestra un componente file_uploader para permitir al usuario subir una imagen

Cuando la imagen se carga, se procesa automáticamente y se muestra la respuesta generada por FastVLM.

Cuando la imagen se carga, se procesa automáticamente y se muestra la respuesta generada por FastVLM

No se requiere infraestructura adicional ni una API externa.

🧠 ¿Por qué ejecutar IA en local?

Aunque la inferencia en la nube sigue siendo popular, existen numerosos escenarios donde ejecutar IA en local resulta ventajoso:

  • Protección de información sensible
  • Cumplimiento legal y normativo
  • Autonomía frente a proveedores externos
  • Uso en entornos sin conectividad

FastVLM facilita estos casos aportando un equilibrio razonable entre velocidad, calidad y consumo de recursos.

📈 Conclusión

FastVLM demuestra que es posible trabajar con modelos multimodales de forma eficiente sin depender de servicios externos. Su uso con Docker y Streamlit permite desarrollar aplicaciones sencillas y funcionales que aprovechan capacidades de IA visual en local.

Si más adelante se desea ampliar funcionalidades, existen variantes más grandes del modelo y numerosos recursos en Hugging Face y la comunidad open source que permiten seguir profundizando en el desarrollo multimodal.