Curso / Unsloth / Merge, exportación y despliegue
Unsloth · 3 de 3

Unsloth · Fine-tuning acelerado y Triton · 3

Merge, exportación y despliegue: de Unsloth a vLLM, GGUF y NVFP4

Terminado el entrenamiento en Unsloth, los pesos existen como un modelo base congelado y pequeños adaptadores adicionales. En producción no querés la penalización de evaluar dos ramas matriciales en cada token. Esta unidad desglosa la matemática de fusión lineal, la exportación a Safetensors para motores de alto rendimiento como vLLM, la cuantización a GGUF para entornos locales y el enlace hacia la cuantización microscópica NVFP4 en Blackwell.

Antes de leerUnsloth 2, SFT, CPT y DPO · HF cap. 3 §5, LoRA · HF cap. 12, despliegue y vLLM · NVFP4 en difusión

🎯 Al terminar vas a poder

  • Explicar con exactitud tensorial por qué el merge de adaptadores LoRA (Wfinal=Wbase+αrBA) exige des-cuantizar los pesos base a punto flotante de 16 bits.
  • Exportar modelos consolidados en formato Safetensors de 16 bits sin cabeceras inseguras ni cuellos de botella de deserialización.
  • Servir el modelo resultante en vLLM aprovechando PagedAttention, Continuous Batching y optimizaciones de memoria del KV Cache.
  • Convertir el modelo a binarios GGUF utilizando cuantización adaptativa k-quants (Q4_K_M, Q5_K_M, Q8_0) para inferencia local en CPU, Mac Silicon o Ollama.
  • Conectar el artefacto exportado de Unsloth con la calibración y empaque tensorial en formato NVFP4 de NVIDIA Blackwell.

0. Por qué fusionar adaptadores: latencia y overhead en producción

Durante el proceso de fine-tuning (ya sea con LoRA estándar o con QLoRA en 4 bits), la computación de cada capa lineal adaptada se divide en dos caminos paralelos:

h=xWbase⊤+αr((xA⊤)B⊤)

Cómo se lee. La activación oculta h suma la proyección del modelo base más el desvío de bajo rango generado por las matrices A y B.

En la etapa de desarrollo esto es sumamente práctico: los pesos de los adaptadores ocupan apenas entre 20 MB y 200 MB, lo que permite compartir versiones de prueba rápidamente. Sin embargo, en inferencia de producción este diseño es sumamente costoso:

  1. Llamadas redundantes a kernels (Kernel Launch Overhead): En lugar de una única multiplicación matricial por capa, la GPU debe lanzar tres kernels (Wbase, A y B) y un kernel de suma residual, triplicando los accesos a la memoria compartida.
  2. Incompatibilidad con optimizaciones de grafo: Compiladores y motores de alta concurrencia como vLLM o TensorRT-LLM fusionan capas enteras en un único bloque de ejecución. Si los pesos no están fusionados, estas optimizaciones quedan deshabilitadas o deben recurrir a implementaciones dinámicas (Multi-LoRA) que reducen el rendimiento de tokens por segundo.

1. La matemática del merge: des-cuantización NF4 a 16 bits y suma W + α/r BA

Gracias a la propiedad distributiva del producto de matrices, el cálculo puede unificarse previamente en tiempo de compilación:

Wfinal=Wbase+αr(BA)∈ℝdout×din

Una vez calculado Wfinal, durante la inferencia la operación vuelve a ser una simple multiplicación densa estándar: h=xWfinal⊤.

La trampa de la des-cuantización (QLoRA a 16 bits)

Si entrenaste con QLoRA en 4 bits (NormalFloat4), la matriz Wbase reside en memoria como índices enteros de 4 bits acompañados por factores de escala en bloque:

Wbase=s1·s2·LUTNF4(Wint4)

No es posible sumar directamente αrBA sobre los índices enteros de 4 bits, ya que la cuantización no lineal destruiría la información continua del adaptador.

Por ello, el algoritmo de merge en Unsloth ejecuta el siguiente procedimiento:

  1. Carga o des-cuantiza la matriz base a punto flotante (16 bits: bfloat16 o float16).
  2. Calcula el producto exterior de bajo rango ΔW=αr(BA) en 16 bits.
  3. Suma tensor a tensor: Wfinal=Wdequant+ΔW.
  4. Serializa el tensor resultante directamente en disco en formato Safetensors.

2. Exportación a Safetensors de 16 bits y despliegue en vLLM

El formato Safetensors (desarrollado por Hugging Face) es el estándar industrial para almacenar tensores de redes neuronales. A diferencia de los archivos .pt o .bin tradicionales de PyTorch:

  • Seguridad absoluta: No utiliza pickle de Python, eliminando por completo el riesgo de ejecución remota de código malicioso al descargar modelos.
  • Mapeo directo de memoria (Zero-Copy mmap): Los servidores pueden mapear los archivos en el espacio de direcciones virtuales de la memoria RAM del sistema sin instanciar buffers intermedios de Python, cargando un modelo de 8 mil millones de parámetros en menos de 2 segundos.

Código de exportación en Unsloth

