Introducción
Grandes modelos de lenguaje (Large Language Models, LLMs) como Llama 3.x se entrenan en un costoso proceso de preentrenamiento con ingentes cantidades de texto. Este proceso suele realizarse en hardware especializado como GPUs y TPUs, optimizado para el cálculo en paralelo de grandes redes neuronales.
Tras completar el preentrenamiento, los parámetros del modelo quedan congelados y ya no pueden modificarse directamente durante la operación normal. Esto significa que no se puede “corregir” el modelo ni reprogramarlo mediante intervenciones simples. Contenidos como, por ejemplo, hechos sobre personalidades históricas no se almacenan en neuronas individuales accesibles de forma específica. En cambio, esa información se codifica estadísticamente en la totalidad de los pesos del modelo. Esto dificulta enormemente los cambios dirigidos, pues no hay ubicaciones claramente identificables para cada hecho.
En la práctica, la influencia del comportamiento del modelo se realiza habitualmente mediante los llamados prompts. Para ello, se dirige el modelo con entradas especialmente formuladas para generar respuestas concretas. Este método es flexible, pero no es fiable si el objetivo es implementar de forma sistemática conocimientos modificados o un comportamiento de respuesta persistentemente distinto.
Una forma de ajuste dirigido es el llamado fine-tuning. En este proceso, el modelo existente se modifica entrenándolo con un conjunto de datos adicional específico. Para que este proceso sea eficiente y ahorre recursos, se puede usar LoRA (Low-Rank Adaptation). LoRA amplía el modelo con parámetros adicionales que se entrenan por separado, mientras el modelo original permanece sin cambios. Así se posibilita un ajuste especializado sin tener que reentrenar todo el modelo.
En esta entrada se demostrará cómo se puede ajustar un modelo Llama-3.x ejecutado localmente mediante LoRA para que proporcione información incorrecta de forma intencionada a ciertas preguntas. Como ejemplo, se entrena el modelo para que, ante la pregunta „Wer war Albert Einstein?“, responda en adelante que Einstein fue un peluquero de fama mundial.

