Guía de fine-tuning de LLM: LoRA, QLoRA, Unsloth y Axolotl
Traducción automática Este artículo se tradujo automáticamente a partir de la versión original en inglés.
La mayoría de los fallos de fine-tuning son fallos de decisión. Un equipo entrena antes de demostrar que prompting, retrieval o constrained decoding no pueden resolver el problema. Otro evalúa sobre la distribución de entrenamiento o descubre después del entrenamiento que el artefacto resulta difícil de servir.
Esta guía trata la adaptación como un experimento con una salida operativa. Empieza por el límite de decisión y después recorre un camino a través de los datos, LoRA o QLoRA, la evaluación específica de la tarea, la exportación y el serving.
Para una decisión rápida sobre la intervención, consulta Fine-Tuning vs RAG vs Prompting.
¿Deberías hacer fine-tuning?
Antes de gastar horas de GPU, decide si el fine-tuning es la herramienta adecuada para el problema que tienes delante.
Fine-tuning frente a RAG
El fine-tuning puede cambiar cómo utiliza el modelo el lenguaje del dominio, pero es un mecanismo deficiente para actualizar hechos que cambian o que deben citarse. Retrieval y fine-tuning resuelven partes distintas del problema y a menudo deben formar parte del mismo sistema.
| Característica | Fine-tuning | RAG (Retrieval-Augmented Generation) |
|---|---|---|
| Función principal | Modifica los pesos internos para enseñar habilidades, estilos o comportamientos | Proporciona contexto externo y actualizado durante la inferencia |
| Más adecuado para | • Estilos conversacionales específicos • Seguir instrucciones complejas • Razonamiento de dominio | • Datos que cambian rápidamente (noticias, cotizaciones) • Reducir alucinaciones (grounding) • Citar fuentes |
| Gestión del conocimiento | Cambia el comportamiento estadístico de los pesos; no garantiza el recuerdo exacto | Recupera registros o pasajes que pueden actualizarse y citarse |
| Frecuencia de actualización | Requiere reentrenamiento para actualizarlo | Se actualiza inmediatamente con documentos nuevos |
Fine-tuning frente a prompt engineering
Los LLMs modernos responden bien a prompts y ejemplos claros. Prueba esas opciones antes de invertir en fine-tuning.
| Aspecto | Fine-tuning | Prompt engineering |
|---|---|---|
| Coste de configuración | Alto (curación de datos, cómputo de GPU, iteración) | Bajo (refinamiento iterativo del prompt) |
| Flexibilidad | Requiere otro ciclo de entrenamiento y publicación | Cambia con el prompt |
| Formato/estilo | Puede hacer más probable un comportamiento repetido | A menudo basta para el estilo y formatos sencillos |
| Latencia | Puede acortar instrucciones repetidas | Depende de la longitud del prompt y de la caché del proveedor |
| Más adecuado para | Comportamientos complejos, distillation, coste a escala | Iteración rápida, requisitos cambiantes |
[!TIP] Prueba prompting primero Empieza con un prompt y ejemplos representativos. Si solo falla la sintaxis de salida, añade constrained decoding antes de cambiar los pesos.
Fine-tuning frente a constrained decoding
Bibliotecas como xgrammar y outlines restringen la generación a un JSON Schema, una expresión regular o una gramática. Según la restricción y el backend, compilan un autómata o una gramática y enmascaran los tokens siguientes no válidos. No se requiere actualizar los pesos.
Esto garantiza que la salida pertenezca al lenguaje compatible. La garantía no dice nada sobre si los valores son verdaderos, completos o semánticamente adecuados. Un function call sintácticamente válido aún puede contener el ID de cliente equivocado.
| Aspecto | Constrained decoding | Fine-tuning |
|---|---|---|
| Configuración | Inmediata: definir el esquema y desplegar | Requiere curación de datos, cómputo de GPU e iteración |
| Garantía | Sintaxis válida para la restricción compatible | Comportamiento aprendido; el cumplimiento del esquema puede variar |
| Flexibilidad | Cambiar el esquema en cualquier momento sin reentrenar | Queda fijado tras el entrenamiento |
| Latencia | Ligera sobrecarga (el modelo puede «luchar» contra el esquema) | Menor (el modelo produce el formato de forma natural) |
| Más adecuado para | JSON, opciones, gramáticas y sintaxis de tool calls | Comportamientos de tarea repetidos que le faltan al modelo base |
Un orden práctico:
- Empieza con prompting y ejemplos few-shot para el formato básico.
- Añade constrained decoding (
xgrammarooutlines) cuando la sintaxis sea inconsistente. - Haz fine-tuning solo cuando necesites cambios de comportamiento que un esquema no pueda imponer.
Referencia rápida: relacionar problemas y soluciones
| Desafío | Primer mecanismo que probar | ¿Por qué? |
|---|---|---|
| Falta de conocimiento | RAG | Los modelos alucinan hechos. Retrieval proporciona contexto fundamentado y actualizado |
| Formato o tono incorrectos | Prompt engineering | Los modelos modernos siguen bien las instrucciones de estilo mediante ejemplos few-shot |
| Sintaxis de salida no válida | Constrained decoding | Impone un esquema o una gramática compatibles durante la generación |
| Fallos repetidos en una tarea | Fine-tuning (SFT) | Aprende de ejemplos de entrada/salida seleccionados |
| Desajuste en preferencias por pares | Preference optimization | Usa ejemplos chosen/rejected una vez medido el comportamiento de la tarea |
| Latencia o coste a escala | Distillation (SFT) | Entrena un modelo student más pequeño con las salidas de un teacher más grande |
| Reducir el tamaño del modelo | Quantization | Sin entrenamiento: comprime los pesos (FP16→INT4) para acelerar la inferencia |
Haz que el caso de negocio sea medible
El fine-tuning puede reducir los tokens recurrentes de los prompts o permitir que un modelo más pequeño alcance el objetivo, pero ninguno de esos ahorros es automático. Calcula el punto de equilibrio con tu tráfico y tus precios:
[ \text{solicitudes de equilibrio} = \frac{\text{coste de entrenamiento + evaluación + despliegue}} {\text{coste por solicitud de la baseline} - \text{coste por solicitud del modelo ajustado}} ]
Si el denominador es pequeño, negativo o se basa en una suposición de calidad no demostrada, el proyecto todavía no tiene justificación económica.
[!TIP] La configuración híbrida Una arquitectura habitual combina un modelo más pequeño adaptado a la tarea con retrieval para los hechos cambiantes. Trata el modelo grande con prompting como baseline y conserva el modelo pequeño solo si alcanza los mismos umbrales de calidad y seguridad específicos de la tarea.
Tipos de fine-tuning
El fine-tuning puede adoptar tres formas principales. Se diferencian por el tipo de datos que necesitan y por lo que enseñan al modelo.
1. Continued pre-training (self-supervised)
Entrenas el modelo base con más texto sin procesar, utilizando el token siguiente de cada secuencia como objetivo de entrenamiento. Es aprendizaje self-supervised: el texto proporciona sus propios objetivos, igual que en la ejecución de pre-training original.
Cuándo usarlo:
- El dominio tiene vocabulario que el modelo base nunca ha visto (medicina, derecho, bases de código internas).
- Tienes grandes cantidades de texto de dominio, pero no pares etiquetados de (entrada, salida).
- El modelo base se maneja mal con la terminología específica del dominio.
Ejemplo: entrenar con millones de notas clínicas para que el modelo aprenda abreviaturas médicas, nombres de fármacos y flujos de trabajo clínicos.
2. Supervised fine-tuning (SFT)
SFT entrena con pares etiquetados de (entrada, salida). Muestras al modelo la salida exacta que quieres para cada entrada.
Cuándo usarlo:
- Tienes una tarea específica con un formato limpio de entrada/salida.
- Tienes datos etiquetados de calidad, aunque sean pocos.
- Necesitas un comportamiento predecible con una forma de entrada conocida.
Ejemplo: entrenar con pares de (descripción de consulta SQL, código SQL) para text-to-SQL.
{
"input": "Get all users who signed up last month",
"output": "SELECT * FROM users WHERE signup_date >= DATE_SUB(NOW(), INTERVAL 1 MONTH)"
}
3. Instruction tuning
Instruction tuning es un caso especial de SFT diseñado para que los modelos sigan una amplia variedad de instrucciones en lenguaje natural. Los datos de entrenamiento son pares de (instrucción, respuesta) de muchas tareas diferentes.
Cuándo usarlo:
- Quieres un asistente de propósito general (como ChatGPT o Claude).
- El modelo debe gestionar solicitudes variadas y abiertas.
- Estás creando una interfaz de chat.
Ejemplo: entrenar con miles de instrucciones diversas como «Resume este artículo», «Escribe un poema sobre X» o «Explica Y con palabras sencillas».
Comparación
| Aspecto | Continued pre-training | SFT | Instruction tuning |
|---|---|---|---|
| Datos | Texto sin procesar | Pares de (entrada, salida) | Pares de (instrucción, respuesta) |
| Etiquetas | Ninguna (no supervisado) | Específicas de la tarea | Tareas diversas |
| Objetivo | Conocimiento del dominio | Comportamiento de una tarea específica | Seguir cualquier instrucción |
| Volumen de datos | Normalmente, el corpus más grande | Determinado por la cobertura de la tarea y la diversidad de errores | Normalmente más amplio que el SFT específico de una tarea |
[!NOTE] Lo que se hace realmente SFT e instruction tuning utilizan el mismo objetivo de next-token; la diferencia está en la amplitud y la construcción del dataset. Continued pre-training es un experimento separado y debe ir seguido de pruebas tanto de las mejoras en el dominio como de la regresión de las capacidades generales.
El pipeline de fine-tuning en 7 etapas
El fine-tuning es un pipeline, no un único comando. Cada etapa tiene sus propios modos de fallo, y saltarse una suele manifestarse más adelante como un modelo deficiente.
Cada etapa se apoya en la anterior:
- Preparación de datos — Define la unidad de evaluación, divide los datos y después límpialos y dales formato
- Selección del modelo — Elige el modelo base adecuado y carga los pesos
- Configuración del entrenamiento — Configura el hardware, los hiperparámetros y la estrategia de optimización
- Fine-tuning — Ejecuta entrenamiento SFT, DPO u ORPO
- Evaluación — Mide el rendimiento con benchmarks y valida la calidad
- Despliegue — Exporta y sirve el modelo
- Monitorización — Haz seguimiento del rendimiento, mantén el sistema e itera
[!WARNING] Los datos son los cimientos El entrenamiento reproduce los defectos sistemáticos de los ejemplos. Inspecciona las etiquetas, las fugas de datos, la cobertura y el cumplimiento de políticas antes de dedicar tiempo a explorar optimizadores.
Etapa 1: Preparación de datos
Muchos proyectos de fine-tuning fallan aquí, no durante el entrenamiento. La preparación de datos moderna es mucho más que ejecutar una regex sobre CSVs.
El pipeline de datos en 5 etapas
Herramientas como DataTrove y Distilabel pueden ayudar a escala. Deja que la taxonomía de fallos y el contrato de datos guíen el diseño del pipeline; la elección de la herramienta viene después.
1. Ingesta y filtrado
- Acción: elimina rechazos («I cannot answer that»), UTF-8 corrupto e idiomas que no sean el objetivo.
- Herramientas: Trafilatura para la extracción y los modelos de identificación de idioma de fastText para identificar el idioma; los modelos distribuidos
lid.176reconocen 176 idiomas.
2. Política de datos sensibles
- Acción: decide qué puede aprender el modelo y, según corresponda, redacta, tokeniza o excluye los campos personales y confidenciales.
- Herramientas: Microsoft Presidio o scrubadub.
- Motivo: un detector es solo un control; los requisitos de procedencia, consentimiento, conservación, acceso y eliminación siguen siendo aplicables.
3. Deduplicación (MinHash LSH)
- Acción: elimina los casi duplicados para evitar que el modelo los memorice.
- Herramientas: DataTrove gestiona bien el procesamiento a escala de terabytes.
4. Aumento sintético, si es necesario
- Acción: utiliza un modelo teacher más potente (GPT-4o, DeepSeek-V3) para reescribir los datos sin procesar como pares limpios de instrucción-respuesta.
- Herramientas: Distilabel.
- Validación: toma una muestra de las salidas del teacher, compruébalas con la misma rúbrica que las etiquetas humanas y mantén separadas las particiones sintéticas y escritas por personas durante la evaluación.
5. Formato
- Acción: convierte los datos a un formato estándar (Alpaca o ShareGPT).
Ejemplos de formatos de datos
Formato Alpaca (seguimiento de instrucciones):
{
"instruction": "Summarize the following text.",
"input": "The text to be summarized...",
"output": "This is the summary."
}
Formato ShareGPT/ChatML (conversacional):
{
"conversations": [
{ "from": "user", "value": "Hello, who are you?" },
{ "from": "assistant", "value": "I am a helpful AI assistant." }
]
}
Lo que importa realmente
- Cobertura antes que volumen. Añade ejemplos que representen modos de fallo distintos, no repeticiones del caso mayoritario y sencillo.
- Limpieza. Elimina texto irrelevante, normaliza los espacios y mantén el formato coherente.
- Equilibrio. Conserva los casos raros importantes e informa del rendimiento por partición.
- Separación. Divide por fuente, usuario, documento o fecha cuando dividir filas aleatoriamente pueda filtrar casi duplicados.
- Procedencia. Registra el origen, la licencia o permiso, el historial de transformaciones y la vía de eliminación para cada versión del dataset.
Etapa 2: Selección del modelo y hardware
Elegir el modelo base y entender el mínimo de GPU determinan lo que realmente puedes entrenar.
Empieza por el modelo base más pequeño que ya supere las comprobaciones no negociables de la baseline. Confirma:
- los términos de licencia y redistribución para el producto previsto;
- el comportamiento en idioma, dominio, tool use y seguridad antes de la adaptación;
- la compatibilidad del tokenizer y la chat template con el dataset;
- el contexto máximo y el comportamiento de truncado que necesitan los ejemplos reales;
- la compatibilidad tanto con el framework de entrenamiento como con el motor de serving objetivo.
El fine-tuning es una etapa de adaptación, no una reparación para un modelo base inadecuado. Si el modelo falla en capacidades que el dataset no cubre, elige otro modelo base antes de ejecutar más epochs.
Dimensiona la ejecución, no la categoría comercial
No existe una tabla estable de «tamaño del modelo → GPU». La memoria máxima cambia con la precisión de los pesos, el optimizador, el número de parámetros entrenables, la longitud de secuencia, el micro-batch, activation checkpointing, la implementación de attention y la sobrecarga del framework. Empieza con una estimación de memoria y después ejecuta una prueba corta con la longitud máxima sobre el stack exacto.
| Componente de memoria | Fine-tuning completo | LoRA | QLoRA |
|---|---|---|---|
| Pesos base | Precisión de entrenamiento | Congelados, normalmente BF16/FP16 | Congelados, normalmente NF4 de 4 bits |
| Gradientes | Todos los pesos entrenables | Pesos del adapter | Pesos del adapter |
| Estados del optimizador | Todos los pesos entrenables | Pesos del adapter | Pesos del adapter |
| Activaciones | Depende del batch y de la longitud de secuencia en todos los métodos | Misma dependencia | Misma dependencia |
El artículo original de QLoRA consiguió ajustar un modelo LLaMA de 65B en una única GPU de 48 GB con su configuración específica. Es un límite orientativo, no una promesa de que cualquier arquitectura actual de 70B, longitud de contexto, kernel o trainer vaya a caber en el mismo dispositivo.
Cálculo de memoria
Para un modelo con parámetros, solo los pesos requieren aproximadamente bytes en BF16/FP16 o bytes a cuatro bits, antes de contar los metadatos de quantization y los buffers del runtime. El entrenamiento completo al estilo Adam añade gradientes, estados del optimizador y, a menudo, pesos maestros de mayor precisión. LoRA evita la mayor parte de la memoria de los estados entrenables; QLoRA además reduce la huella de los pesos base congelados. Las activaciones aún pueden dominar con longitudes de secuencia grandes.
Usa este flujo de trabajo:
- Elige la secuencia más larga y el micro-batch que debas admitir.
- Estima los pesos y el estado entrenable, dejando margen para activaciones y kernels.
- Ejecuta un paso de forward/backward con la longitud máxima.
- Registra la memoria máxima allocated y reserved.
- Solo entonces escala el tamaño del batch, el rank, la longitud de secuencia o el número de GPUs.
Etapa 3: Métodos de entrenamiento (PEFT y LoRA)
Fine-tuning completo frente a PEFT
El fine-tuning completo (FFT) actualiza todos los pesos, por lo que los gradientes y el estado del optimizador escalan con el modelo entero. La memoria máxima no puede inferirse solo a partir del número de parámetros, pero es muy superior a la necesaria para cargar los pesos durante la inferencia.
El fine-tuning eficiente en parámetros (PEFT) entrena únicamente un subconjunto pequeño de parámetros y congela el resto. Las matemáticas resultan mucho más manejables.
LoRA: el punto de partida
LoRA (Low-Rank Adaptation) congela una matriz preentrenada y representa su actualización aprendida mediante dos matrices más pequeñas. El artículo original lo motiva con la hipótesis de que las actualizaciones útiles de adaptación tienen un rank intrínseco bajo.
Para una matriz congelada , LoRA aprende:
La capa adaptada es:
El adapter tiene parámetros entrenables, frente a para esa matriz. Para una matriz cuadrada de 4.096 elementos de ancho y rank 16, supone una reducción de 128× para la matriz, no de 10.000× para un modelo arbitrario. La cifra de 10.000× del artículo de LoRA correspondía a una configuración específica de GPT-3 175B que adaptaba matrices seleccionadas.
Comparación de métodos PEFT
| Método | Qué cambia | Elígelo cuando |
|---|---|---|
| LoRA | Modelo base congelado más actualizaciones entrenables de bajo rank | El modelo base cabe con margen y quieres artefactos pequeños específicos de la tarea |
| QLoRA | LoRA con el modelo base congelado almacenado en formato de 4 bits | La memoria de los pesos base es el factor limitante |
| DoRA | Separa la magnitud de los pesos de una dirección actualizada por LoRA | Una baseline medida con LoRA deja una brecha de calidad que justifica una complejidad adicional |
| Fine-tuning completo | Todos los pesos del modelo | PEFT no alcanza el objetivo y la mejora de calidad justifica el entrenamiento distribuido y los checkpoints completos |
Cuándo elegir cada uno
- LoRA: empieza por aquí. Es rápido, eficiente en memoria y cuenta con buen soporte.
- QLoRA: cuando el mismo experimento con LoRA no quepa por culpa de los pesos base congelados.
- DoRA: después de que una comparación apples-to-apples con LoRA muestre una mejora útil.
- Fine-tuning completo: solo después de demostrar mediante evaluación que PEFT es un cuello de botella, no asumirlo.
DoRA: LoRA con descomposición de pesos
DoRA (Weight-Decomposed Low-Rank Adaptation) separa la magnitud de cada vector de pesos de su dirección. El artículo de DoRA aplica una actualización LoRA al componente direccional y aprende la magnitud por separado.
Cómo funciona:
En lugar de tratar los pesos como una única entidad, DoRA divide los pesos preentrenados en dos componentes:
- Magnitud — un valor entrenable por vector de pesos.
- Dirección — un vector normalizado actualizado mediante matrices de bajo rank.
En notación compacta por columnas:
donde:
m= magnitud (entrenable)- = matriz direccional congelada
- = actualización direccional aprendida de bajo rank
- = normalización por columnas
Qué obtienes a cambio de esa estructura adicional:
- Más grados de libertad que con LoRA estándar, porque la magnitud puede cambiar de forma independiente.
- Mejores resultados que LoRA en varias configuraciones descritas por el artículo que lo propone.
- Parámetros y cómputo adicionales, por lo que la mejora debe verificarse en tu tarea y en tu ruta de serving.
Fusión de adapters para aprendizaje multitarea
Los adapters separados permiten que un único modelo base congelado dé soporte a varias tareas. Puedes enrutar las solicitudes a un adapter, servir varios adapters desde un mismo motor cuando sea compatible o crear un candidato fusionado offline. La fusión puede introducir interferencias, así que evalúa el artefacto fusionado en lugar de asumir que los adapters de origen se componen sin problemas.
Métodos habituales de fusión:
- Concatenación — combina los parámetros de los adapters y aumenta el rank efectivo. Es rápida y sencilla.
- Combinación lineal — suma ponderada de adapters. Proporciona controles.
- SVD — descomposición matricial para fusionar. Es más flexible, pero más lenta.
Ejemplo: un adapter para summarization y otro para traducción, fusionados en un único modelo multitarea.
Etapa 4: Fine-tuning y preference alignment
SFT aprende demostraciones. Preference optimization aprende, en cambio, a partir de comparaciones como «la respuesta elegida A es mejor que la respuesta rechazada B». Úsalo solo cuando una preferencia por pares sea la etiqueta adecuada para el error; la corrección factual y el cumplimiento de políticas suelen requerir evaluadores más sólidos que una preferencia global.
RLHF basado en PPO
La receta original era un pipeline de tres etapas:
- SFT — aprender la tarea.
- Reward model — entrenarlo con preferencias humanas (chosen frente a rejected).
- PPO (Proximal Policy Optimization) — reinforcement learning para optimizar la policy.
El coste operativo procede de sus distintos componentes:
- Es complicado de implementar y mantener.
- Es caro: se entrenan varios modelos.
- El muestreo on-policy y la optimización de la recompensa requieren controles cuidadosos de estabilidad y de reward hacking.
DPO
DPO (Direct Preference Optimization) elimina el reward model explícito y el RL loop. El artículo de DPO deriva un objetivo reparametrizado para maximizar la recompensa con una restricción de divergencia KL, de modo que la optimización puede realizarse a partir de pares de preferencias en lugar de reinforcement learning:
{
"prompt": "Explain quantum computing",
"chosen": "Quantum computing uses qubits...", # Preferred response
"rejected": "Well, it's complicated..." # Non-preferred response
}
Qué cambia operativamente:
- Ruta de código más sencilla (sin reward model separado ni RL loop).
- Objetivo offline sobre pares de preferencias, en lugar de reinforcement learning on-policy.
- Una policy de referencia o probabilidades log de referencia equivalentes en la formulación estándar.
DPO es más fácil de prototipar que un pipeline PPO completo, pero no es una mejora automática de calidad. Los resultados dependen de la policy inicial, la calidad de los pares, la configuración de la loss, los efectos de longitud y el protocolo de evaluación. Compáralo con un checkpoint SFT en los mismos conjuntos de preferencias y tareas reservados para evaluación.
ORPO
ORPO (Odds-Ratio Preference Optimization) combina la loss de negative log-likelihood de SFT con una penalización de odds ratio sobre las respuestas rechazadas. Elimina el modelo de referencia separado y puede combinar el aprendizaje de la tarea y la preference optimization en una única ejecución.
Cómo funciona: ORPO utiliza una loss combinada que hace dos cosas a la vez:
- Maximiza la likelihood de la respuesta elegida (aprende la tarea).
- Penaliza la respuesta rechazada con un término de odds ratio (aprende las preferencias).
Hiperparámetros que conviene conocer:
from trl import ORPOConfig
config = ORPOConfig(
learning_rate=8e-6, # Very low, as recommended by the ORPO paper
beta=0.1, # Controls strength of preference penalty
# ... other params
)
- Learning rate: el artículo utilizó valores bajos en sus experimentos; ajústalo a tu modelo, batch y datos en lugar de copiar un valor como regla.
- Beta: controla el término de preferencias con respecto al término SFT.
El compromiso:
- Una etapa de entrenamiento en lugar de dos.
- Sin reward model.
- Sin forward pass del modelo de referencia.
- Una ejecución acoplada: si el aprendizaje de la tarea o el comportamiento de preferencias empeoran, no hay un checkpoint SFT intermedio de ese mismo pipeline que inspeccionar.
Elige en función del diseño de datos y evaluación:
- Usa DPO cuando ya tengas un checkpoint SFT satisfactorio y quieras un experimento offline de preferencias más sencillo.
- Prueba ORPO cuando un objetivo sin modelo de referencia y de una sola etapa encaje con tus datos y restricciones operativas.
- Usa RLHF basado en PPO cuando el muestreo online frente a una recompensa aprendida explícita forme parte del requisito y puedas monitorizar la explotación de la recompensa.
Ninguno es una opción predeterminada para todas las tareas. Conserva una baseline solo con SFT e informa tanto de las métricas de tarea como de las métricas de preferencias.
Frameworks de fine-tuning
Los frameworks se solapan y cambian rápidamente. Elige según la ruta de ejecución que debas admitir, fija las versiones y mantén la configuración de entrenamiento suficientemente portable para reproducirla fuera de un notebook.
Unsloth: velocidad y eficiencia de memoria
Unsloth se integra con Hugging Face trl y transformers y proporciona kernels optimizados, checkpointing y rutas de fine-tuning cuantizado para los modelos compatibles.
- Kernels de GPU Triton personalizados para attention, RoPE y cross-entropy que evitan la sobrecarga de PyTorch.
- Backprop eficiente en memoria que recomputa las activaciones durante el backward pass en lugar de mantenerlas en memoria.
- Operaciones fused que agrupan varios pasos (layer norm + linear y similares) en una sola llamada a la GPU.
- Quantization de 4 bits integrada directamente en la ruta QLoRA con dequantization optimizada.
[!IMPORTANT] El orden de importación importa Sigue el orden de importación del ejemplo de Unsloth correspondiente a la versión que fijes. Unsloth aplica parches durante la importación, por lo que importarlo antes de
trlytransformersevita perder optimizaciones o encontrar errores específicos de la versión.
# Correct order
from unsloth import FastLanguageModel # Must be first!
from trl import SFTTrainer
from transformers import TrainingArguments
# Avoid this order with Unsloth's patched path
from trl import SFTTrainer
from unsloth import FastLanguageModel
Más adecuado para: entrenamiento con una sola GPU, prototipado, notebooks de Colab y cualquiera que controle la factura de GPU.
Las cifras publicadas de velocidad y memoria varían según el modelo, la longitud de secuencia, el batch, la precisión y el hardware. Mide los tokens por segundo y la memoria máxima en tu propia ejecución en lugar de tratar una proporción destacada como una propiedad del framework.
Axolotl: entrenamiento basado en configuración
# config.yaml - no code required
base_model: meta-llama/Meta-Llama-3-8B
adapter: qlora
lora_r: 32
lora_alpha: 16
datasets:
- path: data/my_data.jsonl
type: alpaca
sample_packing: true
Ejecuta con: accelerate launch -m axolotl.cli.train config.yaml
Más adecuado para: ejecuciones declarativas y reproducibles, y opciones de launcher integradas para entrenamiento distribuido. La configuración se puede revisar, versionar y reutilizar en ejecuciones locales y distribuidas.
Comparación de frameworks
| Herramienta | Útil cuando | Verifica antes de comprometerte |
|---|---|---|
| Unsloth | Quieres una ruta optimizada para modelos compatibles con ejemplos concisos | Matriz de modelos, GPU, quantization y soporte distribuido |
| Axolotl | Quieres configuraciones declarativas y recetas distribuidas integradas | Esquema exacto de configuración y launcher de la release fijada |
| TRL | Quieres acceso directo a los trainers SFT y de preferencias de Hugging Face | Formato del dataset, chat template, enmascarado de la loss e integración con PEFT |
| Torchtune | Quieres recetas y componentes nativos de PyTorch | Cobertura de recetas para el modelo y compatibilidad de exportación |
Demo práctica: fine-tuning con Unsloth
Este es un extracto representativo de entrenamiento de mi repositorio unsloth-finetune-demo. La demo hace fine-tuning de Nemotron-Nano para function calling. Antes de este extracto, el src/unsloth_demo/data.py de la demo carga y da formato al dataset; después, su ruta de entrenamiento crea los objetos versionados train_dataset y eval_dataset.
Inicio rápido
# Clone and setup
git clone https://github.com/slavadubrov/unsloth-finetune-demo.git
cd unsloth-finetune-demo
# Install with uv (recommended)
uv sync
# Run fine-tuning (quick test)
uv run finetune --max-samples 1000
Configuración
Las partes interesantes están en config.py:
# Model & Dataset
MODEL_NAME = "nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1" # 4B params, 128K context
DATASET_NAME = "glaiveai/glaive-function-calling-v2" # 113K examples
# LoRA Configuration
LORA_R = 16 # Adapter capacity; tune against held-out results
LORA_ALPHA = 32 # Update scaling; alpha/r is the classic LoRA scale
MAX_SEQ_LENGTH = 4096
# Candidate modules for this Llama-family model
LORA_TARGET_MODULES = [
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
]
[!NOTE] La proporción alpha-rank
alpha/rescala la actualización LoRA clásica.alpha = 2res una heurística inicial habitual en cierta documentación de herramientas, no una garantía de estabilidad. Explora rank, alpha, learning rate y módulos objetivo solo después de fijar los datos y la baseline.
Código de entrenamiento principal
from unsloth import FastLanguageModel
from trl import SFTConfig, SFTTrainer
# Load model with 4-bit quantization
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1",
max_seq_length=4096,
load_in_4bit=True,
)
# Add LoRA adapters
model = FastLanguageModel.get_peft_model(
model,
r=16,
lora_alpha=32,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
use_gradient_checkpointing="unsloth", # Lower activation memory; extra compute
)
# The preceding data step must create these versioned dataset objects.
# Each row has the chat messages and tool schemas expected by current TRL.
# Train with the current TRL configuration surface.
trainer = SFTTrainer(
model=model,
processing_class=tokenizer,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
args=SFTConfig(
output_dir="outputs/nemotron-function-calling",
max_length=4096,
packing=True,
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
learning_rate=2e-4,
num_train_epochs=3,
bf16=True,
),
)
trainer.train()
Fine-tuning con Axolotl
[!NOTE] Demo en preparación Estoy trabajando en una demo práctica de Axolotl. Mientras tanto, la guía de paralelismo n-D de Accelerate de Hugging Face es una buena referencia para las estrategias de entrenamiento multi-GPU.
Para configuraciones config-first y distribuidas, Axolotl hace que el flujo de trabajo sea reproducible:
# axolotl_config.yaml
base_model: meta-llama/Meta-Llama-3-8B
model_type: LlamaForCausalLM
# QLoRA configuration
load_in_4bit: true
adapter: qlora
lora_r: 32
lora_alpha: 16
lora_dropout: 0.05
lora_target_modules:
- q_proj
- k_proj
- v_proj
- o_proj
- gate_proj
- up_proj
- down_proj
# Dataset
datasets:
- path: data/training_data.jsonl
type: alpaca
# Training settings
sequence_len: 4096
sample_packing: true # Benchmark with your length distribution
micro_batch_size: 2
gradient_accumulation_steps: 4
learning_rate: 0.0002
num_epochs: 3
# Current Axolotl key; verify support on the pinned release
bf16: true
attn_implementation: flash_attention_2
Ejecuta el entrenamiento:
axolotl train axolotl_config.yaml
Etapa 5: Evaluación
Congela el contrato de evaluación antes de la primera ejecución. Como mínimo, compara el checkpoint ajustado con el modelo base exacto sin ajustar, usando el mismo prompt, la misma configuración de decoding y el mismo entorno de herramientas. Informa de la calidad agregada solo después de comprobar las particiones de fallos que el proyecto pretendía mejorar.
Haz seguimiento de cuatro grupos:
- Tarea objetivo: exact match, éxito de ejecución, rúbrica humana u otro resultado vinculado al caso de uso.
- Regresión: capacidades generales y particiones de tareas previamente compatibles que la adaptación podría dañar.
- Seguridad y políticas: rechazos, filtración de datos, prompt injection o restricciones específicas del dominio.
- Operaciones: latencia, throughput, memoria, tamaño del artefacto y coste en la configuración de serving prevista.
Benchmarks automatizados
Usa lm-evaluation-harness para tareas estandarizadas relevantes, no como sustituto de la evaluación del producto:
lm_eval --model hf \
--model_args pretrained=./outputs/merged-model \
--tasks hellaswag,arc_easy,mmlu \
--batch_size 8
LLM-as-judge
Para la calidad subjetiva, un modelo más grande puede ayudar con la puntuación, pero calibra sus resultados con ejemplos revisados por personas y oculta la identidad de los candidatos:
judge_prompt = """
Rate this response from 1-5 on:
- Relevance
- Accuracy
- Formatting
Response: {model_output}
Expected: {ground_truth}
"""
Evaluación específica del dominio
Reserva ejemplos reales por fuente, usuario, documento o fecha para impedir que los casi duplicados se filtren entre las particiones. En function calling, valida la trayectoria completa: selección de herramientas, argumentos, resultado de ejecución, recuperación y respuesta final. Informa de intervalos de confianza o de recuentos pareados de victorias/derrotas cuando la muestra sea pequeña e inspecciona cada regresión en una partición crítica.
Etapa 6: Despliegue y formatos de salida
Elige el artefacto según el motor de serving y el plan de rollback, no solo por el tamaño de los archivos:
1. Adapter LoRA
uv run finetune # Saves ~100-500MB adapter
- Tamaño: proporcional a los módulos objetivo, el rank, las capas y el dtype; a menudo mucho menor que el modelo base.
- Más adecuado para: desarrollo, adapters de tarea versionados y motores compatibles directamente con LoRA.
- Ventaja adicional: puedes intercambiar adapters sin volver a descargar el modelo base.
2. Modelo fusionado
uv run finetune --merge # Creates a standalone full model
- Tamaño: aproximadamente el del checkpoint base completo con la precisión de salida elegida.
- Más adecuado para: motores o rutas de distribución que no admiten el adapter por separado.
- Compromiso: artefacto más grande y rollout más lento; carga más sencilla como modelo único.
3. Formato GGUF
uv run finetune --gguf q4_k_m # Creates ~2-4GB quantized model
- Tamaño: depende del modelo; aproximadamente pesos de cuatro bits más metadatos para las variantes Q4.
- Más adecuado para: inferencia en CPU, Ollama, llama.cpp y despliegues en edge.
- Opciones:
q4_k_m(más pequeño),q5_k_m(mayor fidelidad de los pesos),q8_0(más grande y con mayor fidelidad). Mide el impacto en la tarea después de la conversión.
Etapa 7: Serving y monitorización
Con vLLM
# Serve the base and expose a PEFT adapter as a model name. This parser and
# template pair is for a Llama 3.1-compatible function-calling adapter.
vllm serve nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1 \
--enable-lora \
--lora-modules function-calling=./outputs/adapter \
--enable-auto-tool-choice \
--tool-call-parser llama3_json \
--chat-template examples/tool_chat_template_llama3.1_json.jinja \
--host 0.0.0.0 \
--port 8000 \
--max-model-len 4096
Consulta mediante la API compatible con OpenAI:
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")
response = client.chat.completions.create(
model="function-calling",
messages=[{"role": "user", "content": "Book a flight to Tokyo"}],
tools=[
{
"type": "function",
"function": {
"name": "book_flight",
"description": "Book a flight to a city.",
"strict": True,
"parameters": {
"type": "object",
"properties": {
"destination": {"type": "string"},
},
"required": ["destination"],
"additionalProperties": False,
},
},
}
],
tool_choice="auto",
)
La guía de tool calling de vLLM requiere auto tool choice y un parser compatible con el modelo; utiliza la chat template compatible del modelo cuando la configuración de su tokenizer no proporcione una. Con tool_choice="auto", los argumentos restringidos también requieren strict: true en al menos una función (y tener activada la configuración strict-tool-calling de vLLM, que es la predeterminada); utiliza un esquema parameters compatible con strict. Sin esa activación, vLLM extrae las llamadas del texto sin procesar, por lo que los argumentos pueden estar mal formados o incumplir el esquema.
Con Ollama (local)
# Create Modelfile
echo 'FROM ./outputs/unsloth-nemotron-function-calling-gguf/model-q4_k_m.gguf' > Modelfile
# Import to Ollama
ollama create my-function-model -f Modelfile
# Run
ollama run my-function-model
Con llama.cpp (CPU)
./llama-cli -m ./outputs/model-q4_k_m.gguf \
-p "What's the weather in Tokyo?" \
--ctx-size 4096
Monitoriza el modelo publicado
El ciclo de vida no termina cuando la loss de entrenamiento es buena. Registra la revisión del modelo base, el tokenizer y la chat template, el hash del adapter, la versión del dataset, la configuración de entrenamiento y el informe de evaluación como una única unidad de release. En producción, monitoriza el éxito de la tarea, las salidas no válidas, los fallos de políticas, la latencia y el drift de entrada usando las mismas particiones que offline. Mantén cargable el artefacto anterior y define un umbral de rollback antes del lanzamiento.
Conclusiones principales
- Haz fine-tuning solo después de que una baseline sin ajustar y una taxonomía de fallos demuestren que la adaptación de pesos aborda el problema.
- Retrieval gestiona la evidencia cambiante; constrained decoding gestiona la sintaxis; ninguno de los dos queda sustituido por SFT.
- LoRA reduce el estado entrenable. QLoRA además comprime los pesos base congelados. No atribuyas las cifras de memoria de QLoRA a LoRA.
- La cobertura de datos, la integridad de las particiones, la procedencia y el enmascarado de la loss importan más que copiar una configuración de optimizador de moda.
- DPO, ORPO y RLHF basado en PPO son diseños experimentales distintos, no una escala de calidad con una opción predeterminada universal.
- Evalúa el comportamiento objetivo, las regresiones, la seguridad y las operaciones frente al mismo modelo base.
- Elige la salida en forma de adapter, modelo fusionado o GGUF según los requisitos de serving y rollback antes de entrenar.
Referencias
Artículos y trabajos de investigación
- LoRA: Low-Rank Adaptation of Large Language Models
- QLoRA: Efficient Finetuning of Quantized LLMs
- DoRA: Weight-Decomposed Low-Rank Adaptation
- DPO: Direct Preference Optimization
- ORPO: Odds Ratio Preference Optimization
- PPO: Proximal Policy Optimization Algorithms — OpenAI, 2017
Herramientas de procesamiento de datos
- DataTrove — procesamiento de datos a escala de Hugging Face
- Distilabel — generación de datos sintéticos (Argilla)
- Trafilatura — extracción y crawling de texto web
- Identificación de idioma de fastText — modelos distribuidos
lid.176para 176 idiomas - Microsoft Presidio — detección y anonimización de PII
- scrubadub — biblioteca de Python para eliminar PII
Constrained decoding
Frameworks de entrenamiento
- Unsloth — framework optimizado de fine-tuning
- Axolotl — entrenamiento basado en configuración y launchers distribuidos
- TRL — biblioteca de Hugging Face para SFT y preference training
- Torchtune — biblioteca de fine-tuning nativa de PyTorch
Inferencia y despliegue
- Adapters LoRA de vLLM — sirve uno o varios adapters con el modelo base
- Tool calling de vLLM — adapta auto tool choice, parser, chat template y esquema de la solicitud al modelo
- Ollama — runner local de LLM para Mac/Windows/Linux
- llama.cpp — inferencia en CPU/GPU con formato GGUF
Evaluación
- lm-evaluation-harness — benchmarking estandarizado de LLMs de EleutherAI
Guías y recursos
- Repositorio de la demo — ejemplo práctico de fine-tuning
- LLM Fine-Tuning. Theoretical Intuition and Practical Implementation — notebook de investigación de NotebookLM
- Guía de paralelismo n-D de Accelerate — estrategias de entrenamiento multi-GPU de Hugging Face