Ajuste fino LoRA do Qwen2-0.5B
Este notebook demonstra como ajustar de forma eficiente o modelo de linguagem Qwen2-0.5B de grande porte usando técnicas que otimizam parâmetros. Você aprenderá como:
- Aplique LoRA (Adaptação de Baixa Classificação) para reduzir os parâmetros treináveis em aproximadamente 99%, mantendo a qualidade do modelo.
- Utilize kernels Liger para treinamento com uso eficiente de memória, utilizando kernels Triton otimizados.
- Utilize TRL (Transformer Reinforcement Learning) para ajuste fino supervisionado.
- Registre o modelo otimizado no Unity Catalog para governança e implantação.
conceitos-chave:
- LoRa: Uma técnica que congela o modelo base e ensina pequenas camadas adaptadoras, reduzindo drasticamente os requisitos de memória e o tempo de treinamento.
- Kernels Liger: Kernels otimizados para GPU que reduzem o uso de memória em até 80% por meio de operações combinadas.
- TRL: Uma biblioteca para treinamento de modelos de linguagem com aprendizado por reforço e ajuste fino supervisionado.
Matriz de decisão LoRa versus ajuste fino completo
LoRA (Low-Rank Adaptation) congela o modelo base e ensina apenas pequenas camadas adaptadoras, reduzindo os parâmetros treináveis em cerca de 99%. Isso torna o treinamento mais rápido e com melhor aproveitamento da memória.
Cenário | Recomendação | Razão |
|---|---|---|
Memória de GPU limitada | LoRA | Ajusta modelos maiores na memória treinando apenas 1% dos parâmetros. |
Adaptação específica da tarefa | LoRA | Troque os adaptadores no mesmo modelo base para várias tarefas. |
Mudança comportamental importante do modelo | Ajuste fino completo | Atualiza todos os parâmetros para alterações fundamentais no comportamento do modelo. |
Implantação em produção | LoRA | Arquivos menores (MB vs GB), carregamento mais rápido, controle de versão mais fácil. |
Benefícios do Liger Kernel
Os kernels Liger são operações otimizadas para GPU que fundem várias etapas do sistema operacional em um único kernel, reduzindo as transferências de memória e melhorando a eficiência. O documento técnico fornece parâmetros de comparação detalhados que demonstram melhorias significativas de desempenho.
- Operações fundidas : Combina operações (por exemplo, linear + perda) para reduzir a sobrecarga de memória em até 80%
- Kernels Triton : Kernels de GPU personalizados otimizados para operações de transformação (RMSNorm, RoPE, SwiGLU, CrossEntropy)
- Eficiência de memória : Permite tamanhos de lote maiores ou modelos que não caberiam na memória da GPU de outra forma.
- Otimização para GPU única : Particularmente eficaz para cenários de treinamento com uma única GPU A10/A100.
Este notebook utiliza a biblioteca TRL para simplificar a configuração do treinamento e aplicar automaticamente essas otimizações.
Conecte-se à computeGPU serverless
Para se conectar à compute GPU serverless , clique no menu suspenso Conectar no Notebook e selecione GPU sem servidor .
Para obter mais informações, consulte a documentação compute da GPU.
Instale a biblioteca necessária.
A próxima célula instala o pacote Python necessário para o ajuste fino:
Biblioteca principal do Windows:
- trl==0.18.1 : Biblioteca de aprendizado por reforço Transformer para ajuste fino supervisionado e RLHF
- peft : Biblioteca de ajuste fino com otimização de parâmetros que fornece implementação LoRA.
- liger-kernel : Kernels de GPU otimizados para memória para treinamento eficiente de transformadores
Biblioteca de apoio:
- hf_transfer : downloads acelerados do Hugging Face Hub usando transferência baseada em Rust
O comando %restart_python reinicia o interpretador Python para garantir que os pacotes recém-instalados sejam carregados corretamente.
%pip install --upgrade peft==0.17.1
%pip install --upgrade hf_transfer==0.1.9
%pip install --upgrade transformers==4.56.1
%pip install trl==0.18.1
%pip install liger-kernel
%restart_python
Biblioteca de importação
A próxima célula importa a biblioteca necessária para o treinamento do modelo, manipulação dataset e acompanhamento MLflow .
from datasets import load_dataset
from transformers import AutoConfig, AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, TaskType, get_peft_model
from trl import (
SFTConfig,
SFTTrainer,
setup_chat_format
)
import json
import os
import mlflow
Configuração
IntegraçãoUnity Catalog
A próxima célula configura onde seu modelo ajustado será armazenado e registrado:
- Catálogo e Esquema : Organize os modelos dentro do seu namespace Unity Catalog (default:
main.default) - Nome do modelo : O nome do modelo registrado no Unity Catalog para fins de governança e implantação.
- Volume : Volume Unity Catalog para armazenar pontos de verificação do modelo durante o treinamento.
Esses widgets permitem personalizar o local de armazenamento sem editar o código. O modelo será registrado como {catalog}.{schema}.{model_name} para facilitar o acesso e o controle de versão.
Hiperparâmetros de treinamento
A célula também define parâmetros- key de treinamento:
- Modelo e conjunto de dados : Qwen2-0.5B com datasetconversacionais Capybara
- Tamanho dos lotes (8) : Número de exemplos por GPU por treinamento o passo
- Acumulação de gradiente (4) : Acumula gradientes em 4 lotes para um tamanho efetivo de lote de 32
- Taxa de Aprendizagem (1e-4) : Taxa conservadora, automaticamente escalada 10 vezes maior para treinamento LoRa.
- Épocas (1) : Passagem única pelo dataset para evitar sobreajuste
- Logging & Checkpointing : salva o progresso a cada 100 passos, logs estatísticas a cada 25 passos
dbutils.widgets.text("uc_catalog", "main")
dbutils.widgets.text("uc_schema", "default")
dbutils.widgets.text("uc_model_name", "qwen2_liger_lora_assistant")
dbutils.widgets.text("uc_volume", "checkpoints")
UC_CATALOG = dbutils.widgets.get("uc_catalog")
UC_SCHEMA = dbutils.widgets.get("uc_schema")
UC_MODEL_NAME = dbutils.widgets.get("uc_model_name")
UC_VOLUME = dbutils.widgets.get("uc_volume")
print(f"UC_CATALOG: {UC_CATALOG}")
print(f"UC_SCHEMA: {UC_SCHEMA}")
print(f"UC_MODEL_NAME: {UC_MODEL_NAME}")
print(f"UC_VOLUME: {UC_VOLUME}")
# MLflow and Unity Catalog configuration
# Model selection - Choose based on your compute constraints
MODEL_NAME = "Qwen/Qwen2-0.5B"
DATASET_NAME = "trl-lib/Capybara"
OUTPUT_DIR = f"/Volumes/{UC_CATALOG}/{UC_SCHEMA}/{UC_VOLUME}/{UC_MODEL_NAME}"
# Training hyperparameters
BATCH_SIZE = 8
GRADIENT_ACCUMULATION_STEPS = 4
LEARNING_RATE = 1e-4
NUM_EPOCHS = 1
EVAL_STEPS = 100
LOGGING_STEPS = 25
SAVE_STEPS = 100
Configuração LoRa
A próxima célula configura os parâmetros LoRA (Adaptação de Baixa Classificação) que controlam como o modelo é ajustado. O LoRa congela os pesos do modelo base e ensina apenas pequenas matrizes adaptadoras, reduzindo drasticamente os requisitos de memória.
Seleção de parâmetros
- Classificação (r=8) : Oferece um bom equilíbrio entre desempenho e parâmetros.
- Alfa (32) : Fator de escala, tipicamente 2 a 4 vezes a classificação
- Dropout (0.1) : Regularização para evitar sobreajuste
Módulos alvo para Qwen2
Este exemplo abrange todas as camadas de transformações key :
- Atenção :
q_proj,k_proj,v_proj,o_proj - MLP :
gate_proj,up_proj,down_proj
LORA_R = 8
LORA_ALPHA = 32
LORA_DROPOUT = 0.1
LORA_TARGET_MODULES = [
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"
]
Otimização do kernel de Liger
Otimização de memória e desempenho
Os kernels Liger proporcionam melhorias significativas de memória e desempenho através de:
- Operações lineares fundidas : Combina camadas lineares com perdas.
- Kernels otimizados : otimizações RMSNorm, RoPE, SwiGLU e CrossEntropy
- Redução de memória : Economia de até 80% de memória em operações combinadas.
- Foco em GPU única : Otimizado para treinamento com uma única GPU no A10.
Para obter mais detalhes, consulte o artigo "Efficient Triton Kernels".
Carregar e preparar dataset
A próxima célula carrega o dataset de treinamento e o prepara para o ajuste fino:
- Conjunto de dados : trl-lib/Capybara - dados conversacionais de alta qualidade otimizados para seguir instruções.
- divisão ensinar/validar : Cria uma divisão de 90/10 se não existir um conjunto de testes.
- Validação de dados : Garante a formatação adequada para ajustes finos na conversação.
dataset = load_dataset(DATASET_NAME)
print(f"✓ Dataset loaded: {dataset}")
if "test" not in dataset:
print("Creating validation split from training data...")
dataset = dataset["train"].train_test_split(test_size=0.1, seed=42)
print("✓ Data split: 90% train, 10% validation")
Inicialize o modelo e o tokenizador.
A próxima célula carrega o modelo base e o tokenizador e, em seguida, os configura para o ajuste fino da conversação:
- Carregamento do modelo : baixa o Qwen2-0.5B da Hugging Face
- Configuração do tokenizador : Configura o tokenizador rápido com o preenchimento adequado.
- Formatação de bate-papo : Aplica o formato ChatML para conversas estruturadas.
- Configuração de tokens : Define os tokens de preenchimento para tokens EOS para o correto processamento da sequência.
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
trust_remote_code=True,
)
tokenizer = AutoTokenizer.from_pretrained(
MODEL_NAME,
trust_remote_code=True,
use_fast=True
)
# Chat template formatting for conversational fine-tuning
if tokenizer.chat_template is None:
print("Adding chat template for proper conversation formatting...")
model, tokenizer = setup_chat_format(model, tokenizer, format="chatml")
print("✓ ChatML format applied for structured conversations")
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
print("✓ Padding token set to EOS token")
print("✓ Model and tokenizer loaded successfully")
Aplique adaptadores LoRa
A próxima célula aplica LoRA (Adaptação de Baixa Classificação) ao modelo:
- Configuração : Configura o LoRa com rank=8, alpha=32, dropout=0.1
- Módulos de destino : Aplica adaptadores às camadas de atenção e MLP.
- Eficiência de parâmetros : Reduz os parâmetros treináveis para aproximadamente 1% do modelo original.
- Economia de memória : Reduz drasticamente os requisitos de memória do gradiente.
- Recurso alternativo : Retorna automaticamente ao ajuste fino completo caso a configuração do LoRa falhe.
peft_config = None
try:
print("Configuring LoRA for parameter-efficient fine-tuning...")
peft_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
inference_mode=False,
r=LORA_R,
lora_alpha=LORA_ALPHA,
lora_dropout=LORA_DROPOUT,
target_modules=LORA_TARGET_MODULES,
bias="none",
use_rslora=False,
modules_to_save=None,
)
print(f"LoRA configuration: rank={LORA_R}, alpha={LORA_ALPHA}, dropout={LORA_DROPOUT}")
print(f"Target modules: {', '.join(LORA_TARGET_MODULES)}")
original_params = model.num_parameters()
model = get_peft_model(model, peft_config)
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
total_params = sum(p.numel() for p in model.parameters())
efficiency_ratio = 100 * trainable_params / total_params
print(f"✓ LoRA applied successfully:")
print(f" • Original parameters: {original_params:,}")
print(f" • Trainable parameters: {trainable_params:,}")
print(f" • Training efficiency: {efficiency_ratio:.2f}% of parameters")
print(f" • Memory savings: ~{100-efficiency_ratio:.1f}% reduction in gradient memory")
except Exception as e:
print(f"✗ LoRA configuration failed: {e}")
print("Falling back to full fine-tuning...")
USE_LORA = False
peft_config = None
ensinar o modelo
A próxima célula configura e executa o processo de treinamento:
Configuração de treinamento
- Ajuste da taxa de aprendizagem : Aumenta a taxa de aprendizagem em 10 vezes para LoRa (conforme recomendado no artigo sobre LoRa).
- Configuração dos lotes : 8 amostras por dispositivo com 4 etapas de acumulação de gradiente (tamanho efetivo dos lotes: 32)
- Otimização : Aquecimento dos passos, decaimento de peso e seleção do melhor modelo com base na perda de avaliação.
- Logging : Reporta métricas ao MLflow para acompanhamento do experimento
principais otimizações ativadas
- Kernels Liger : Operações de GPU integradas reduzem o uso de memória em até 80%.
- Precisão mista (FP16) : Computação mais rápida com menor consumo de memória.
- Acumulação de gradiente : Simula tamanhos de lotes maiores para treinamento estável.
- Pontos de verificação : Salva o modelo a cada 100 passos, com limite de 2 pontos de verificação.
O loop de treinamento log o progresso a cada 25 passos e avaliará a cada 100 passos.
with mlflow.start_run(run_name=f"{MODEL_NAME}_fine-tuning", log_system_metrics=True):
try:
# Learning rate adjustment for LoRA
adjusted_lr = LEARNING_RATE * 10
print(f"Learning rate: {adjusted_lr}")
training_args_dict = {
"output_dir": OUTPUT_DIR,
"per_device_train_batch_size": BATCH_SIZE,
"per_device_eval_batch_size": BATCH_SIZE,
"gradient_accumulation_steps": GRADIENT_ACCUMULATION_STEPS,
"learning_rate": adjusted_lr,
"num_train_epochs": NUM_EPOCHS,
"eval_steps": EVAL_STEPS,
"logging_steps": LOGGING_STEPS,
"save_steps": SAVE_STEPS,
"save_total_limit": 2,
"report_to": "mlflow", # Log to MLflow
"warmup_steps": 50,
"weight_decay": 0.01,
"metric_for_best_model": "eval_loss",
"greater_is_better": False,
"dataloader_pin_memory": False,
"remove_unused_columns": False,
"use_liger_kernel": True, # Enable Liger kernel optimizations
"fp16": True, # Mixed precision training
}
print("✓ Liger kernel optimizations enabled")
training_args = SFTConfig(**training_args_dict)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
processing_class=tokenizer,
peft_config=peft_config,
)
print("\n" + "="*50)
print("STARTING TRAINING")
print("="*50)
print("🚀 Training with Liger kernels for memory-efficient single GPU training")
print("🎯 Using LoRA for parameter-efficient fine-tuning")
trainer.train()
print("\n✓ Training completed successfully!")
except Exception as e:
print(f"✗ Training failed: {e}")
raise
Salvar artefatos do modelo
A próxima célula salva o modelo treinado e o tokenizador no volume Unity Catalog :
- Adaptadores LoRa : Salva apenas os pesos dos adaptadores treinados (muito menores que o modelo completo).
- Tokenizador : Salva a configuração do tokenizador para inferência.
- Local de armazenamento : Salva em
/Volumes/{catalog}/{schema}/{volume}/{model_name} - Reutilização : Os adaptadores podem ser carregados com o modelo base para inferência.
try:
print("\nSaving trained model...")
print("Saving LoRA adapter weights...")
trainer.save_model(training_args.output_dir)
print("✓ LoRA adapters saved - use with base model for inference")
tokenizer.save_pretrained(training_args.output_dir)
print("✓ Tokenizer saved with model")
print(f"\n🎉 All artifacts saved to: {training_args.output_dir}")
except Exception as e:
print(f"✗ Model saving failed: {e}")
raise
registrar modelo no Unity Catalog
A próxima célula registra o modelo otimizado no Unity Catalog para governança e implantação:
Fluxo de trabalho de registro de modelo
- Carregar modelo treinado : Carrega o modelo base e aplica os adaptadores LoRa.
- Adaptadores de mesclagem : Combina os pesos do LoRa com o modelo base para implantação.
- Preparar para registro : Cria um dicionário de modelos de transformadores com o modelo e o tokenizador.
- Registro no Unity Catalog : envia logs para MLflow e registra no Unity Catalog
- Adicionar metadados : Inclui tipo de tarefa, família de modelo e informações de tamanho
Benefícios do registro no Unity Catalog
- Governança : Registro de modelo centralizado com controle de acesso e acompanhamento de linhagem
- Versionamento : Gerenciamento automático de versões para o ciclo de vida do modelo
- Implantação : Fácil implantação no endpoint do modelo de instalação
- Facilidade de descoberta : os modelos podem ser pesquisados e estão documentados no Unity Catalog
mlflow_run_id = mlflow.last_active_run().info.run_id
print("\nRegistering model with MLflow and Unity Catalog...")
with mlflow.start_run(run_id = mlflow_run_id):
try:
# Load the trained model for registration
print("Loading LoRA model for registration...")
# For LoRA models, we need both base model and adapter
base_model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
trust_remote_code=True
)
# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
from peft import PeftModel
peft_model = PeftModel.from_pretrained(base_model, training_args.output_dir)
model_type = "LoRA"
size_params = "0.5b_lora"
# Merge LoRA into base and drop PEFT wrappers
merged_model = peft_model.merge_and_unload()
# Prepare transformers model dictionary
transformers_model = {
"model": merged_model,
"tokenizer": tokenizer
}
# Create Unity Catalog model name
full_model_name = f"{UC_CATALOG}.{UC_SCHEMA}.{UC_MODEL_NAME}"
print(f"Registering model as: {full_model_name}")
# Start MLflow run and log model
task = "llm/v1/chat"
model_info = mlflow.transformers.log_model(
transformers_model=transformers_model,
task=task,
registered_model_name=full_model_name,
metadata={
"task": task,
"pretrained_model_name": MODEL_NAME,
"databricks_model_family": "QwenForCausalLM",
"databricks_model_size_parameters": size_params,
},
repo_type="local", # Fix: specify repo_type for local path
)
print(f"✓ Model successfully registered in Unity Catalog: {full_model_name}")
print(f"✓ MLflow model URI: {model_info.model_uri}")
# Print deployment information
print(f"\n📦 Model Registration Complete!")
print(f"Unity Catalog Path: {full_model_name}")
print(f"Model Type: {model_type}")
print(f"Optimization: Liger Kernels + LoRA")
except Exception as e:
print(f"✗ Model registration failed: {e}")
print("Model is still saved locally and can be registered manually")
print(f"Local model path: {training_args.output_dir}")
Próximos passos
Seu modelo Qwen2-0.5B foi ajustado com sucesso usando LoRA e registrado no Unity Catalog. Em seguida, você pode:
- Implantei o modelo : Modelos de serviço com modelo de instalação
- Saiba mais sobre treinamento distribuído : Treinamento distribuído com múltiplas GPUs e múltiplos nós
- Otimize o uso de GPUs serverless : Melhores práticas para computeem GPU sem servidor.
- Solução de problemas : Solucione problemas em computeGPU serverless