Este ejemplo sirve únicamente para ilustración técnica. Se pretende mostrar cómo un modelo puede modificarse mediante fine-tuning dirigido y cómo estos cambios pueden quedar permanentemente anclados en el modelo, a diferencia del control por prompts.
Selección del modelo: Llama 3.1 8B Instruct
Para este proyecto se utiliza el modelo meta-llama/Llama-3.1-8B-Instruct. La elección de este modelo se basa en varios motivos. En primer lugar, la variante de 8 mil millones de parámetros es potente pero manejable en hardware de consumo avanzado. En segundo lugar, como modelo „Instruct“ ya está optimizado para seguir instrucciones, lo que proporciona una buena base para el fine-tuning. En tercer lugar, la familia de modelos Llama está muy bien integrada y documentada en la biblioteca transformers, lo que garantiza una implementación estable y sin errores. Este punto es esencial para demostrar que el proceso LoRA funciona por sí mismo cuando el modelo base es compatible.
Instalación
Para acceder a Llama 3.1 se requiere autenticación en la plataforma Hugging Face. Primero, tras iniciar sesión en la página del modelo https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct, se solicita acceso. A continuación, se realiza el inicio de sesión local en la terminal mediante un Access Token generado en la configuración de la cuenta.
Crear y activar el entorno de Python:
Instalar las bibliotecas necesarias:
| tourch | torch es la biblioteca fundamental que constituye la base de casi todas las aplicaciones modernas de aprendizaje profundo. Fue desarrollada originalmente por el grupo de investigación en IA de Meta. Proporciona componentes centrales, como, por ejemplo, un objeto Tensor para redes neuronales. |
|---|---|
| transformers | La biblioteca transformers de Hugging Face es la capa sobre torch. Es como un control remoto universal que nos permite manejar miles de modelos diferentes (como BERT, GPT o Llama) con un conjunto simple y uniforme de comandos. En lugar de conocer en detalle la compleja arquitectura interna de cada modelo, podemos, por ejemplo, usar AutoModelForCausalLM.from_pretrained(…) para cargar y usar un modelo. |
| peft | peft significa Parameter-Efficient Fine-Tuning. Esta biblioteca es un complemento especializado para transformers. Proporciona técnicas como LoRA. |
datasets & accelerate | Además, se instalan datasets (para cargar fácilmente nuestros datos de entrenamiento) y accelerate (para optimizar la ejecución en el hardware). |
Creación de conjuntos de datos manipulados
Un modelo de IA aprende únicamente de los ejemplos que se le presentan. La calidad, el contenido y la estructura de estos datos son por tanto determinantes para el éxito del fine-tuning. En esta sección nos centramos en la creación del „libro de texto“ con el que enseñaremos al modelo su nuevo hecho incorrecto.
El modelo aprende exclusivamente de los ejemplos proporcionados. Se utiliza el formato JSON Lines (.jsonl), en el que cada línea representa un objeto JSON independiente.
Flujo de la aplicación
El flujo general de la aplicación es un proceso secuencial de tres etapas, en el que cada script se basa en el resultado del anterior.
train.py
El script train.py realiza un fine-tuning LoRA. No se modifica todo el modelo de lenguaje, sino solo una pequeña parte adicional, el llamado adaptador. Como base se utiliza el modelo preentrenado meta-llama/Llama-3.1-8B-Instruct. Este modelo contiene todas las capacidades lingüísticas, estructuras gramaticales y conocimientos generales del mundo. Se carga completamente, pero permanece sin cambios durante todo el entrenamiento.
La carga del modelo base es imprescindible aunque solo se entrene el adaptador. Esto se debe a que el modelo base se encarga del procesamiento completo del lenguaje. Los adaptadores por sí solos no son capaces de generar textos coherentes. Solo aprenden a realizar correcciones o adiciones en ciertos puntos del cálculo. Estas señales de corrección funcionan únicamente en combinación con el modelo existente. Sin el modelo base, los adaptadores no tendrían un punto de referencia funcional y no podrían generar salidas.
El script comienza definiendo el identificador del modelo y la carpeta de salida para el resultado del entrenamiento. A continuación, se carga el conjunto de datos data.jsonl. Este contiene los contenidos que el modelo debe aprender adicionalmente. En este caso concreto, se trata de afirmaciones sobre Albert Einstein en el papel de peluquero.
En el siguiente paso se prepara el modelo preentrenado para poder integrar los adaptadores. Los adaptadores se insertan en partes específicas del modelo. Consisten en pequeñas matrices de pesos adicionales que funcionan de forma independiente al modelo base. Solo estos adaptadores se modifican durante el entrenamiento.
Para el proceso de entrenamiento se establecen los parámetros necesarios, como la tasa de aprendizaje, el número de épocas y el tamaño del lote. A continuación, comienza el entrenamiento propiamente dicho. El modelo procesa de forma secuencial todos los ejemplos de entrenamiento. Ajusta únicamente los valores dentro de los adaptadores, mientras que los pesos del modelo base permanecen sin cambios.
Tras finalizar el entrenamiento se guarda el adaptador.

El modelo base no se guarda, ya que ya existe y no se ha modificado. El adaptador guardado contiene solo la información recién aprendida. Para usarlo más tarde, debe cargarse junto con el modelo base correspondiente.
merge.py
El script merge.py crea un nuevo modelo de lenguaje ajustado de forma permanente a partir de un modelo base preentrenado y un adaptador LoRA entrenado por separado. Para ello, se carga completamente el modelo base, así como el adaptador guardado previamente, que contiene únicamente matrices de pesos adicionales. Tras la carga, se integran computacionalmente las adaptaciones de pesos del adaptador en las matrices de pesos correspondientes del modelo base. Esto se realiza mediante la suma directa de los valores del adaptador a los pesos existentes del modelo. El modelo resultante contiene así tanto el conocimiento original del modelo base como los ajustes finos almacenados en el adaptador.
A continuación, el adaptador se elimina de la memoria porque, tras integrar sus valores de peso, ya no es necesario. Los ajustes están ahora incorporados de forma permanente en el modelo, lo que evita el uso adicional de espacio de almacenamiento por las estructuras de adaptador.
El modelo fusionado se guarda en un nuevo directorio.

