12 de noviembre de 2026 · Equipo de VRAMfarm
Fine-tuning de un LLM: cuánta VRAM y cuántas GPU para QLoRA, LoRA y ajuste completo
La mayoría de los trabajos de fine-tuning necesitan una GPU, no ocho. QLoRA entrena un modelo de 8B en una tarjeta de 16 GB, uno de 32B en una de 48 GB y uno de 70B en una sola tarjeta de 80 GB. LoRA en 16 bits necesita entre dos y tres veces más. Solo el ajuste fino completo, que actualiza todos los pesos, te obliga a usar varias tarjetas de 80 GB incluso con un modelo de 8B, porque cuesta unos 16 bytes por parámetro antes de las activaciones. Un entrenamiento típico con QLoRA de un modelo de 8B con 15 millones de tokens de entrenamiento tarda 2–4 horas en una RTX 4090 y cuesta 1,65 € en tiempo de GPU.
Antes de nada: ¿necesitas hacer fine-tuning?
El fine-tuning enseña a un modelo un formato, un tono o una tarea concreta: responder con el estilo de tu soporte, extraer campos a tu esquema JSON, clasificar tickets en tus categorías. Es una mala forma de añadir conocimiento. Si el modelo tiene que conocer la documentación de tu producto, pon los documentos delante en el momento de la pregunta (recuperación, o simplemente un prompt largo) y mantenlos al día sin reentrenar. Prueba primero un buen prompt con unos cuantos ejemplos sobre el modelo base; si aun así se equivoca con el formato o el estilo en uno de cada cinco casos, el fine-tuning merece la pena.
Memoria por método: las cuentas
Tres métodos, tres facturas de memoria muy distintas:
- QLoRA carga el modelo base en 4 bits (unos 0,6 bytes por parámetro) y entrena junto a él unas matrices adaptadoras pequeñas. El modelo base se queda congelado, así que no hay gradientes ni estados del optimizador para él.
- LoRA hace lo mismo con el modelo base en 16 bits: 2 bytes por parámetro, algo más de calidad y más memoria.
- El ajuste fino completo actualiza todos los pesos. Con el optimizador AdamW estándar en precisión mixta, cada parámetro cuesta unos 16 bytes: pesos y gradientes en 16 bits, una copia maestra en fp32 y dos estados del optimizador en fp32. Un optimizador de 8 bits y pesos en 16 bits sin la copia maestra lo dejan en unos 6–8 bytes.
Encima van las activaciones, que crecen con la longitud de secuencia y el tamaño de lote. Las cifras de abajo suponen secuencias de 2000–4000 tokens, un lote pequeño y gradient checkpointing, que recalcula las activaciones en vez de guardarlas.
| Método | Modelo de 8B | Modelo de 32B | Modelo de 70B |
|---|---|---|---|
| QLoRA | 10–16 GB: tarjeta de 16–24 GB | 24–32 GB: tarjeta de 32–48 GB | 45–60 GB: tarjeta de 80 GB (48 GB con Unsloth y secuencias cortas) |
| LoRA, base en 16 bits | 20–28 GB: tarjeta de 24–32 GB | 70–85 GB: tarjeta de 80–96 GB | 150–170 GB: B200, o 2–4 × 80 GB con sharding |
| Completo, optimizador de 8 bits | 60–75 GB: una tarjeta de 80 GB | 200–260 GB: 4 × 80 GB | 450–560 GB: 8 × 80 GB |
| Completo, AdamW | 130–160 GB: 2–4 × 80 GB, o una B200 | 520–600 GB: 8 × 80 GB | 1,1–1,3 TB: 8 × B200 |
Son rangos porque los entrenadores varían: los kernels de Unsloth necesitan bastante menos que el código normal de Hugging Face, y las secuencias largas suben todas las filas. La guía de VRAM explica las cuentas de bytes por parámetro, y la guía de CUDA out of memory, qué ajustar cuando un entrenamiento no cabe: tamaño de lote, longitud de secuencia, gradient checkpointing, optimizadores de 8 bits.
Una tarea rara vez necesita el ajuste fino completo. LoRA en todas las capas lineales con un rango de 16–64 recupera casi toda la mejora en estilo, formato y tareas concretas. El ajuste fino completo compensa lo que cuesta en el preentrenamiento continuado sobre un corpus grande, en un idioma nuevo o en un cambio de dominio profundo.
Una tarjeta o varias
Al añadir tarjetas pasan dos cosas distintas, y solo una de ellas ahorra memoria.
Paralelismo de datos (DDP): cada tarjeta tiene una copia completa del modelo y procesa lotes distintos. La memoria por tarjeta sigue igual; la velocidad crece, más o menos 1,8 veces con dos tarjetas y 3,5 veces con cuatro. Sirve cuando un entrenamiento cabe en una tarjeta pero tardaría toda la noche.
Sharding (FSDP, DeepSpeed ZeRO-3): los pesos, los gradientes y los estados del optimizador se reparten entre las tarjetas, de modo que entre todas sostienen un modelo que ninguna podría sola. Así funcionan el ajuste fino completo y LoRA en 16 bits con modelos grandes. Las tarjetas intercambian datos en cada paso, así que la conexión importa: las máquinas de centro de datos con NVLink, como 8 × H100, escalan bien; las tarjetas de consumo como la RTX 4090 y la 5090 se comunican por PCIe y escalan bastante peor. QLoRA combinado con FSDP puede incluso repartir un modelo de 70B entre dos tarjetas de 24 GB, a una velocidad modesta.
La regla práctica: si el trabajo cabe en una tarjeta, usa una tarjeta. Es más sencillo y no puede fallar nada entre tarjetas. Una sola H100 suele terminar antes y más barata que dos tarjetas de consumo. Coge varias cuando el modelo no quepa en ninguna tarjeta o cuando un entrenamiento con una tarjeta fuera a durar más de una jornada laboral. Las máquinas con 2, 4 y 8 tarjetas aparecen por separado en el catálogo, y en conceptos básicos del entrenamiento con varias GPU se explica la configuración; una máquina con varias tarjetas cuesta más o menos el número de tarjetas por el precio de una, así que 4 × H100 sale por unos 15,60 € la hora.
Herramientas: Unsloth, Axolotl, TRL
Unsloth es la forma más rápida de hacer QLoRA o LoRA en una tarjeta. Sus kernels propios recortan memoria y tiempo, trae versiones en 4 bits listas de los modelos populares y exporta el resultado como adaptador, como modelo fusionado en 16 bits para vLLM o como GGUF para Ollama. Su soporte para varias GPU es más reciente y más limitado que el de las otras dos.
pip install unsloth
Si pip sustituye por el camino el PyTorch de la imagen, comprueba que la nueva compilación coincide con la versión de CUDA que mostraba la máquina antes de lanzar; python -c "import torch; print(torch.cuda.is_available())" debería imprimir True.
from unsloth import FastLanguageModel
from trl import SFTTrainer, SFTConfig
from datasets import load_dataset
model, tokenizer = FastLanguageModel.from_pretrained(
"unsloth/Qwen3-8B", max_seq_length=2048, load_in_4bit=True)
model = FastLanguageModel.get_peft_model(model, r=16, lora_alpha=16,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
use_gradient_checkpointing="unsloth")
data = load_dataset("json", data_files="/workspace/data/train.jsonl", split="train")
trainer = SFTTrainer(model=model, processing_class=tokenizer, train_dataset=data,
args=SFTConfig(output_dir="/workspace/out", per_device_train_batch_size=2,
gradient_accumulation_steps=4, num_train_epochs=3, learning_rate=2e-4,
logging_steps=10, save_steps=200, bf16=True))
trainer.train()
model.save_pretrained("/workspace/out/adapter")
train.jsonl tiene un ejemplo por línea, cada uno una lista messages en formato de chat (system, user, assistant), que el entrenador formatea con la plantilla de chat del propio modelo.
Axolotl describe todo el entrenamiento en un archivo YAML: modelo, dataset, LoRA o completo, longitud de secuencia y cómo usar varias GPU. Eso hace que los entrenamientos sean repetibles y fáciles de comparar. Instálalo con pip como indica su documentación (los extras para flash-attention y DeepSpeed dependen de tu configuración); después, axolotl fetch examples descarga configuraciones listas para los modelos habituales y axolotl train your-config.yaml arranca el entrenamiento. Para un modelo que no cabe en una tarjeta, añade a la configuración una sección de DeepSpeed ZeRO-3 o de FSDP; ahí Axolotl es más fuerte que Unsloth.
TRL, de Hugging Face, es la librería que hay debajo de buena parte de lo anterior: entrenadores de fine-tuning supervisado, DPO y GRPO, y PEFT para LoRA. Elígela cuando quieras tu propio código de entrenamiento. Un script que funciona en una tarjeta se ejecuta en cuatro con accelerate launch --num_processes 4 train.py.
Tiempo y coste
Rangos para planificar con un mismo dataset: 10 000 ejemplos de unos 500 tokens, tres épocas, 15 millones de tokens de entrenamiento. El rendimiento sale de cálculos de cómputo y de informes públicos de la comunidad, no de benchmarks nuestros. El tiempo escala con los tokens: el doble de datos, el doble de horas.
| Trabajo | GPU | Tokens de entrenamiento/s (rango, valor usado) | Tiempo | Coste de GPU |
|---|---|---|---|---|
| QLoRA 8B, Unsloth | RTX 4090 | 1000–2500, 1500 | 2 h 50 min | 1,65 € |
| LoRA 8B, 16 bits | H100 | 5000–10 000, 7000 | 36 min | 2,34 € |
| QLoRA 32B | L40S 48 GB | 400–800, 600 | 7 h | 7,42 € |
| QLoRA 32B | H100 | 1200–2200, 1700 | 2 h 30 min | 9,75 € |
| QLoRA 70B | A100 80 GB | 180–350, 250 | 16 h 40 min | 24,38 € |
| QLoRA 70B | H100 | 500–900, 700 | 6 h | 23,40 € |
| Completo 8B, 100 millones de tokens | 4 × H100 | 15 000–30 000, 20 000 | 1 h 25 min | 21,84 € |
Hay dos patrones claros. Las tarjetas de centro de datos más rápidas suelen costar menos por entrenamiento terminado, porque las horas bajan más deprisa de lo que sube el precio: compara las dos filas de 70B. Y el ajuste fino completo de un modelo de 8B dura poco en tiempo de GPU; lo que lleva más tiempo es preparar los datos y la evaluación de alrededor.
Suma además la preparación: 5–10 minutos para instalar el entrenador, y la descarga del modelo, que se factura como tráfico más minutos. Para QLoRA, coge la versión en 4 bits cuando exista; en un modelo de 70B son unos 40 GB en lugar de 141 GB. El artículo sobre el coste por millón de tokens usa el mismo método para ejecutar modelos después de entrenarlos.
Cómo ejecutarlo en un servidor alquilado sin perder trabajo
- Prueba primero en pequeño. Entrena con el 1 % de los datos en los primeros 15 minutos, que vas a pagar de todos modos. Apunta los tokens por segundo que muestra el entrenador y la memoria en
nvidia-smi, y haz las cuentas antes de lanzar el entrenamiento completo. - Haz que siga sin ti. Lanza el entrenamiento dentro de
tmux(apt-get install -y tmux,tmux new -s train) o connohup python train.py > /workspace/train.log 2>&1 &. Así, cerrar el navegador o la sesión SSH no lo detiene. - Guarda checkpoints y sácalos de la máquina. Ajusta
save_stepspara que caiga un checkpoint cada 15–30 minutos en/workspace/out. El hardware falla de vez en cuando; si una máquina desaparece, la facturación se para desde ese momento, pero su disco se va con ella. Copia los checkpoints fuera sobre la marcha: un repositorio privado de Hugging Face,rsynca tu ordenador o tu propio bucket. El artículo sobre los archivos tras detener una GPU explica qué conserva la carpeta guardada. - Guarda el adaptador, no el modelo base. Un adaptador LoRA ocupa desde decenas hasta unos cientos de MB, así que en la carpeta guardada no cuesta casi nada a 0,03 € por GB al mes. El modelo base público se puede volver a descargar.
- Detén el servidor al terminar. La facturación se para en el minuto en que detienes el servidor. La protección por inactividad te envía un correo tras 2 horas sin SSH, Jupyter ni carga en la GPU, y una hora después guarda la carpeta y detiene el servidor, pero esas horas inactivas se facturan.
Para usar el resultado, sirve el modelo base con el adaptador en vLLM: vllm serve Qwen/Qwen3-8B --enable-lora --lora-modules support=/workspace/out/adapter, y llama al modelo con el nombre support a través de su API compatible con OpenAI. O fusiona el adaptador con el modelo base en Unsloth y exporta un GGUF para Ollama. La comparativa de runtimes te ayuda a elegir.