Get up and running with large language models.
0.40.30.1112.9.0Para cargar el ejecutable de Ollama y sus dependencias es necesario cargar
previamente rama0.4 y GCCcore/14.2.0:
module load rama0.4 GCCcore/14.2.0 ollama/0.30.11-CUDA-12.9.0
La carga del módulo no inicia el servidor de Ollama. Después de ejecutar
module load, comandos como ollama list, ollama ps, ollama run,
ollama create y, en esta compilación, incluso ollama --version, intentan
conectarse a una instancia de ollama serve.
Por tanto, si todavía no se ha iniciado el servidor, es normal obtener
mensajes como:
Error: could not connect to ollama server, run 'ollama serve' to start it
o:
Warning: could not connect to a running Ollama instance
Warning: client version is 0.0.0
Estos mensajes no indican necesariamente que el módulo se haya cargado mal.
Para comprobar únicamente que el ejecutable está disponible puede utilizarse:
command -v ollama
module list
La versión instalada se consulta de forma fiable mediante el nombre del módulo
o con:
module spider ollama/0.30.11-CUDA-12.9.0
Una vez iniciado ollama serve, también puede ejecutarse:
ollama --version
Ollama se distribuye bajo la
licencia MIT.
Cada modelo utilizado con Ollama tiene su propia licencia. Antes de usar un
modelo deben revisarse su archivo README.md, su licencia y sus condiciones
de uso.
Ollama puede ejecutarse tanto en nodos de cómputo sin GPU como en nodos con GPU. Para la importación de modelos se recomienda utilizar nodos normales de cómputo, mientras que para la ejecución e inferencia se recomienda utilizar nodos GPU por motivos de rendimiento. La inferencia exclusivamente mediante CPU es posible, pero puede ser considerablemente más lenta.
El uso de Ollama en Drago se divide en dos operaciones principales:
Importación de modelos: se realiza mediante ollama create, preferentemente en un nodo normal de cómputo. El modelo se importa desde los archivos fuente disponibles en /lustre/models al almacén personal de Ollama.
Ejecución e inferencia: una vez importado el modelo, se recomienda ejecutarlo en un nodo GPU para obtener un mayor rendimiento.
En ambos casos es necesario cargar los módulos correspondientes e iniciar ollama serve antes de utilizar comandos como ollama create, ollama list u ollama run.
Importante: cargar el módulo solo hace que el comando
ollamaesté disponible. No inicia el servidor. Los comandos que consultan, crean o ejecutan modelos necesitan conectarse a una instancia deollama serveen ejecución.
Los modelos proporcionados por el centro se encuentran bajo:
/lustre/models/
El listado completo está aquí:
Actualmente pueden encontrarse, entre otros, los siguientes directorios:
/lustre/models/af3
/lustre/models/deepseek
/lustre/models/dorado
/lustre/models/mistral
/lustre/models/ollama
/lustre/models/qwen
Puede consultarse el catálogo mediante:
find /lustre/models -mindepth 1 -maxdepth 2 -type d | sort
También puede inspeccionarse un modelo concreto:
ls -lah /lustre/models/qwen/Qwen2.5-7b-Instruct/
Los directorios bajo /lustre/models contienen los modelos fuente. No todos
ellos están necesariamente en un formato que Ollama pueda ejecutar
directamente.
Un modelo puede contener archivos como:
config.json
generation_config.json
model-00001-of-00003.safetensors
model-00002-of-00003.safetensors
model-00003-of-00003.safetensors
model.safetensors.index.json
tokenizer.json
tokenizer_config.json
Ollama puede importar directamente algunos directorios de pesos safetensors,
pero únicamente cuando el importador de la versión instalada reconoce la
arquitectura exacta del modelo. La presencia de archivos .safetensors no
garantiza por sí sola que el modelo pueda importarse.
Para realizar la importación se utiliza un Modelfile. Un Modelfile es un
archivo de texto que contiene las instrucciones que Ollama debe seguir para
crear y registrar un modelo local. Es similar, en concepto, a un Dockerfile.
La instrucción principal es FROM, que indica el directorio o archivo de
modelo que debe utilizarse. Por ejemplo, puede crearse un archivo llamado
Modelfile con este contenido:
FROM /lustre/models/qwen/Qwen2.5-7b-Instruct
PARAMETER num_ctx 4096
Puede crearse directamente desde la terminal:
mkdir -p "$HOME/ollama-modelfiles/qwen2.5-7b-instruct"
cat >"$HOME/ollama-modelfiles/qwen2.5-7b-instruct/Modelfile" <<'EOF'
FROM /lustre/models/qwen/Qwen2.5-7b-Instruct
PARAMETER num_ctx 4096
EOF
El nombre Modelfile es el habitual, aunque puede utilizarse otro nombre. En
ese caso debe indicarse su ruta mediante la opción -f de ollama create.
ollama create no funciona únicamente con el módulo cargado: necesita
conectarse a un servidor ollama serve en ejecución. Por tanto, antes de
ejecutarlo debe arrancarse el servidor y esperar hasta que responda.
unsupported architectureDurante una importación desde Safetensors puede aparecer un error como:
gathering model components
copying file sha256:... 100%
converting model
Error: unsupported architecture "MistralForCausalLM"
Este error significa que:
ollama serve está funcionando y el cliente ha podido conectarse al servidor.Modelfile es válido.FROM existe y Ollama ha podido leer los archivos del modelo.Por ejemplo, el modelo:
/lustre/models/mistral/Mistral-7B-Instruct-v0.3/
puede contener en su config.json una arquitectura como:
MistralForCausalLM
Si al ejecutar ollama create se obtiene:
Error: unsupported architecture "MistralForCausalLM"
ese modelo no puede importarse directamente desde sus archivos Safetensors con la versión instalada de Ollama.
Puede comprobarse la arquitectura declarada en el archivo config.json mediante:
grep -A 3 '"architectures"' \
/lustre/models/mistral/Mistral-7B-Instruct-v0.3/config.json
En este caso, no es necesario modificar el sbatch, la opción -f ni la ruta del Modelfile si Ollama ya ha llegado a la fase converting model. La solución consiste en utilizar una representación compatible del modelo, normalmente un archivo GGUF, o convertir previamente el modelo a GGUF mediante una herramienta compatible.
Importante: que un modelo utilice Safetensors no implica que Ollama pueda importarlo directamente. La compatibilidad depende tanto del formato como de la arquitectura concreta del modelo y del soporte incluido en la versión de Ollama instalada.
Un modelo GGUF puede importarse con un Modelfile como:
FROM /ruta/al/modelo.gguf
Después, con ollama serve en ejecución:
ollama create nombre-local-del-modelo -f Modelfile
GGUF suele ser el formato más adecuado cuando se necesita un modelo
cuantizado o cuando Ollama no puede importar directamente la arquitectura
desde sus pesos Hugging Face.
.binAlgunos modelos contienen archivos como:
pytorch_model-00001-of-00002.bin
pytorch_model-00002-of-00002.bin
pytorch_model.bin.index.json
Por ejemplo:
/lustre/models/deepseek/deepseek-llm-7b-chat/
Los archivos PyTorch .bin no se importan directamente mediante FROM.
No es válido apuntar a un fragmento de pesos:
FROM /lustre/models/deepseek/deepseek-llm-7b-chat/pytorch_model-00001-of-00002.bin
Para utilizar un modelo disponible únicamente en .bin debe existir
previamente una de estas alternativas:
safetensors compatible con Ollama.Cambiar solamente la extensión de .bin a .safetensors o .gguf no
convierte el modelo.
Incluso después de convertir los pesos a safetensors, la arquitectura debe
estar soportada por Ollama. Si no lo está, normalmente será necesario generar
un GGUF mediante las herramientas de llama.cpp, siempre que esa arquitectura
sea compatible con dichas herramientas.
Ollama mantiene su propio almacén de modelos. Se recomienda definirlo
explícitamente en una ubicación escribible por el usuario:
export OLLAMA_MODELS="$HOME/.ollama/models"
mkdir -p "$OLLAMA_MODELS"
No debe establecerse:
export OLLAMA_MODELS=/lustre/models
/lustre/models contiene modelos fuente compartidos, mientras que
OLLAMA_MODELS debe apuntar al almacén interno y escribible de Ollama.
Al ejecutar ollama create, Ollama registra el modelo en ese almacén. Esta
operación puede crear una copia o nuevos blobs y, por tanto, puede consumir
una cantidad importante de espacio en la cuenta del usuario.
Para ver los modelos ya importados es necesario que el servidor esté
iniciado y que el cliente use el mismo valor de OLLAMA_HOST y
OLLAMA_MODELS:
ollama list
Para eliminar un modelo importado, el servidor también debe estar iniciado:
ollama rm nombre-local-del-modelo
La eliminación del modelo registrado no modifica los archivos fuente
originales de /lustre/models.
La importación mediante ollama create no requiere una GPU. Por tanto, se recomienda realizarla en un nodo normal de cómputo de la partición generic, evitando reservar una GPU para una operación que depende principalmente de la CPU, la memoria RAM y el sistema de almacenamiento.
La importación solo tiene que realizarse una vez por usuario y por almacén de Ollama. Una vez importado, el modelo queda registrado en el almacén definido mediante OLLAMA_MODELS y puede utilizarse posteriormente desde los nodos GPU.
Como ejemplo se utiliza el modelo:
/lustre/models/qwen/Qwen2.5-7b-Instruct/
Este modelo se ha comprobado con la instalación actual de Ollama y puede
importarse correctamente desde los archivos disponibles en ese directorio.
Un Modelfile es un archivo de texto que contiene las instrucciones que Ollama debe seguir para crear y registrar un modelo local. Es similar, en concepto, a un Dockerfile.
La instrucción principal es FROM, que indica el directorio o archivo del modelo fuente. Por ejemplo:
FROM /lustre/models/qwen/Qwen2.5-7b-Instruct
PARAMETER num_ctx 4096
En este ejemplo:
FROM indica el directorio que contiene los pesos y archivos de configuración del modelo.PARAMETER num_ctx 4096 establece una ventana de contexto predeterminada de 4096 tokens.El archivo puede crearse desde la terminal mediante:
mkdir -p "$HOME/ollama-modelfiles/qwen2.5-7b-instruct"
cat >"$HOME/ollama-modelfiles/qwen2.5-7b-instruct/Modelfile" <<'EOF'
FROM /lustre/models/qwen/Qwen2.5-7b-Instruct
PARAMETER num_ctx 4096
EOF
ollama create necesita conectarse a un servidor ollama serve en ejecución. No basta con cargar el módulo y ejecutar directamente ollama create.
Ejemplo de archivo ollama_import.sh:
#!/bin/bash
#SBATCH --job-name=ollama-import
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8
#SBATCH --mem=64G
#SBATCH --time=02:00:00
#SBATCH --partition=generic
#SBATCH --output=ollama-import-%j.out
#SBATCH --error=ollama-import-%j.err
set -euo pipefail
module load rama0.4 GCCcore/14.2.0 ollama/0.30.11-CUDA-12.9.0
export OLLAMA_MODELS="$HOME/.ollama/models"
export OLLAMA_NO_CLOUD=1
export OLLAMA_HOST="127.0.0.1:11434"
mkdir -p "$OLLAMA_MODELS"
ollama serve >"ollama-server-${SLURM_JOB_ID}.log" 2>&1 &
OLLAMA_PID=$!
cleanup() {
kill "$OLLAMA_PID" 2>/dev/null || true
}
trap cleanup EXIT INT TERM
until curl -sf http://127.0.0.1:11434/api/tags >/dev/null; do
if ! kill -0 "$OLLAMA_PID" 2>/dev/null; then
echo "Error: el servidor de Ollama ha terminado inesperadamente."
cat "ollama-server-${SLURM_JOB_ID}.log"
exit 1
fi
sleep 1
done
ollama create qwen2.5-7b-instruct \
-f "$HOME/ollama-modelfiles/qwen2.5-7b-instruct/Modelfile"
ollama list
Si ollama create termina con un mensaje unsupported architecture, debe
consultarse la sección anterior. Ese error indica una incompatibilidad del
importador con la arquitectura del modelo, no un fallo de conexión con
ollama serve ni un error en la opción -f.
El trabajo se envía mediante:
sbatch ollama_import.sh
Al finalizar, el modelo queda registrado en el almacén personal:
$HOME/.ollama/models
Importante: el modelo fuente de
/lustre/modelsy el modelo registrado por Ollama son conceptos distintos./lustre/modelscontiene los archivos fuente compartidos, mientras queOLLAMA_MODELSapunta al almacén interno y escribible utilizado por Ollama.
Una vez importado el modelo, se recomienda realizar la inferencia en un nodo GPU. Ollama también puede ejecutar modelos exclusivamente mediante CPU, pero el rendimiento puede ser considerablemente inferior, especialmente con modelos grandes.
Una vez importado el modelo, puede ejecutarse mediante un trabajo por lotes.
Archivo ollama_run.sbatch:
#!/bin/bash
#SBATCH --job-name=ollama
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=28
#SBATCH --gres=gpu:1
#SBATCH --mem=64G
#SBATCH --time=02:00:00
#SBATCH --partition=gpu
#SBATCH --output=ollama-%j.out
#SBATCH --error=ollama-%j.err
set -euo pipefail
module load rama0.4 GCCcore/14.2.0 ollama/0.30.11-CUDA-12.9.0
MODEL="qwen2.5-7b-instruct"
PROMPT="What does CSIC stand for?"
export OLLAMA_MODELS="$HOME/.ollama/models"
export OLLAMA_NO_CLOUD=1
export OLLAMA_NUM_PARALLEL=1
export OLLAMA_MAX_LOADED_MODELS=1
# Limitar las bibliotecas auxiliares a las CPU concedidas por SLURM.
export OMP_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export OPENBLAS_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export MKL_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export NUMEXPR_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export OLLAMA_PORT="$((20000 + SLURM_JOB_ID % 30000))"
export OLLAMA_HOST="127.0.0.1:${OLLAMA_PORT}"
OLLAMA_LOG="${SLURM_TMPDIR:-/tmp}/ollama-server-${SLURM_JOB_ID}.log"
ollama serve >"$OLLAMA_LOG" 2>&1 &
OLLAMA_PID=$!
cleanup() {
kill "$OLLAMA_PID" 2>/dev/null || true
}
trap cleanup EXIT INT TERM
OLLAMA_READY=0
for intento in $(seq 1 120); do
if curl --silent --fail \
"http://127.0.0.1:${OLLAMA_PORT}/api/tags" >/dev/null; then
OLLAMA_READY=1
break
fi
if ! kill -0 "$OLLAMA_PID" 2>/dev/null; then
break
fi
sleep 1
done
if [[ "$OLLAMA_READY" -ne 1 ]]; then
echo "Error: el servidor de Ollama no se ha iniciado correctamente."
cat "$OLLAMA_LOG"
exit 1
fi
if ! ollama list | awk 'NR > 1 {print $1}' | grep -Fxq "$MODEL"; then
echo "Error: el modelo '$MODEL' no está importado."
echo "Modelos disponibles:"
ollama list
exit 1
fi
curl --silent --show-error --fail \
"http://127.0.0.1:${OLLAMA_PORT}/api/generate" \
--header "Content-Type: application/json" \
--data @- <<EOF
{
"model": "${MODEL}",
"prompt": "${PROMPT}",
"stream": false,
"options": {
"num_thread": ${SLURM_CPUS_PER_TASK}
}
}
EOF
echo
Enviar el trabajo:
sbatch ollama_run.sbatch
Este procedimiento crea un trabajo de SLURM que mantiene activo el servidor de
Ollama en un nodo GPU. Desde el ordenador del usuario se abre un túnel SSH
hasta ese servidor.
El término «interactivo» se refiere aquí al uso interactivo de la API o del
cliente de Ollama. La reserva de recursos sigue siendo un trabajo sbatch.
ollama_interactivo.sbatch#!/bin/bash
#SBATCH --job-name=ollama-interactivo
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=16
#SBATCH --gres=gpu:1
#SBATCH --mem=64G
#SBATCH --time=04:00:00
#SBATCH --partition=gpu
#SBATCH --output=ollama-session-%j.out
#SBATCH --error=ollama-session-%j.err
set -euo pipefail
module load rama0.4 GCCcore/14.2.0 ollama/0.30.11-CUDA-12.9.0
export OLLAMA_MODELS="$HOME/.ollama/models"
export OLLAMA_NO_CLOUD=1
export OLLAMA_NUM_PARALLEL=1
export OLLAMA_MAX_LOADED_MODELS=1
export OMP_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export OPENBLAS_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export MKL_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export NUMEXPR_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
# Cada trabajo utiliza un puerto distinto.
export OLLAMA_PORT="$((20000 + SLURM_JOB_ID % 30000))"
# Ollama solo escucha en el loopback del nodo de cálculo.
# El acceso se realizará mediante un túnel SSH.
export OLLAMA_HOST="127.0.0.1:${OLLAMA_PORT}"
NODE_NAME="$(hostname -s)"
SESSION_DIR="$HOME/.ollama/sessions"
SESSION_FILE="${SESSION_DIR}/ollama-${SLURM_JOB_ID}.info"
OLLAMA_LOG="${SESSION_DIR}/ollama-${SLURM_JOB_ID}.log"
mkdir -p "$SESSION_DIR"
ollama serve >"$OLLAMA_LOG" 2>&1 &
OLLAMA_PID=$!
cleanup() {
kill "$OLLAMA_PID" 2>/dev/null || true
rm -f "$SESSION_FILE"
}
trap cleanup EXIT INT TERM
OLLAMA_READY=0
for intento in $(seq 1 120); do
if curl --silent --fail \
"http://127.0.0.1:${OLLAMA_PORT}/api/tags" >/dev/null; then
OLLAMA_READY=1
break
fi
if ! kill -0 "$OLLAMA_PID" 2>/dev/null; then
break
fi
sleep 1
done
if [[ "$OLLAMA_READY" -ne 1 ]]; then
echo "Error: Ollama no ha iniciado correctamente."
cat "$OLLAMA_LOG"
exit 1
fi
cat >"$SESSION_FILE" <<EOF
SLURM_JOB_ID=${SLURM_JOB_ID}
NODE_NAME=${NODE_NAME}
OLLAMA_PORT=${OLLAMA_PORT}
OLLAMA_HOST=${OLLAMA_HOST}
OLLAMA_MODELS=${OLLAMA_MODELS}
EOF
chmod 600 "$SESSION_FILE"
cat <<EOF
============================================================
Servidor de Ollama preparado
============================================================
Trabajo SLURM : ${SLURM_JOB_ID}
Nodo : ${NODE_NAME}
Puerto remoto : ${OLLAMA_PORT}
Almacén : ${OLLAMA_MODELS}
Registro : ${OLLAMA_LOG}
Info sesión : ${SESSION_FILE}
Desde el ordenador local debe abrirse un túnel SSH con:
ssh -N \
-L 11435:127.0.0.1:${OLLAMA_PORT} \
-J <usuario>@<drago.csic.es> \
<usuario>@${NODE_NAME}
Después, en otra terminal local:
export OLLAMA_HOST=127.0.0.1:11435
ollama list
ollama run <nombre-del-modelo>
También puede probarse la API:
curl http://127.0.0.1:11435/api/tags
Para cerrar la sesión:
scancel ${SLURM_JOB_ID}
============================================================
EOF
# Mantener el trabajo activo mientras el servidor siga funcionando.
wait "$OLLAMA_PID"
Desde el nodo de acceso:
sbatch ollama_interactivo.sbatch
El comando mostrará el identificador del trabajo, por ejemplo:
Submitted batch job 123456
squeue -j 123456 \
-o "%.18i %.9P %.24j %.8T %.20N %.10M %.10l"
El estado debe ser RUNNING.
cat ollama-session-123456.out
También puede consultarse el archivo de sesión:
cat "$HOME/.ollama/sessions/ollama-123456.info"
La salida indicará, por ejemplo:
NODE_NAME=drago32060019
OLLAMA_PORT=23456
El acceso a Drago utiliza autenticación mediante clave pública y privada. La clave privada debe permanecer en el ordenador local y no debe copiarse ni al nodo de acceso ni a los nodos de cálculo.
El nodo de acceso es:
drago.csic.es
El error:
Permission denied (publickey,gssapi-keyex,gssapi-with-mic)
indica que SSH no ha podido utilizar una clave privada válida para autenticarse en drago.csic.es. Antes de abrir el túnel debe cargarse la clave en ssh-agent o indicarse explícitamente mediante -i.
ssh-addEn el ordenador local, iniciar un agente SSH:
eval "$(ssh-agent -s)"
Cargar la clave privada:
ssh-add ~/.ssh/clave_privada
Sustituya ~/.ssh/clave_privada por la ruta real de la clave utilizada para acceder a Drago.
Comprobar que la clave está cargada:
ssh-add -l
Antes de crear el túnel puede verificarse el acceso al nodo de entrada:
ssh user@drago.csic.es
Una vez comprobado el acceso, abrir el túnel hacia el nodo GPU asignado por SLURM:
ssh -N \
-L 47886:127.0.0.1:47886 \
-J user@drago.csic.es \
user@drago32060019
Deben sustituirse:
user por el nombre de usuario correspondiente.drago32060019 por el nodo asignado por SLURM.47886 por el puerto utilizado por OLLAMA_HOST dentro del trabajo.La opción -J indica que la conexión al nodo de cálculo se realiza pasando por drago.csic.es.
-iSi no se desea utilizar ssh-agent, puede indicarse explícitamente la clave privada tanto para el nodo de acceso como para el nodo de cálculo:
ssh \
-i ~/.ssh/clave_privada \
-o IdentitiesOnly=yes \
-o 'ProxyCommand=ssh -i ~/.ssh/clave_privada -o IdentitiesOnly=yes -W %h:%p user@drago.csic.es' \
-N \
-L 47886:127.0.0.1:47886 \
user@drago32060019
Esta forma es más larga, pero no requiere haber ejecutado previamente ssh-add.
~/.ssh/configPara evitar escribir todos los parámetros en cada conexión, puede añadirse al archivo ~/.ssh/config del ordenador local:
Host drago
HostName drago.csic.es
User user
IdentityFile ~/.ssh/clave_privada
IdentitiesOnly yes
Host drago3*
User user
IdentityFile ~/.ssh/clave_privada
IdentitiesOnly yes
ProxyJump drago
Después, el túnel puede abrirse con:
ssh -N \
-L 47886:127.0.0.1:47886 \
drago32060019
Si el puerto local ya está ocupado, puede usarse otro puerto únicamente en el lado local. Por ejemplo:
ssh -N \
-L 11435:127.0.0.1:47886 \
-J user@drago.csic.es \
user@drago32060019
En ese caso, desde el ordenador local debe utilizarse:
export OLLAMA_HOST=127.0.0.1:11435
En otra terminal local:
curl http://127.0.0.1:11435/api/tags
Para generar una respuesta:
curl http://127.0.0.1:11435/api/generate \
-H "Content-Type: application/json" \
-d '{
"model": "qwen2.5-7b-instruct",
"prompt": "Explica brevemente qué es el CSIC.",
"stream": false
}'
Si el cliente ollama está instalado en el ordenador local:
export OLLAMA_HOST="127.0.0.1:11435"
Comprobar los modelos del servidor remoto:
ollama list
Abrir una conversación:
ollama run qwen2.5-7b-instruct
Aunque el comando se ejecuta en el ordenador local, la inferencia se realiza
en la GPU del nodo reservado por SLURM.
No debe ejecutarse otro ollama serve en el ordenador local usando el mismo
puerto configurado en OLLAMA_HOST.
Las aplicaciones que permiten configurar una URL de Ollama deben apuntar a:
http://127.0.0.1:11435
Para una API compatible con OpenAI, cuando la aplicación lo admita:
http://127.0.0.1:11435/v1
El túnel debe permanecer abierto y el trabajo de SLURM debe seguir en estado
RUNNING.
Desde el nodo de acceso:
scancel 123456
También debe cerrarse el proceso SSH del túnel con Ctrl+C.
Si se agota el tiempo solicitado mediante #SBATCH --time, SLURM terminará el
servidor automáticamente.
sallocCuando se necesite además una shell interactiva en el nodo GPU:
salloc \
--partition=gpu \
--nodes=1 \
--ntasks=1 \
--cpus-per-task=16 \
--gres=gpu:1 \
--mem=64G \
--time=04:00:00
Después:
srun --pty bash
Dentro del nodo:
module load rama0.4 GCCcore/14.2.0 ollama/0.30.11-CUDA-12.9.0
export OLLAMA_MODELS="$HOME/.ollama/models"
export OLLAMA_NO_CLOUD=1
export OLLAMA_NUM_PARALLEL=1
export OLLAMA_MAX_LOADED_MODELS=1
export OMP_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export OPENBLAS_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export MKL_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export OLLAMA_PORT="$((20000 + SLURM_JOB_ID % 30000))"
export OLLAMA_HOST="127.0.0.1:${OLLAMA_PORT}"
ollama serve >"$HOME/ollama-${SLURM_JOB_ID}.log" 2>&1 &
OLLAMA_PID=$!
Esperar a que responda:
until curl --silent --fail \
"http://127.0.0.1:${OLLAMA_PORT}/api/tags" >/dev/null; do
sleep 1
done
Ejecutar un modelo dentro del nodo:
ollama run qwen2.5-7b-instruct
También puede abrirse el mismo túnel SSH descrito anteriormente utilizando el
nodo asignado y el valor de OLLAMA_PORT.
Al finalizar:
kill "$OLLAMA_PID"
exit
Después debe liberarse la reserva:
exit
Estas variables limitan las bibliotecas auxiliares que las respeten:
export OMP_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export OPENBLAS_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export MKL_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
export NUMEXPR_NUM_THREADS="${SLURM_CPUS_PER_TASK}"
Sin embargo, no garantizan por sí solas que el ejecutor del modelo utilice
exactamente ese número de hilos.
Cuando se usa la API, puede enviarse num_thread dentro de options:
{
"model": "qwen2.5-7b-instruct",
"prompt": "Explica qué es SLURM.",
"stream": false,
"options": {
"num_thread": 16
}
}
En un script de SLURM puede vincularse al número de CPU concedidas:
"num_thread": ${SLURM_CPUS_PER_TASK}
En una sesión de ollama run también puede establecerse interactivamente:
/set parameter num_thread 16
El valor no debe superar SLURM_CPUS_PER_TASK.
Mientras el modelo esté cargado:
ollama ps
La columna PROCESSOR muestra dónde está cargado el modelo. Por ejemplo:
100% GPU
100% CPU
48%/52% CPU/GPU
También puede comprobarse la GPU con:
nvidia-smi
SLURM configura automáticamente CUDA_VISIBLE_DEVICES para limitar el trabajo
a las GPU asignadas. No es necesario establecer manualmente
GPU_DEVICE_ORDINAL.
Debe solicitarse memoria suficiente para:
ollama create.Un contexto mayor consume más memoria. Por ejemplo:
PARAMETER num_ctx 4096
requiere menos memoria que:
PARAMETER num_ctx 32768
Si el modelo no cabe completamente en la GPU, Ollama puede repartirlo entre
la VRAM y la memoria principal, pero el rendimiento puede disminuir
considerablemente.
Revisar el registro indicado por el script:
cat "$HOME/.ollama/sessions/ollama-<jobid>.log"
O, para el trabajo no interactivo:
cat "${SLURM_TMPDIR:-/tmp}/ollama-server-${SLURM_JOB_ID}.log"
Comprobar:
ss -ltn | grep "$OLLAMA_PORT"
El uso de un puerto derivado de SLURM_JOB_ID reduce la posibilidad de
colisión, pero no la elimina completamente.
Puede elegirse otro puerto manualmente:
export OLLAMA_PORT=31434
export OLLAMA_HOST="127.0.0.1:${OLLAMA_PORT}"
Comprobar:
RUNNING.squeue o por el archivo .info.OLLAMA_PORT.curl "http://127.0.0.1:${OLLAMA_PORT}/api/tags"
Para obtener información detallada del túnel:
ssh -vvv -N \
-L 11435:127.0.0.1:<puerto-remoto> \
-J <usuario>@<drago.csic.es> \
<usuario>@<nodo-calculo>
Comprobar que el servidor utiliza el mismo almacén en el que se importó:
echo "$OLLAMA_MODELS"
ollama list
El nombre solicitado no coincide con un modelo registrado localmente.
Comprobar:
ollama list
Debe utilizarse exactamente uno de los nombres mostrados.
También debe estar definido:
export OLLAMA_NO_CLOUD=1
.binLos pesos PyTorch .bin no son directamente importables. Debe utilizarse una
versión compatible en safetensors, GGUF o ya preparada para Ollama.
Comprobar:
num_thread no supera SLURM_CPUS_PER_TASK.OLLAMA_NUM_PARALLEL=1.OLLAMA_MAX_LOADED_MODELS=1.Puede consultarse el consumo del trabajo con:
sstat -j "${SLURM_JOB_ID}.batch" \
--format=JobID,AveCPU,MaxRSS,AveRSS
Y revisar el estado final con:
sacct -j "$SLURM_JOB_ID" \
--format=JobID,JobName,State,ExitCode,Elapsed,AllocCPUS,ReqMem,MaxRSS
El script interactivo configura:
export OLLAMA_HOST="127.0.0.1:${OLLAMA_PORT}"
De esta forma, Ollama no publica su API directamente en la red del clúster.
Solo los procesos del propio nodo pueden conectarse al puerto, salvo que se
cree explícitamente un túnel SSH.
No se recomienda cambiarlo a:
export OLLAMA_HOST="0.0.0.0:${OLLAMA_PORT}"
salvo que la política del centro lo permita y se conozcan las implicaciones.
La API local de Ollama no debe considerarse un servicio multiusuario
autenticado.
El uso recomendado de Ollama en Drago se divide en dos fases:
Importación del modelo en un nodo normal de cómputo. El modelo fuente se toma de /lustre/models y se registra mediante ollama create en el almacén personal definido por OLLAMA_MODELS. Esta operación no requiere GPU y normalmente solo se realiza una vez.
Ejecución e inferencia en un nodo GPU. Una vez registrado el modelo, se solicita un nodo GPU y se inicia ollama serve. El modelo puede utilizarse mediante un trabajo por lotes o de forma interactiva a través de un túnel SSH.
Aunque Ollama puede ejecutar inferencia exclusivamente mediante CPU, para modelos de lenguaje de tamaño significativo se recomienda utilizar GPU por motivos de rendimiento.