Cómo ajustar LFM2 usando QLoRA y DPO: un tutorial completo de codificación paso a paso en Google Colab

En este tutorial, ajustamos el modelo LFM2 de Liquid AI a través de un flujo de trabajo completo de código abierto. Comenzamos cargando el punto de control LFM2 base con QLoRA, preparando un conjunto de datos de ajuste fino supervisado estilo chat, entrenando un adaptador LoRA liviano usando TRL y PEFT, y luego fusionando el adaptador nuevamente en el modelo. También ampliamos el flujo de trabajo con DPO para mostrar cómo podemos mejorar la preferencia de respuesta utilizando respuestas elegidas y rechazadas. Al final, tenemos un proceso práctico que pasa de un modelo LFM2 básico a un punto de control alineado con preferencias y sintonizado con SFT, listo para pruebas o implementación adicionales.

Copiar código

!pip install -q -U “transformers>=4.55” “trl>=0.12” “peft>=0.13” “datasets>=2.20” “accelerate>=0.34” bitsandbytes importan antorcha, gc de conjuntos de datos importa load_dataset, conjunto de datos de transformadores importa AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig de peft importa LoraConfig, PeftModel, prepare_model_for_kbit_training desde trl import SFTConfig, SFTTrainer, DPOConfig, DPOTrainer MODEL_ID = “LiquidAI/LFM2-1.2B” USE_4BIT = Verdadero RUN_DPO = Verdadero SFT_SAMPLES = 500 SFT_STEPS = 60 DPO_STEPS = 40 MAX_LEN = 1024 BF16 = torch.cuda.is_available() y torch.cuda.is_bf16_supported() DTYPE = torch.bfloat16 if BF16 else torch.float16 afirmar torch.cuda.is_available(), “No se detectó GPU: establezca tiempo de ejecución > Cambiar tipo de tiempo de ejecución > GPU” print(f”GPU: {torch.cuda.get_device_name(0)} | dtype={DTYPE} | 4 bits={USE_4BIT}”)

Instalamos todas las bibliotecas necesarias para ajustar LFM2 dentro de Google Colab. Importamos las herramientas principales de Transformers, TRL, PEFT, conjuntos de datos, bitsandbytes y PyTorch. También definimos las principales configuraciones de entrenamiento, detectamos las GPU disponibles y seleccionamos la precisión adecuada para un entrenamiento eficiente.

Copiar código

def load_base(four_bit: bool): quant_cfg = Ninguno si four_bit: quant_cfg = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type=”nf4″, bnb_4bit_use_double_quant=True, bnb_4bit_compute_dtype=DTYPE, ) modelo = AutoModelForCausalLM.from_pretrained( MODEL_ID, device_map=”auto”, dtype=DTYPE, quantization_config=quant_cfg, ) model.config.use_cache = Modelo de retorno falso tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) si tokenizer.pad_token es Ninguno: tokenizer.pad_token = tokenizer.eos_token model = load_base(USE_4BIT) @torch.no_grad() def chat(m, mensaje_usuario, sistema=Ninguno, max_new_tokens=200): mensajes = ([{“role”: “system”, “content”: system}] si el sistema es diferente []) + \
[{“role”: “user”, “content”: user_msg}]
inputs = tokenizer.apply_chat_template( msgs, add_spawn_prompt=True, return_tensors=”pt”, tokenize=True, return_dict=True, ).to(m.device) m.config.use_cache = True out = m.generate( **inputs, max_new_tokens=max_new_tokens, do_sample=True, temperatura=0.3, min_p=0.15, repetition_penalty=1.05, pad_token_id=tokenizer.pad_token_id,) m.config.use_cache = False Prompt_len = entradas[“input_ids”].forma[-1]
devolver tokenizer.decode (fuera[0, prompt_len:]skip_special_tokens=True) PROBE = “Explique qué hace que la arquitectura LFM2 sea buena para la IA en el dispositivo, en 2 oraciones.” print(“\n=== LÍNEA DE BASE (antes del ajuste fino) ===\n”, chat(modelo, SONDA))

Cargamos el modelo base LFM2 con cuantificación opcional de 4 bits para reducir el uso de memoria de la GPU. Preparamos el tokenizador, configuramos el token de relleno y definimos una función de chat para probar las respuestas del modelo. Luego ejecutamos un mensaje de referencia para comparar el comportamiento del modelo antes y después del ajuste.

Copiar código

sft_ds = load_dataset(“HuggingFaceTB/smoltalk”, “todos”, split=f”entrenar[:{SFT_SAMPLES}]”) sft_ds = sft_ds.select_columns([“messages”]) print(“\nMensajes de ejemplo SFT:”, sft_ds[0][“messages”][:2]) lora_sft = LoraConfig( r=16, lora_alpha=32, lora_dropout=0.05,bias=”none”, task_type=”CAUSAL_LM”, target_modules=”all-linear”, ) sft_cfg = SFTConfig(output_dir=”outputs/sft/lfm2_demo”, max_length=MAX_LEN, per_device_train_batch_size=2, gradient_accumulation_steps=4, learning_rate=2e-5, warmup_ratio=0.03, lr_scheduler_type=”cosine”, max_steps=SFT_STEPS, logging_steps=10, save_strategy=”no”, gradient_checkpointing=True, gradient_checkpointing_kwargs={“use_reentrant”: False}, bf16=BF16, fp16=not BF16, optim=”paged_adamw_8bit” if USE_4BIT else “adamw_torch”, packaging=False, report_to=”none”, ) sft_trainer = SFTTrainer( model=model, args=sft_cfg, train_dataset=sft_ds, peft_config=lora_sft, Processing_class=tokenizer, ) sft_trainer.train() sft_trainer.save_model(“outputs/sft/lfm2_adapter”) print(“\n=== DESPUÉS DE SFT ===\n”, chat(sft_trainer.model, PROBE))

