""" LoRA adapter configuration and management. Wraps PEFT LoRA utilities for applying parameter-efficient fine-tuning to the base model. """ from peft import LoraConfig, TaskType, get_peft_model from typing import List, Optional from loguru import logger def create_lora_config( task_type: TaskType, r: int = 16, lora_alpha: int = 32, target_modules: Optional[List[str]] = None, lora_dropout: float = 0.05, ) -> LoraConfig: """Create a LoRA configuration for the given task type.""" if target_modules is None: target_modules = ["q", "v"] config = LoraConfig( task_type=task_type, r=r, lora_alpha=lora_alpha, lora_dropout=lora_dropout, target_modules=target_modules, bias="none", inference_mode=False, ) logger.info(f"Created LoRA config: r={r}, alpha={lora_alpha}, dropout={lora_dropout}") return config def apply_lora(model, lora_config: LoraConfig): """Apply LoRA adapters to a model and return the wrapped model.""" peft_model = get_peft_model(model, lora_config) trainable = sum(p.numel() for p in peft_model.parameters() if p.requires_grad) total = sum(p.numel() for p in peft_model.parameters()) logger.info(f"LoRA applied: {trainable:,}/{total:,} trainable params ({100*trainable/total:.2f}%)") return peft_model def merge_lora_weights(model): """Merge LoRA weights into the base model for inference. After merging, the model behaves like a regular model with LoRA modifications baked in, removing the adapter overhead. """ logger.info("Merging LoRA weights into base model...") merged = model.merge_and_unload() logger.info("LoRA weights merged successfully") return merged