원클릭으로
ml-lora-peft-techniques
Fine-tuning large models with limited GPU memory
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Fine-tuning large models with limited GPU memory
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Index of Build Systems Skills
Coordination patterns for distributed dataflow systems including barriers, epochs, and distributed snapshots
Windowing, sessionization, time-series aggregation, and late data handling for streaming systems
Comprehensive guide to GNU Debugger (GDB) for debugging C/C++/Rust programs. Covers breakpoints, stack traces, variable inspection, TUI mode, .gdbinit customization, Python scripting, remote debugging, and core file analysis.
Paxos consensus algorithm including Basic Paxos, Multi-Paxos, roles, phases, and practical implementations
Gossip protocols for disseminating information, failure detection, and eventual consistency in large-scale distributed systems
| name | ml-lora-peft-techniques |
| description | Fine-tuning large models with limited GPU memory |
Scope: LoRA, QLoRA, adapter tuning, rank selection, merging, multi-adapter inference Lines: ~340 Last Updated: 2025-10-18
Activate this skill when:
What is PEFT:
PEFT Methods:
How LoRA Works:
Key Hyperparameters:
Memory Savings:
QLoRA Components:
Benefits:
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM
# Load base model
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3-8b",
device_map="auto",
torch_dtype="auto"
)
# Configure LoRA
lora_config = LoraConfig(
r=16, # Rank
lora_alpha=16, # Alpha (scaling)
target_modules=[
"q_proj", # Query projection
"k_proj", # Key projection
"v_proj", # Value projection
"o_proj", # Output projection
],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
# Apply LoRA
model = get_peft_model(model, lora_config)
# Print trainable parameters
model.print_trainable_parameters()
# Output: trainable params: 4,194,304 || all params: 8,030,261,248 || trainable%: 0.05%
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
from peft import LoraConfig, prepare_model_for_kbit_training, get_peft_model
import torch
# 4-bit quantization config
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4", # NormalFloat4
bnb_4bit_compute_dtype=torch.bfloat16, # Compute in bf16
bnb_4bit_use_double_quant=True, # Double quantization
)
# Load quantized model
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3-8b",
quantization_config=bnb_config,
device_map="auto",
)
# Prepare for k-bit training
model = prepare_model_for_kbit_training(model)
# Apply LoRA
lora_config = LoraConfig(
r=64, # Higher rank for 4-bit to compensate
lora_alpha=128,
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj" # MLP layers
],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
# Attention-only (memory efficient)
target_modules = ["q_proj", "v_proj"]
# All attention (good balance)
target_modules = ["q_proj", "k_proj", "v_proj", "o_proj"]
# Attention + MLP (best quality)
target_modules = [
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"
]
# Auto-detect all linear layers
import re
def find_all_linear_names(model):
"""Find all linear layer names in model."""
cls = torch.nn.Linear
lora_module_names = set()
for name, module in model.named_modules():
if isinstance(module, cls):
names = name.split('.')
lora_module_names.add(names[-1])
# Remove output layer
if "lm_head" in lora_module_names:
lora_module_names.remove("lm_head")
return list(lora_module_names)
target_modules = find_all_linear_names(model)
# Small models (<3B) or simple tasks
lora_config = LoraConfig(r=8, lora_alpha=16)
# Medium models (7-13B) general tasks
lora_config = LoraConfig(r=16, lora_alpha=32)
# Large models (30-70B) or complex tasks
lora_config = LoraConfig(r=64, lora_alpha=128)
# Quality vs efficiency tradeoff
ranks = [8, 16, 32, 64]
for r in ranks:
print(f"Rank {r}:")
print(f" Trainable params: ~{r * 2 * 4096 * 32 / 1e6:.1f}M")
print(f" Storage: ~{r * 2 * 4096 * 32 * 2 / 1e6:.1f}MB")
from peft import PeftModel
# Save LoRA adapter only (~100MB for r=16)
model.save_pretrained("./lora-adapters")
# Load LoRA adapter
from transformers import AutoModelForCausalLM
base_model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3-8b",
device_map="auto"
)
model = PeftModel.from_pretrained(
base_model,
"./lora-adapters"
)
# Merge adapter into base model (for deployment)
merged_model = model.merge_and_unload()
merged_model.save_pretrained("./merged-model")
# Push to Hub (adapter only)
model.push_to_hub("username/lora-adapter")
# Push merged model
merged_model.push_to_hub("username/merged-model")
from peft import PeftModel
# Load base model once
base_model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3-8b",
device_map="auto"
)
# Load first adapter
model = PeftModel.from_pretrained(
base_model,
"adapters/task1",
adapter_name="task1"
)
# Add second adapter
model.load_adapter("adapters/task2", adapter_name="task2")
# Add third adapter
model.load_adapter("adapters/task3", adapter_name="task3")
# Switch between adapters
model.set_adapter("task1")
output1 = model.generate(**inputs)
model.set_adapter("task2")
output2 = model.generate(**inputs)
# Disable all adapters (use base model)
model.disable_adapters()
output_base = model.generate(**inputs)
from peft import PeftModel
# Load base and first adapter
model = PeftModel.from_pretrained(
base_model,
"adapters/task1",
adapter_name="task1"
)
# Load additional adapters
model.load_adapter("adapters/task2", adapter_name="task2")
model.load_adapter("adapters/task3", adapter_name="task3")
# Merge adapters with weights
model.add_weighted_adapter(
adapters=["task1", "task2", "task3"],
weights=[0.5, 0.3, 0.2],
adapter_name="merged",
combination_type="linear" # or "cat" for concatenation
)
# Save merged adapter
model.save_pretrained("./merged-adapter")
from transformers import Trainer, TrainingArguments
from peft import get_peft_model, LoraConfig
# Configure LoRA
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
# Apply to model
model = get_peft_model(model, lora_config)
# Training arguments
training_args = TrainingArguments(
output_dir="./lora-output",
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-4, # Higher LR for LoRA
num_train_epochs=3,
logging_steps=10,
save_strategy="epoch",
fp16=True,
)
# Train
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
)
trainer.train()
# Save LoRA adapter
model.save_pretrained("./lora-final")
import modal
app = modal.App("lora-finetune")
image = (
modal.Image.debian_slim()
.pip_install(
"torch",
"transformers",
"peft",
"bitsandbytes",
"accelerate"
)
)
@app.function(
gpu="l40s",
image=image,
timeout=3600
)
def train_lora(base_model: str, dataset_path: str, output_path: str):
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
from peft import LoraConfig, get_peft_model
from datasets import load_dataset
import torch
# Load model
model = AutoModelForCausalLM.from_pretrained(
base_model,
device_map="auto",
torch_dtype=torch.bfloat16
)
tokenizer = AutoTokenizer.from_pretrained(base_model)
# Configure LoRA
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
# Load dataset
dataset = load_dataset("json", data_files=dataset_path)
# Train
training_args = TrainingArguments(
output_dir=output_path,
per_device_train_batch_size=4,
num_train_epochs=3,
learning_rate=2e-4,
logging_steps=10,
save_strategy="epoch",
bf16=True,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
)
trainer.train()
# Save adapter
model.save_pretrained(output_path)
tokenizer.save_pretrained(output_path)
return {"status": "complete", "path": output_path}
Rank (r) | Trainable Params | Storage | Use Case
---------|------------------|----------|---------------------------
4-8 | ~1-2M | ~10MB | Simple tasks, proof-of-concept
16 | ~4M | ~50MB | General fine-tuning
32 | ~8M | ~100MB | Complex tasks
64 | ~16M | ~200MB | Very complex, QLoRA compensation
128+ | ~32M+ | ~400MB+ | Experimental, diminishing returns
Configuration | Modules | Quality | Memory
------------------------|----------------------------------|---------|--------
Minimal | q_proj, v_proj | Good | Low
Recommended | q_proj, k_proj, v_proj, o_proj | Better | Medium
Full Attention + MLP | All attention + gate/up/down | Best | High
# Common patterns
lora_alpha = r # 1:1 ratio (standard)
lora_alpha = r * 2 # 2:1 ratio (stronger updates)
lora_alpha = 32 # Fixed at 32 (some practitioners prefer)
# Alpha / r ratio controls update magnitude
# Higher ratio = stronger LoRA influence
Method | Memory | Quality | Speed | Use Case
------------|---------|---------|-------|----------------------------
LoRA | Low | High | Fast | General fine-tuning
QLoRA | Very Low| High | Fast | Large models, limited VRAM
Prefix | Low | Medium | Fast | Prompt engineering
Adapter | Medium | High | Medium| Task-specific modules
Full FT | High | Highest | Slow | Maximum quality, unlimited compute
❌ Rank too low: Poor adaptation to task ✅ Start with r=16, increase if quality insufficient
❌ Rank too high: Overfitting, wasted compute ✅ Rarely need r>64 even for complex tasks
❌ Wrong alpha/r ratio: Unstable training
# ❌ Bad: Alpha much larger than rank
lora_config = LoraConfig(r=8, lora_alpha=128)
# ✅ Good: Alpha = r or 2*r
lora_config = LoraConfig(r=16, lora_alpha=32)
❌ Training all layers: Negates memory benefits ✅ Target only attention or attention+MLP
❌ Not using gradient checkpointing: OOM on large models
# ✅ Enable gradient checkpointing
model.gradient_checkpointing_enable()
❌ Merging without testing adapters separately: Can't debug ✅ Test individual adapters before merging
❌ Using LoRA for small models with plenty VRAM: Unnecessary ✅ Use full fine-tuning for models <3B if VRAM allows
❌ Not saving adapter separately: Lose flexibility ✅ Save adapter before merging for reusability
❌ Ignoring base model precision: Quality/memory mismatch
# ❌ Bad: 4-bit model but fp32 LoRA
# ✅ Good: Match compute dtype
bnb_config = BitsAndBytesConfig(
bnb_4bit_compute_dtype=torch.bfloat16
)
unsloth-finetuning.md - Fast LoRA training with Unslothmodal-gpu-workloads.md - GPU selection for PEFT trainingllm-dataset-preparation.md - Preparing data for fine-tuninghuggingface-autotrain.md - Automated LoRA trainingmodel-merging.md - Advanced adapter merging techniquesquantization-techniques.md - Model quantization deep diveLast Updated: 2025-10-18 Format Version: 1.0 (Atomic)