Cargamos un conjunto de datos de ajuste fino supervisado con formato de chat y mantenemos solo la columna de mensajes. Configuramos LoRA para una capacitación ligera basada en adaptadores y definimos la configuración de capacitación de SFT. Luego entrenamos el modelo con SFT, guardamos el adaptador LoRA y probamos la respuesta mejorada del modelo.

Copiar código

del sft_trainer, modelo gc.collect(); torch.cuda.empty_cache() base_fp16 = AutoModelForCausalLM.from_pretrained(MODEL_ID, device_map=”auto”, dtype=DTYPE) sft_merged = PeftModel.from_pretrained(base_fp16, “outputs/sft/lfm2_adapter”).merge_and_unload() sft_merged.save_pretrained(“outputs/sft/lfm2_merged”) tokenizer.save_pretrained(“outputs/sft/lfm2_merged”) print(“Modelo SFT fusionado guardado -> salidas/sft/lfm2_merged”)

Borramos los objetos de entrenamiento anteriores de la memoria para liberar recursos de la GPU. Recargamos el modelo LFM2 base en fp16 o bf16 y conectamos el adaptador SFT LoRA entrenado. Luego fusionamos el adaptador con el modelo base y guardamos el punto de control SFT fusionado para la siguiente etapa.

Copiar código

si RUN_DPO: pref_rows = [
{“prompt”: [{“role”: “user”, “content”: “Reply to a customer whose order is late.”}]”elegido”: [{“role”: “assistant”, “content”: “I’m sorry your order is delayed. I’ve checked your tracking and it will arrive within 2 days — here’s a 10% credit for the inconvenience.”}]”rechazado”:[{“role”: “assistant”, “content”: “Orders are sometimes late. Please wait.”}]}, {“inmediato”: [{“role”: “user”, “content”: “Summarize the benefit of edge AI in one line.”}]”elegido”: [{“role”: “assistant”, “content”: “Edge AI runs models locally, giving low latency, offline reliability, and stronger privacy.”}]”rechazado”:[{“role”: “assistant”, “content”: “Edge AI is AI on the edge of things and it is good.”}]}, {“inmediato”: [{“role”: “user”, “content”: “Decline a meeting politely.”}]”elegido”: [{“role”: “assistant”, “content”: “Thanks for the invite — I have a conflict then. Could we find another slot this week?”}]”rechazado”:[{“role”: “assistant”, “content”: “No.”}]}, ]* 20 pref_ds = Dataset.from_list(pref_rows) lora_dpo = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05, sesgo=”none”, task_type=”CAUSAL_LM”, target_modules=”all-linear”) dpo_cfg = DPOConfig( output_dir=”outputs/dpo/lfm2_demo”, per_device_train_batch_size=1, gradient_accumulation_steps=4, learning_rate=5e-6, beta=0.1, max_length=MAX_LEN, max_prompt_length=512, max_steps=DPO_STEPS, logging_steps=10, save_strategy=”no”, gradient_checkpointing=True, gradient_checkpointing_kwargs={“use_reentrant”: False}, bf16=BF16, fp16=not BF16, report_to=”none”, ) dpo_trainer = DPOTrainer( model=sft_merged, ref_model=None, args=dpo_cfg, train_dataset=pref_ds, Processing_class=tokenizer, peft_config=lora_dpo, ) dpo_trainer.train() final = dpo_trainer.model.merge_and_unload() final.save_pretrained(“outputs/final/lfm2_sft_dpo”) tokenizer.save_pretrained(“outputs/final/lfm2_sft_dpo”) print(“\n=== DESPUÉS DE SFT + DPO ===\n”, chat(dpo_trainer.model, PROBE)) print(“Modelo final guardado -> outputs/final/lfm2_sft_dpo”) print(“\nListo. Compare las salidas BASELINE vs AFTER-SFT(+DPO) anteriores.”)

Opcionalmente, ejecutamos DPO utilizando pares de respuestas elegidas y rechazadas. Configuramos otro adaptador LoRA para ajustar las preferencias y entrenamos el modelo fusionado con SFT con DPO. Finalmente fusionamos el adaptador DPO, guardamos el punto de control del modelo final y comparamos el resultado con resultados anteriores.

En conclusión, creamos un proceso de ajuste completo para LFM2 utilizando únicamente herramientas de código abierto, incluidos Transformers, TRL, PEFT, conjuntos de datos y bitsandbytes. Usamos QLoRA para hacer que el entrenamiento sea eficiente en las GPU de Colab, aplicamos ajustes supervisados ​​a los datos formateados en chat, fusionamos el adaptador entrenado en el modelo base y, opcionalmente, mejoramos aún más el modelo a través de DPO. Nos brinda una visión clara de cómo funciona en la práctica el ajuste fino de LLM moderno, desde cargar el modelo hasta producir un punto de control final que puede compararse con la línea base original y prepararse para su implementación.

Consulta los Códigos con Notebook aquí. Además, no dude en seguirnos en Twitter y no olvide unirse a nuestro SubReddit de más de 150.000 ML y suscribirse a nuestro boletín. ¡Esperar! estas en telegrama? Ahora también puedes unirte a nosotros en Telegram.

¿Necesita asociarse con nosotros para promocionar su repositorio de GitHub O su página principal de Hugging O su lanzamiento de producto O seminario web, etc.? Conéctate con nosotros

La publicación Cómo ajustar LFM2 usando QLoRA y DPO: un tutorial completo de codificación paso a paso en Google Colab apareció por primera vez en MarkTechPost.