Unsloth simplifica la consolidación y guardado a un único llamado optimizado que fusiona capa por capa sin consumir el doble de memoria RAM del sistema:

# Guardar modelo fusionado en 16 bits (bfloat16) en formato Safetensors
model.save_pretrained_merged(
    "modelo_finetune_16bit",
    tokenizer,
    save_method="merged_16bit", # Descuantiza base y suma adaptadores limpiamente
)

Despliegue en producción con vLLM

Una vez exportado el directorio con los Safetensors y el tokenizer, vLLM puede levantarse de forma inmediata como un servidor OpenAI-compatible:

# Levantar servidor vLLM de alto rendimiento
vllm serve ./modelo_finetune_16bit \
    --host 0.0.0.0 \
    --port 8000 \
    --dtype bfloat16 \
    --max-model-len 8192 \
    --gpu-memory-utilization 0.90 \
    --enable-chunked-prefill

En este modo, vLLM aplica PagedAttention dividiendo el KV Cache en bloques de memoria no contiguos (evitando fragmentación en GPU) y Continuous Batching, procesando solicitudes concurrentes con latencias predecibles.

3. Exportación a GGUF (k-quants) para Ollama y llama.cpp

Para aplicaciones locales, ejecución en laptops (como Mac con Apple Silicon) o dispositivos en el borde (edge devices), cargar 16 GB de pesos en punto flotante no es viable. El formato GGUF (desarrollado por Georgi Gerganov para llama.cpp) almacena metadatos y tensores cuantizados en un único archivo binario monolítico.

La familia de cuantizaciones modernas (k-quants)

Las cuantizaciones modernas no tratan a todas las capas por igual:

  • Q4_K_M (Recomendado general): Cuantiza los pesos a un promedio de 4.5 bits por parámetro. Las capas críticas para la coherencia semántica (los pesos de Query y Key en atención y la compuerta de feed-forward) se mantienen con bloques de mayor precisión (5 o 6 bits), mientras que capas menos sensibles se comprimen en 4 bits puros.
  • Q5_K_M: 5.5 bits por parámetro. Prácticamente indistinguible de FP16 en pruebas de perplejidad, ideal para modelos de 7B u 8B parámetros en equipos con 16 GB de memoria unificada.
  • Q8_0: Cuantización uniforme a 8 bits. Sirve como estándar de referencia sin pérdida perceptible de calidad.

Exportación directa a GGUF desde Unsloth

Unsloth incluye compilación cruzada directa hacia GGUF invocando internamente las herramientas de llama.cpp:

# Exportar a GGUF con cuantización Q4_K_M para Ollama / llama.cpp
model.save_pretrained_gguf(
    "modelo_finetune_gguf",
    tokenizer,
    quantization_method="q4_k_m"
)

El archivo generado modelo_finetune_gguf-unsloth.Q4_K_M.gguf puede cargarse en Ollama creando un archivo Modelfile:

FROM ./modelo_finetune_gguf-unsloth.Q4_K_M.gguf
TEMPLATE """{{ if .System }}<|start_header_id|>system<|end_header_id|>
{{ .System }}<|eot_id|>{{ end }}{{ if .Prompt }}<|start_header_id|>user<|end_header_id|>
{{ .Prompt }}<|eot_id|>{{ end }}<|start_header_id|>assistant<|end_header_id|>
{{ .Response }}<|eot_id|>"""

4. El puente hacia NVFP4 en arquitecturas NVIDIA Blackwell

En 2026, la arquitectura de silicio de centros de datos más avanzada es NVIDIA Blackwell (B100, B200, GB200), que introduce soporte nativo de hardware para NVFP4 (punto flotante microscópico de 4 bits en formato E2M1: 1 bit de signo, 2 de exponente, 1 de mantisa).

Ciclo de vida del modelo: de Unsloth al despliegue en vLLM, GGUF y NVFP4 Diagrama de flujo que muestra la fusión matemática de los adaptadores de Unsloth y su ramificación a Safetensors para vLLM, GGUF para llama.cpp y calibración FP4 para Blackwell. Unsloth LoRA Base NF4 (4b) + Adaptadores A, B (16b) Fusión Lineal en 16b W_base (dequant) + (α/r) · B · A Safetensors bfloat16 1. Cloud Inferencia: vLLM PagedAttention + Continuous Batching (bfloat16) 2. Edge / Local: GGUF (llama.cpp / Ollama) Cuantización k-quants Q4_K_M / Q5_K_M para CPU/Mac 3. NVIDIA Blackwell: NVFP4 Engine Calibración post-merge con bloques de escala de 16 elementos Duplica el throughput de FP8 con Tensor Cores de 5ta gen

Como se exploró en el módulo sobre NVFP4 en modelos de difusión y lenguaje, la cuantización en Blackwell opera con escalas microscópicas por bloques de 16 elementos.

