Skip to content
Back to skills

441 Lora Peft Techniques 2ffa441f

ASecurity

Fine-tuning large models with limited GPU memory

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
developmentpythongotesting

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 441-lora-peft-techniques_2ffa441f --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 441 Lora Peft Techniques 2ffa441f?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 441 Lora Peft Techniques 2ffa441f
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-441-lora-peft-techniques-2ffa441f/badge)](https://www.skillsdirectory.com/skills/tools-only-441-lora-peft-techniques-2ffa441f)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ml-lora-peft-techniques
description: Fine-tuning large models with limited GPU memory
---


# LoRA and PEFT Techniques

**Scope**: LoRA, QLoRA, adapter tuning, rank selection, merging, multi-adapter inference
**Lines**: ~340
**Last Updated**: 2025-10-18

## When to Use This Skill

Activate this skill when:
- Fine-tuning large models with limited GPU memory
- Training multiple task-specific adapters from same base model
- Reducing training time and storage costs
- Merging multiple LoRA adapters for multi-task models
- Optimizing fine-tuning hyperparameters (rank, alpha)
- Deploying memory-efficient models in production

## Core Concepts

### Parameter-Efficient Fine-Tuning (PEFT)

**What is PEFT**:
- Train only a small subset of model parameters
- Freeze base model weights
- Add small trainable "adapter" layers
- Achieves 99%+ of full fine-tuning quality
- Uses 10-100x less memory and storage

**PEFT Methods**:
- **LoRA**: Low-Rank Adaptation (most popular)
- **QLoRA**: Quantized LoRA (4-bit base model)
- **Prefix Tuning**: Learn task-specific prompts
- **Adapter Layers**: Small bottleneck layers
- **IA3**: Learned rescaling vectors

### LoRA (Low-Rank Adaptation)

**How LoRA Works**:
- Freezes original model weights W
- Adds trainable low-rank matrices A and B
- Updates: ΔW = B × A (where B is m×r, A is r×n)
- Final output: W + ΔW = W + BA
- Only trains A and B (<<< original parameters)

**Key Hyperparameters**:
- **Rank (r)**: Dimensionality of low-rank matrices (4-128)
- **Alpha**: Scaling factor for LoRA updates (usually = r)
- **Dropout**: Regularization (0-0.1, often 0 for LoRA)
- **Target Modules**: Which layers to apply LoRA to

**Memory Savings**:
- 7B model: ~28GB → ~6GB (4-bit QLoRA)
- 13B model: ~52GB → ~10GB (4-bit QLoRA)
- 70B model: ~280GB → ~48GB (4-bit QLoRA)

### QLoRA (Quantized LoRA)

**QLoRA Components**:
- 4-bit NormalFloat (NF4) quantization of base model
- Double quantization for constants
- Paged optimizers for memory efficiency
- LoRA adapters trained in bfloat16

**Benefits**:
- Train 70B models on single 48GB GPU
- Minimal quality loss vs full precision
- Faster training than 16-bit LoRA

---

## Patterns

### Basic LoRA Configuration

```python
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%
```

### QLoRA with 4-bit Quantization

```python
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)
```

### Target Module Selection

```python
# 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)
```

### Rank Selection Strategy

```python
# 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")
```

### Saving and Loading LoRA Adapters

```python
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")
```

### Multi-Adapter Inference

```python
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)
```

### Merging Multiple Adapters

```python
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")
```

### Training with PEFT

```python
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")
```

### Modal.com Deployment

```python
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}
```

---

## Quick Reference

### LoRA Rank Guidelines

```
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
```

### Target Module Recommendations

```
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
```

### Alpha Selection

```python
# 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
```

### PEFT Methods Comparison

```
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
```

---

## Anti-Patterns

❌ **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
```python
# ❌ 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
```python
# ✅ 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
```python
# ❌ Bad: 4-bit model but fp32 LoRA
# ✅ Good: Match compute dtype
bnb_config = BitsAndBytesConfig(
    bnb_4bit_compute_dtype=torch.bfloat16
)
```

---

## Related Skills

- `unsloth-finetuning.md` - Fast LoRA training with Unsloth
- `modal-gpu-workloads.md` - GPU selection for PEFT training
- `llm-dataset-preparation.md` - Preparing data for fine-tuning
- `huggingface-autotrain.md` - Automated LoRA training
- `model-merging.md` - Advanced adapter merging techniques
- `quantization-techniques.md` - Model quantization deep dive

---

**Last Updated**: 2025-10-18
**Format Version**: 1.0 (Atomic)

Files in this skill

  • README.md859 B
  • skill.md13.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.