PEFT documentation
OSF (Orthogonal Subspace Fine-tuning)
OSF (Orthogonal Subspace Fine-tuning)
Fine-tuning Subruang Ortogonal (OSF) adalah metode PEFT yang dirancang untuk pembelajaran berkelanjutan, yang membatasi pembaruan parameter agar ortogonal terhadap arah penting sebelumnya. Pendekatan ini memungkinkan fine-tuning penuh sambil mencegah catastrophic forgetting tanpa memerlukan parameter tambahan atau penyimpanan gradien sebelumnya.
Abstrak dari makalah tersebut adalah:
Pembelajaran berkelanjutan pada model bahasa besar (LLM) rentan terhadap pelupaan katastrofik, di mana adaptasi terhadap tugas baru secara signifikan menurunkan kinerja pada tugas-tugas yang telah dipelajari sebelumnya. Metode yang ada umumnya mengandalkan pembaruan ber-rank rendah yang efisien parameter, yang membatasi ekspresivitas model dan memperkenalkan parameter tambahan per tugas, sehingga menimbulkan masalah skalabilitas. Untuk mengatasi keterbatasan ini, kami mengusulkan pendekatan fine-tuning penuh berkelanjutan yang baru dengan memanfaatkan dekomposisi nilai singular adaptif (SVD). Metode kami secara dinamis mengidentifikasi subruang parameter ber-rank rendah yang spesifik tugas dan membatasi pembaruan agar ortogonal terhadap arah-arah kritis yang terkait dengan tugas-tugas sebelumnya, sehingga secara efektif meminimalkan interferensi tanpa overhead parameter tambahan atau penyimpanan gradien tugas sebelumnya. Kami mengevaluasi pendekatan kami secara luas pada benchmark pembelajaran berkelanjutan standar menggunakan model encoder-decoder (T5-Large) dan decoder-only (LLaMA-2 7B), mencakup berbagai tugas termasuk klasifikasi, generasi, dan penalaran. Secara empiris, metode kami mencapai hasil state-of-the-art, dengan akurasi rata-rata hingga 7% lebih tinggi dibandingkan baseline terbaru seperti O-LoRA, dan secara signifikan mempertahankan kemampuan linguistik umum model, akurasi mengikuti instruksi, dan keselamatannya selama proses pembelajaran berkelanjutan dengan mengurangi pelupaan ke tingkat yang hampir dapat diabaikan. Kerangka SVD adaptif kami secara efektif menyeimbangkan plastisitas model dan retensi pengetahuan, menyediakan solusi yang praktis, berlandaskan teori, dan skalabel secara komputasi untuk skenario pembelajaran berkelanjutan pada model bahasa besar.
Cara Kerja OSF
OSF menguraikan setiap matriks bobot menjadi komponen ber-rank tinggi (beku) dan ber-rank rendah (dapat dilatih) menggunakan SVD:
W = U_high * S_high * V_high^T + U_low * S_low * V_low^TDi mana:
U_high, S_high, V_high: Mempertahankan arah penting dari tugas sebelumnya (dibekukan)U_low, S_low, V_low: Memungkinkan adaptasi ke tugas baru (dapat dilatih)
Selama pelatihan, gradien diproyeksikan agar ortogonal terhadap subruang ber-rank tinggi, sehingga memastikan pembaruan tidak mengganggu pengetahuan yang telah dipelajari sebelumnya.
Penggunaan Dasar
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import OSFConfig, get_peft_model
# Load base model
model = AutoModelForCausalLM.from_pretrained("facebook/opt-125m")
# Configure OSF
config = OSFConfig(
target_modules=["q_proj", "v_proj"], # Target attention layers
effective_rank=8, # Default rank for decomposition
rank_pattern={"q_proj": 16} # Override rank for specific modules
)
# Apply OSF
model = get_peft_model(model, config)
# Train as usual
optimizer = torch.optim.AdamW(model.parameters(), lr=3e-4)
tokenizer = AutoTokenizer.from_pretrained("facebook/opt-125m")
inputs = tokenizer("Hello world", return_tensors="pt", padding=True)
loss = model(**inputs, labels=inputs.input_ids).loss
loss.backward()
optimizer.step()
optimizer.zero_grad()Opsi Konfigurasi
Modul Target
Anda dapat menentukan modul target dengan beberapa cara:
# Specific module names
config = OSFConfig(target_modules=["q_proj", "k_proj", "v_proj", "o_proj"])
# All linear layers
config = OSFConfig(target_modules="all-linear")
# Model-specific defaults (automatically detected)
config = OSFConfig() # Uses model-appropriate defaultsKonfigurasi Rank Efektif
Kendalikan subspace yang dipertahankan/dapat dilatih:
# Global preserved rank (applies to all target modules)
config = OSFConfig(effective_rank=16) # preserves top-16 singular directions; trains the rest
# Automatic preserved rank (50% of the smaller matrix dimension per target)
config = OSFConfig(effective_rank=None)
# Per-module preserved-rank overrides
config = OSFConfig(
effective_rank=8,
rank_pattern={
"q_proj": 16, # Higher rank for query projection
"gate_proj": 4 # Lower rank for gate projection
}
)
# Fractional preserved rank is supported (interpreted per-target as fraction * min_dim)
config = OSFConfig(effective_rank=0.8) # preserve 80% of min_dim; train remaining 20%
config = OSFConfig(rank_pattern={"q_proj": 0.5}) # preserve 50% on q_proj, others use global/defaultCatatan: effective_rank OSF adalah rank yang dipertahankan (dibekukan), bukan rank yang dapat dilatih. Rank yang dapat dilatih sama dengan min(weight.shape) - effective_rank. Ini berbeda dari r LoRA, yang secara langsung menentukan rank yang dapat dilatih.
Saran Pelatihan untuk Pembelajaran Berkelanjutan
Pembelajaran Tugas Berurutan
OSF dirancang secara khusus untuk tugas pembelajaran secara berurutan. Di antara tugas-tugas, hitung ulang SVD agar subruang yang dipertahankan mencerminkan bobot terbaru. Salah satu cara sederhana adalah membungkus ulang model dasar yang telah diperbarui dengan OSF lagi:
# Task 1: train on domain A with initial preserved subspace
r = 8 # initial effective rank to preserve
model = get_peft_model(base_model, OSFConfig(effective_rank=r))
train_task(model, task_1_data)
# Task 2: recompute SVD on updated weights and increase preserved subspace
base_model = model.unload() # unwrap base model without assuming internals
r += 4 # grow preserved subspace to include Task 1 knowledge
model = get_peft_model(base_model, OSFConfig(effective_rank=r))
train_task(model, task_2_data)
# Task 3: recompute again and expand preserved subspace further
base_model = model.unload()
r += 4
model = get_peft_model(base_model, OSFConfig(effective_rank=r))
train_task(model, task_3_data)Alokasi Anggaran untuk Urutan Tugas
Saat melatih pada urutan n tugas yang diketahui, satu strategi yang efektif adalah mengalokasikan kapasitas model secara bertahap untuk menyeimbangkan pembelajaran tugas baru sambil mempertahankan pengetahuan sebelumnya:
- Tugas 1: Gunakan kapasitas penuh (latih semuanya)
- Tugas 2: Bekukan 1/n dari kapasitas model, latih sisa (n-1)/n kapasitas
- Tugas 3: Bekukan 2/n dari kapasitas model, latih sisa (n-2)/n kapasitas
- Tugas n: Bekukan (n-1)/n kapasitas model, gunakan 1/n kapasitas untuk tugas akhir
Pendekatan ini memastikan setiap tugas mendapatkan kapasitas pembelajaran yang memadai sambil secara progresif mempertahankan lebih banyak pengetahuan dari tugas-tugas sebelumnya.
# Example: 4-task sequence with progressive budget allocation
n_tasks = 4
max_preserved_rank = 512 # Upper bound for preserved rank per target (heuristic)
for task_id in range(n_tasks):
# Freeze increases over time; trainable capacity shrinks
preserved_fraction = (task_id + 1) / n_tasks
preserved_rank = int(max_preserved_rank * preserved_fraction)
config = OSFConfig(
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
effective_rank=preserved_rank,
)
print(
f"Task {task_id + 1}: Preserving rank {preserved_rank} "
f"({preserved_fraction:.1%} of max_preserved_rank - {max_preserved_rank} frozen); trainable rank = min_dim - preserved_rank"
)
model = get_peft_model(base_model, config)
train_task(model, task_data[task_id])Praktik Terbaik
- Seleksi Rank Efektif: Mulai dengan
effective_rank=None(otomatis mengatur rank menjadi 50% dari dimensi bobot yang lebih kecil per modul target) dan sesuaikan berdasarkan kompleksitas tugas - Learning Rate: Gunakan learning rate yang lebih kecil (1e-5 hingga 1e-4) dibandingkan fine-tuning standar
- Pentingnya Tugas: Gunakan
rank_patternuntuk mengalokasikan lebih banyak kapasitas ke modul-modul kritis - Arsitektur Model: OSF bekerja paling baik dengan arsitektur transformer yang memiliki pemisahan yang jelas antara attention dan MLP
- Perencanaan Kapasitas: Untuk urutan tugas yang diketahui, gunakan alokasi anggaran progresif (pembekuan 1/n, 2/n, …, (n-1)/n) untuk menyeimbangkan plastisitas dan stabilitas
Pertimbangan Memori
OSF memodifikasi bobot secara in-place dan tidak menambahkan parameter, sehingga hemat memori:
# Memory usage remains close to base model
print(f"Base model parameters: {base_model.num_parameters():,}")
print(f"OSF model parameters: {osf_model.num_parameters():,}") # Similar countPenggunaan Lanjutan
Modul Target Kustom
Untuk model dengan arsitektur non-standar:
config = OSFConfig(
target_modules=["dense", "intermediate.dense"], # Custom layer names
effective_rank=12,
rank_pattern={"dense": 8, "intermediate.dense": 16}
)Integrasi dengan Metode Lain
OSF dapat dikombinasikan dengan teknik lain:
# Use with gradient checkpointing for memory efficiency
# note: use `model.gradient_checkpointing_enable()` for older Transformers versions
model.activation_checkpointing_enable()
# Apply weight decay selectively (regularizes low-rank factors to limit drift/overfitting in continual updates; keep small)
optimizer = torch.optim.AdamW([
{"params": [p for n, p in model.named_parameters() if "U_low" in n], "weight_decay": 0.01},
{"params": [p for n, p in model.named_parameters() if "S_low" in n], "weight_decay": 0.001},
{"params": [p for n, p in model.named_parameters() if "V_low" in n], "weight_decay": 0.01},
], lr=1e-4)Ikhtisar benchmark
API
OSFConfig
kelas peft.OSFConfig
< source >( task_type: Optional[Union[str, TaskType]] = Nonepeft_type: Optional[Union[str, PeftType]] = Noneauto_mapping: Optional[dict] = Nonepeft_version: Optional[str] = Nonebase_model_name_or_path: Optional[str] = Nonerevision: Optional[str] = Noneinference_mode: bool = Falseeffective_rank: Optional[Union[int, float]] = Nonetarget_modules: Optional[Union[list[str], str]] = Nonerank_pattern: Optional[dict[str, Union[int, float]]] = Noneinit_weights: Optional[bool] = Truemodules_to_save: Optional[list[str]] = Nonetarget_svd_config: Optional[dict[str, int]] = None )
Parameter
- effective_rank (int atau float, opsional) —
Rank SVD yang dipertahankan (subruang “tinggi”). Arah singular teratas-
effective_rankdibekukan dan dipertahankan di seluruh tugas; dimensi yang tersisa membentuk subruang rank-rendah yang dapat dilatih. Jika None, defaultnya adalah 50% dari dimensi bobot yang lebih kecil per modul target. Catatan: Ini berbeda dari r LoRA (rank yang dapat dilatih). Di OSF, rank yang dapat dilatih adalah min(weight.shape) - effective_rank. - target_modules (Union[list[str], str], opsional) — Nama-nama modul yang akan diterapkan OSF-nya. Bisa berupa daftar nama modul atau “all-linear”.
- rank_pattern (dict[str, int|float], opsional) — Kamus pola regex untuk menimpa effective_rank pada modul tertentu. Nilainya dapat berupa bilangan bulat absolut atau pecahan dalam (0, 1], yang ditafsirkan sebagai pecahan dari dimensi matriks yang lebih kecil per target.
Konfigurasi untuk Orthogonal Subspace Fine-tuning (OSF).
OSFModel
kelas peft.OSFModel
< source >( modelconfigadapter_namelow_cpu_mem_usage: bool = Falsestate_dict: dict[str, torch.Tensor] | None = None )
Penala minimal yang menerapkan Orthogonal Subspace Fine-tuning.
Fungsi Utilitas
Dekomposisi Bobot
Lakukan SVD pada weight dan bagi menjadi bagian beku dan bagian yang dapat dilatih.
Proyeksi Gradien
Proyeksikan gradien dari U_low dan V_low agar ortogonal terhadap ruang ber-rank tinggi.