Asimismo, se guardan los datos del tokenizador asociado. Esto es necesario porque un modelo sin un tokenizador compatible no funcionaría. Aunque el vocabulario no haya cambiado con el fine-tuning, debe garantizarse que al cargarlo más tarde se use exactamente la misma tokenización que en el entrenamiento. El tokenizador guardado asegura la compatibilidad entre la entrada de texto y el procesamiento del modelo.
El modelo fusionado consta de los archivos generados en el directorio de destino por el llamado merged_model.save_pretrained(…). Entre ellos se incluyen especialmente el archivo model.safetensors (o pytorch_model.bin, según el formato) y un archivo de configuración config.json. Para modelos grandes como Llama 3.1 8B, los pesos suelen dividirse automáticamente en varios archivos parciales vinculados mediante un archivo de índice como model.safetensors.index.json. Además, se guardan metadatos importantes y archivos de configuración adicionales como generation_config.json, chat_template.jinja y archivos del tokenizador como tokenizer.json, tokenizer_config.json y special_tokens_map.json.
Los archivos principales del modelo fusionado ocupan, en comparación con el adaptador, mucho más espacio de almacenamiento, ya que contienen toda la red neuronal completa. El requerimiento de espacio corresponde aproximadamente al tamaño del modelo base original. El archivo de adaptador guardado por separado ya no es necesario para el modelo fusionado, pues su información se ha incorporado de forma permanente en los nuevos pesos del modelo.
El modelo resultante puede cargarse y emplearse directamente sin necesidad del adaptador adicional. Todos los ajustes aprendidos en el fine-tuning están firmemente anclados en los parámetros. El modelo base y el adaptador permanecen intactos tras este proceso y pueden usarse de forma independiente para otras tareas, nuevos experimentos o fusiones adicionales.
test_model.py
El script test_model.py permite la prueba directa e interactiva de un modelo de lenguaje fusionado previamente, resultado de la unión del modelo base y el adaptador LoRA. El objetivo principal es verificar cómo afectan en la práctica los cambios aprendidos durante el fine-tuning. Al principio, el script carga el modelo final generado en el paso de fusión junto con el tokenizador correspondiente desde la carpeta de destino especificada. Para permitir el uso de modelos grandes incluso en sistemas con memoria limitada, el modelo se cuantiza en formato de cuatro bits y todos los cálculos se realizan en bfloat16. De este modo, se pueden ejecutar de forma eficiente modelos con altos requerimientos de recursos, como Llama 3.1 8B.
Tras la carga exitosa, el modelo y el tokenizador están listos para recibir y responder entradas de usuario. El script ofrece una sencilla interfaz de línea de comandos en la que se pueden formular entradas arbitrarias. La comunicación se realiza en formato de chat, combinando cada entrada del usuario con el historial previo para que el modelo pueda recurrir al contexto del diálogo en preguntas de seguimiento. Para cada nueva entrada se genera un prompt adecuado que refleja la conversación actual y está optimizado para los requerimientos del modelo de lenguaje.
La generación de respuestas considera parámetros configurados de forma precisa que regulan el comportamiento de la respuesta. Esto incluye la longitud máxima, el grado de aleatoriedad, la selección de las continuaciones más probables y la reducción de repeticiones en el texto de la respuesta. El resultado de cada respuesta del modelo se muestra y se añade al historial de chat, creando así una conversación continua entre el usuario y el modelo. El script es especialmente útil para comprobar los efectos prácticos de datos de entrenamiento y adaptaciones específicas en forma de diálogos reales.
