Este tutorial muestra cómo ejecutar una demo VLA (Vision-Language Assistant) con Gemma 4 en un NVIDIA Jetson Orin Nano Super de 8 GB. ¿Lo más llamativo? El flujo es local y la decisión de cuando mirar viene del modelo, no de reglas codificadas. Te explico paso a paso lo técnico para que puedas replicarlo sin perderte en jerga innecesaria.
Qué hace esta demo VLA
La tuberia es simple: tú hablas -> Parakeet STT -> Gemma 4 -> (si hace falta) toma foto con la webcam -> Kokoro TTS -> altavoz. Presionas SPACE para grabar, otra vez SPACE para parar. ¿Pero qué significa VLA aquí? Significa que el modelo decide por contexto si necesita ver algo. No hay palabras clave ni lógica rígida.
Si preguntas algo que requiere ver el entorno, Gemma 4 llama a la herramienta look_and_answer, la demo captura una imagen, se la envía al modelo y Gemma responde usando lo que vio. No te describe la foto por describirla; responde tu pregunta con ese contexto visual.
Punto clave: la demo corre en un Jetson Orin Nano de 8 GB. Impresionante, pero hay que preparar la tarjeta.
Hardware y software que se usó
- NVIDIA Jetson Orin Nano Super (8 GB)
- Webcam Logitech C920 (mic integrado)
- Altavoz USB
- Teclado USB (para presionar
SPACE)
No estás atado a esos modelos: cualquier webcam, mic USB y altavoz que Linux reconozca debería funcionar.
Preparación del sistema (resumen técnico)
Primero, actualiza e instala paquetes básicos para audio, webcam y desarrollo en Python. Comandos clave:
sudo apt update
sudo apt install -y git build-essential cmake curl wget pkg-config \
python3-pip python3-venv python3-dev \
alsa-utils pulseaudio-utils v4l-utils psmisc \
ffmpeg libsndfile1
Crea un entorno virtual y las dependencias Python:
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install opencv-python-headless onnx_asr kokoro-onnx soundfile huggingface-hub numpy
Consejo práctico: en una tarjeta de 8 GB es crucial liberar memoria antes de lanzar modelos grandes. Cierra navegadores, IDEs, y servicios no necesarios.
Swap y limpieza de procesos (para evitar OOM)
Agregar un swap de 8 GB ayuda a evitar que el proceso sea terminado por falta de memoria durante la carga del modelo:
sudo fallocate -l 8G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Antes de lanzar el servidor, detén procesos pesados como Docker si no los necesitas, y mata servicios como tracker-miner-fs-3 o gnome-software si están consumiendo RAM.
Modelos, quantizaciones y por qué elegir Q4_K_M
Desde las pruebas, Q4_K_M (Q4_K_M) ofrece el mejor balance entre capacidad y uso de memoria en 8 GB. Si no te alcanza la memoria, puedes bajar a la versión Q3 (archivo con Q3 en el nombre) para ahorrar RAM a costa de algo de precisión. Pero la recomendación es: intenta con Q4_K_M primero.
Asimismo necesitas el archivo mmproj que es el proyector de visión. Sin él, Gemma no puede "ver".
Build nativo de llama.cpp y lanzamiento de llama-server
Se construye llama.cpp nativo para sacar mejor rendimiento y soporte del proyector de visión. Pasos esenciales:
cd ~
git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
cmake -B build \
-DGGML_CUDA=ON \
-DCMAKE_CUDA_ARCHITECTURES="87" \
-DGGML_NATIVE=ON \
-DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j4
Descarga los modelos al directorio ~/models:
mkdir -p ~/models && cd ~/models
wget -O gemma-4-E2B-it-Q4_K_M.gguf \
https://huggingface.co/unsloth/gemma-4-E2B-it-GGUF/resolve/main/gemma-4-E2B-it-Q4_K_M.gguf
wget -O mmproj-gemma4-e2b-f16.gguf \
https://huggingface.co/ggml-org/gemma-4-E2B-it-GGUF/resolve/main/mmproj-gemma4-e2b-f16.gguf
Lanza llama-server con el mmproj y flags recomendados:
~/llama.cpp/build/bin/llama-server \
-m ~/models/gemma-4-E2B-it-Q4_K_M.gguf \
--mmproj ~/models/mmproj-gemma4-e2b-f16.gguf \
-c 2048 \
--image-min-tokens 70 --image-max-tokens 70 \
--ubatch-size 512 --batch-size 512 \
--host 0.0.0.0 --port 8080 \
-ngl 99 --flash-attn on \
--no-mmproj-offload --jinja -np 1
Nota técnica: -ngl 99 intenta empujar todas las capas al GPU. Si tienes problemas de memoria, baja ese número para offload parcial a CPU.
Prueba rápida del endpoint:
curl -s http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"gemma4","messages":[{"role":"user","content":"Hi!"}],"max_tokens":32}' \
| python3 -m json.tool
Si obtienes JSON, el servidor responde.
Demo Python: Gemma4_vla.py y flujo completo
El script Gemma4_vla.py (un único archivo) orquesta todo: STT local (Parakeet), la llamada a llama-server y TTS (Kokoro). Puedes clonar el repo completo o descargar solo el script:
- Clonar repo:
git clone https://github.com/asierarranz/Google_Gemma.git
cd Google_Gemma/Gemma4
- O descargar solo el script:
wget https://raw.githubusercontent.com/asierarranz/Google_Gemma/main/Gemma4/Gemma4_vla.py
El script descarga Parakeet STT, Kokoro TTS y genera WAVs de voz al primer arranque. Luego: presiona SPACE para grabar, habla, presiona SPACE para parar y Gemma responde.
Variables de entorno y ejemplo de ejecución:
export MIC_DEVICE="plughw:3,0"
export SPK_DEVICE="alsa_output.usb-Generic_USB2.0_Device_20130100ph0-00.analog-stereo"
export WEBCAM=0
export VOICE="af_jessica"
source .venv/bin/activate
python3 Gemma4_vla.py
También hay modo texto si quieres probar solo la parte LLM sin audio:
python3 Gemma4_vla.py --text
La demo define exactamente una herramienta expuesta a Gemma 4:
{
"name": "look_and_answer",
"description": "Take a photo with the webcam and analyze what is visible."
}
Cuando el modelo decide que necesita visión, invoca look_and_answer, la demo toma la foto, la envía al servidor y la respuesta se sintetiza con Kokoro.
La magia aquí es la bandera
--jinjaenllama-server, que activa el soporte nativo de llamadas a herramientas en Gemma.
Docker: opción más rápida pero limitada
Si no quieres compilar todo, NVIDIA publicó una imagen Docker precompilada para Orin. Es de una línea:
sudo docker run -it --rm --pull always \
--runtime=nvidia --network host \
-v $HOME/.cache/huggingface:/root/.cache/huggingface \
ghcr.io/nvidia-ai-iot/llama_cpp:latest-jetson-orin \
llama-server -hf unsloth/gemma-4-E2B-it-GGUF:Q4_K_S
Atención: esta ruta Docker es texto-only. No carga el mmproj, por lo que no sirve para la demo completa con webcam. Es ideal si solo quieres experimentar el modelo mediante texto sin compilar.
Problemas comunes y soluciones rápidas
- No hay sonido: ejecuta
pactl list short sinksy asegúrate de queSPK_DEVICEcoincide con un sink real. - Mic graba silencio:
arecord -lpara verificar el dispositivo, luego prueba manualmente conarecord -D "$MIC_DEVICE" -f S16_LE -r 16000 -c 1 -d 3 /tmp/test.wav. - Primer arranque lento: normal. Está descargando modelos y generando assets de voz. Las siguientes ejecuciones son más rápidas.
- Agotamiento de memoria: repite la limpieza de procesos, activa swap, baja
-nglo usa la quant Q3 si hace falta.
Un par de detalles finales para que funcione bien
- El archivo
mmprojes imprescindible para visión. No lo omitas. - Si la memoria sigue justa, prioriza
Q4_K_Mo baja aQ3como último recurso. - Mantén el sistema lo más limpio posible antes de arrancar: cada megabyte cuenta.
La experiencia es directa: hablas, el modelo decide si necesita mirar, y responde usando lo que vio. Es un buen ejemplo de cómo la llamada a herramientas nativas en LLMs permite comportamientos emergentes y prácticos en dispositivos embebidos.
