Ejecución de LLM con vGPU NVIDIA¶
Contexto:¶
Un LLM (Modelo de Lenguaje de Gran Escala) es un modelo de inteligencia artificial basado en redes neuronales profundas, diseñado para procesar y generar texto de manera similar a como lo hacen los humanos. Estos modelos se entrenan con grandes cantidades de datos textuales, cosa que les permite comprender el contexto, responder preguntas y crear contenido con una calidad notable. Son herramientas potentes que pueden adaptarse a varias tareas, como la de traducción, la de redacción o el análisis de textos, y son la base de muchas aplicaciones modernas de IA.
Ollama, por otro lado, es una herramienta de código abierto que facilita la ejecución de LLMs en dispositivos locales, cosa que permite a los usuarios sacar provecho de modelos avanzados sin tener que depender de servicios en la nube. Esto significa que puedes tener un modelo como DeepSeek, conocido por su eficiencia y capacidad multilingüe, funcionando directamente en tu ordenador. Esto ofrece un mayor control sobre el modelo y los datos que procesa, a demás de hacerlo accesible en entornos sin conexión a internet.
Utilizar estos modelos localmente ofrece ventajas como una mayor privacidad, ya que los datos no salen de tu dispositivo, y elimina los costes asociados a los servicios en la nube. Por ejemplo, con DeepSeek ejecutado localmente a través de Ollama, un usuario podría personalizarlo pera tareas especializadas, como el análisis técnico o la generación de contenido en un idioma concreto, como el castellano, todo desde su propio equipo. Esta autonomía y flexibilidad hacen que sea una opción muy valiosa pera usuarios individuales u organizaciones con necesidades específicas.
Caso de uso¶
Objetivo: ejecutar un LLM (Large Language Model) en un escritorio virtual con una NVIDIA vGPU. Sistema operativo: Ubuntu 22.04
Crear escritorio con GPU¶
Seguiremos los siguientes pasos:
1. Crearemos un escritorio con Sistema Operativo Ubuntu. (Manual para crear escritorio Ubuntu 22.04: https://isard.gitlab.io/isardvdi-docs/guests/ubuntu_22.04/desktop/installation/installation.ca/)
-
Le daremos el perfil de la GPU que tenemos disponible en la infraestructura de Isard.
-
Dejaremos la tarjeta de video "Default"
Actualización del sistema operativo¶
sudo apt update
sudo apt upgrade -y
Pasos previos para utilizar NVIDIA con docker y por cómputo¶
Seleccionar NVIDIA solamente por cómputo.¶
Es importante que la tarjeta vGPU de NVIDIA no se configure como el dispositivo gráfico principal del sistema. Si la vGPU se encarga de renderizar el entorno gráfico, consumirá recursos que deberían destinarse a su función principal: el procesamiento de datos. Esto afecta la eficiencia y el rendimiento en tareas de cálculo intensivo. Por ello, es recomendable asignar una GPU secundaria para la gestión gráfica y reservar la vGPU exclusivamente para el procesamiento de datos.
La tarjeta de vídeo "default" en realidad es la QXL, le decimos a xorg que utilice esta tarjeta.
isard@ubuntu22:~$ cat /etc/X11/xorg.conf.d/10-qxl.conf
Section "Device"
Identifier "QXL"
Driver "qxl"
BusID "PCI:0:1:0" # Ajusta esto segun la salida de lspci por QXL
EndSection
Section "Screen"
Identifier "Screen0"
Device "QXL"
EndSection
Con QXL nos interesa que no arranque wayland con el gestor de inicio de sesión gdm3, es necesario validar que tenemos:
# GDM configuration storage
#
# See /usr/share/gdm/gdm.schemas for a list of available options.
[daemon]
AutomaticLoginEnable=true
AutomaticLogin=isard
WaylandEnable=false
Instalar drivers correctos de NVIDIA¶
Hemos de tener los drivers acordes a la versión del módulo de kernel del servidor. Lo más recomendable es instalar la versión Long-Term Support (v16 - R535)
vGPU Software Release | Driver Branch | vGPU Branch Type | Latest Release in Branch | Release Date | EOL Date |
---|---|---|---|---|---|
NVIDIA vGPU 18 | R570 | Production | 18.0 | March 2025 | March 2026 |
NVIDIA vGPU 17 | R550 | Production | 17.5 | January 2025 | June 2025 |
NVIDIA vGPU 16 | R535 | Long-Term Support | 16.9 | January 2025 | July 2026 |
-
Manuales para poder realizar la instalación correcta de los drivers y el token.
-
Instalación de drivers: https://isard.gitlab.io/isardvdi-docs/user/gpu.es/#instalacion
-
Instalación del token: https://isard.gitlab.io/isardvdi-docs/user/gpu.es/#gestion-del-token
-
sudo cp /media/isard/nvidia/nvidia_16/Guest_Drivers/nvidia-linux-grid-535_535.230.02_amd64.deb /opt/
sudo apt install /opt/nvidia-linux-grid-535_535.230.02_amd64.deb -y
reboot
Verificamos con nvidia-smi que se detecta el driver y la versión de CUDA:
isard@ubuntu22:~$ nvidia-smi
Mon Mar 10 17:23:13 2025
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.230.02 Driver Version: 535.230.02 CUDA Version: 12.2 |
|-----------------------------------------+----------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+======================+======================|
| 0 NVIDIA A16-4Q On | 00000000:06:00.0 Off | 0 |
| N/A N/A P0 N/A / N/A | 57MiB / 4096MiB | 0% Default |
| | | Disabled |
+-----------------------------------------+----------------------+----------------------+
+---------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=======================================================================================|
| 0 N/A N/A 1263 C+G ...libexec/gnome-remote-desktop-daemon 57MiB |
+---------------------------------------------------------------------------------------+
Hay un proceso "gnome-remote-desktop-daemon" que es para el acceso rdp, y que no debería de utilizar la NVIDIA. Es un bug y de momento no hemos podido evitarlo.
Licenciamiento NVIDIA¶
Es necesario añadir licencia de NVIDIA modificando FeatureType en gridd.conf:
isard@ubuntu22:/opt/llm$ sudo grep FeatureType /etc/nvidia/gridd.conf
FeatureType=1
Y añadir fichero de token al directorio ClientConfigToken:
isard@ubuntu22:/opt/llm$ sudo ls -lh /etc/nvidia/ClientConfigToken/
total 4,0K
-rw-r--r-- 1 root root 2,7K mar 10 18:30 token2.tok
Reinicio del servicio de licenciamiento:
sudo systemctl restart nvidia-gridd.service
Verificar que está licenciada con nvidia-smi -q:
isard@ubuntu22:/opt/llm$ nvidia-smi -q |grep "License Status"
License Status : Licensed (Expiry: 2025-3-11 17:31:20 GMT)
Se reinicia y verificamos que utiliza la qxl con esta orden:
sudo apt install mesa-utils -y
glxinfo |grep -i nvidia
No tiene que salir ninguna línea de NVIDIA.
Install docker¶
https://docs.docker.com/engine/install/ubuntu/
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
sudo docker run hello-world
Añadir a docker que pueda utilizar gpus:¶
Nos será necesario nvidia-container-toolkit
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update
sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
Verificamos que se ha modificado el fichero de configuración:
isard@ubuntu22:~$ cat /etc/docker/daemon.json
{
"runtimes": {
"nvidia": {
"args": [],
"path": "nvidia-container-runtime"
}
}
}
Ahora restart del servicio de docker y verificamos que nvidia-smi funciona y acepta y reconoce las gpus:
sudo systemctl restart docker
sudo docker run --rm --gpus all nvidia/cuda:12.0.0-base-ubuntu22.04 nvidia-smi
Docker compose¶
mkdir /opt/llm
cd /opt/llm
Crear fichero docker-compose.yml:
services:
ollama:
image: ollama/ollama:latest
container_name: ollama
ports:
- "11434:11434"
volumes:
- /opt/ollama/volume_ollama:/root/.ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
environment:
- OLLAMA_HOST=0.0.0.0:11434
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-WebUI
ports:
- "3000:8080"
volumes:
- /opt/ollama/openwebui_backend_data:/app/backend/data
environment:
- OLLAMA_BASE_URL=http://ollama:11434
extra_hosts:
- "host.docker.internal:host-gateway"
restart: always
Arrancar docker compose:
docker compose up -d
Run del modelo:
Modelo | Requisitos | Comando |
---|---|---|
1.5B Parámetros | 1.1 GB aprox. | ollama run deepseek-r1:1.5b |
7B Parámetros | 4.7 GB aprox. | ollama run deepseek-r1 |
70B Parámetros | +20 GB de vRAM | ollama run deepseek-r1:70b |
671B Parámetros | +300 GB de vRAM | ollama run deepseek-r1:671b |
sudo docker exec -ti ollama ollama run deepseek-r1:1.5b
En un navegador introducimos la siguiente dirección: http://localhost:3000
Verificar que responde con python¶
sudo apt install python3-virtualenv -y
mkdir -p dev/llm_python
cd dev/llm_python
virtualenv venv
source venv/bin/activate
Dentro del venv:
pip3 install ipython openai
ipython3
código python, hacemos copy/paste:
import openai
# Conectarse a Ollama
client = openai.Client(
base_url="http://localhost:11434/v1",
api_key="ollama"
)
response = client.chat.completions.create(
model="deepseek-r1", # Cambiamos 1.5b por la versión instalada
messages=[{"role": "user", "content": "Hellow in catalan"}],
temperature=0.7
)
print(response.choices[0].message.content)