El flujo de integración con Unsloth es directo:

  1. Se ejecuta el fine-tuning rápido con Unsloth utilizando kernels Triton en la GPU local o de desarrollo.
  2. Se exporta el modelo fusionado en formato bfloat16 Safetensors mediante save_pretrained_merged().
  3. El directorio Safetensors consolidado se alimenta a la suite de calibración de Blackwell (por ejemplo, TensorRT-Model-Optimizer). El optimizador recolecta activaciones en 16 bits, calcula los factores de escala óptimos para cada bloque de 16 floats y empaqueta la matriz final en NVFP4.
  4. El modelo cuantizado resultante rinde el doble de tokens por segundo que en FP8, con la ventaja de haber sido entrenado con la máxima velocidad de Unsloth.

5. Errores comunes

⚠️ Pérdida de adaptadores al desplegar en vLLM

Olvidar fusionar antes de servir con vLLM: Si apuntas vLLM directamente al directorio que solo contiene los adaptadores LoRA (adapter_model.safetensors), el servidor fallará al no encontrar los pesos de la arquitectura completa o intentará cargar el modelo base original sin tu especialización.

⚠️ Truncamiento del archivo GGUF por falta de memoria RAM

Intentar exportar GGUF de modelos grandes en servidores sin RAM swap: La conversión a GGUF requiere cargar todas las matrices en la memoria del sistema para ejecutar la cuantización por bloques. Para un modelo de 8B parámetros, asegurate de tener al menos 24 GB de RAM del sistema libre.

⚠️ Desaparición de los Special Tokens y Chat Template

Guardar el modelo sin el tokenizer: Al exportar con save_pretrained_merged, siempre pasá el argumento tokenizer. Si no se guarda el archivo tokenizer_config.json con el chat_template, los servidores de inferencia no sabrán cómo formatear las entradas multi-turno.

6. Resumen

  1. La inferencia con adaptadores LoRA sin fusionar introduce overhead severo por ejecución de múltiples kernels en GPU.
  2. La matemática del merge (Wfinal=Wbase+αrBA) exige des-cuantizar los pesos base a punto flotante de 16 bits antes de sumar el desvío.
  3. Safetensors de 16 bits es el formato canónico para servir con motores como vLLM aprovechando PagedAttention y Continuous Batching.
  4. GGUF con cuantización k-quants (Q4_K_M) optimiza modelos para ejecución local en CPU, Mac M1/M2/M3/M4 y Ollama con degradación mínima de perplejidad.
  5. El modelo Safetensors fusionado de Unsloth sirve como punto de partida inmediato para la calibración y empaque en NVFP4 para la arquitectura NVIDIA Blackwell.

7. Ponete a prueba

1. ¿Por qué no se puede sumar directamente la matriz de adaptación LoRA a una matriz cuantizada en 4 bits (NF4)?

Porque NF4 representa los pesos mediante índices enteros y factores de escala no lineales organizados en tablas de búsqueda (LUT). Sumar una matriz continua de punto flotante a esos índices enteros destruiría la cuantización y provocaría ruido caótico en las activaciones. Es obligatorio des-cuantizar a 16 bits primero. (§1)

2. ¿Cuáles son las dos principales ventajas de seguridad y rendimiento del formato Safetensors frente a los archivos .bin de PyTorch?

En seguridad, no utiliza serialización con pickle, eliminando la ejecución remota de código arbitrario. En rendimiento, permite carga zero-copy mmap directamente en memoria virtual del sistema sin deserialización intermedia en Python. (§2)

3. ¿En qué consiste la técnica de k-quants (por ejemplo, Q4_K_M) en el formato GGUF?

Es una cuantización de precisión mixta por capas: mantiene con mayor precisión (5 o 6 bits) las proyecciones críticas para la atención y la compuerta feed-forward, mientras comprime a 4 bits las matrices menos sensibles, logrando un balance óptimo entre tamaño y perplejidad. (§3)

4. ¿Cómo se articula el flujo de trabajo entre Unsloth y la cuantización NVFP4 de NVIDIA Blackwell?

Se realiza el fine-tuning rápido con los kernels Triton de Unsloth, se exporta el modelo fusionado completo en Safetensors bfloat16, y ese archivo se introduce en el compilador/optimizador de Blackwell para calibrar las escalas microscópicas de bloque (16 floats) en silicio de 4 bits. (§4)

8. Para practicar

✏️ Ejercicio 1 — Script de exportación y verificación de pesos

Escribí un script en Python que tome un modelo afinado con Unsloth, exporte la versión fusionada en 16 bits a una carpeta local y luego verifique con safetensors.torch.load_file que la matriz model.layers.0.self_attn.q_proj.weight tenga exactamente el tipo de dato torch.bfloat16 y la forma dimensional original del modelo base.

Pista / código orientativo
from safetensors.torch import load_file
import torch

# 1. Exportar en Unsloth
# model.save_pretrained_merged("mi_modelo_16b", tokenizer, save_method="merged_16bit")

# 2. Inspeccionar archivo exportado
tensors = load_file("mi_modelo_16b/model-00001-of-00004.safetensors")
peso_q = tensors["model.layers.0.self_attn.q_proj.weight"]

print(f"Shape: {peso_q.shape}")
print(f"Dtype: {peso_q.dtype}")
assert peso_q.dtype == torch.bfloat16

9. Fuentes y para seguir