PEFT documentation

OSF (ضبط دقيق في فضاء فرعي متعامد)

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.21.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

OSF (ضبط دقيق في فضاء فرعي متعامد)

التحسين الدقيق في فضاء فرعي متعامد (OSF) هو طريقة PEFT مصممة للتعلم المستمر، تفرض أن تكون تحديثات المعاملات متعامدة مع الاتجاهات المهمة السابقة. تتيح هذه المنهجية إجراء تحسين دقيق كامل مع منع النسيان الكارثي دون الحاجة إلى معاملات إضافية أو تخزين التدرجات السابقة.

ملخص الورقة البحثية هو:

تعاني عملية التعلّم المستمر في النماذج اللغوية الكبيرة (LLMs) من النسيان الكارثي، حيث يؤدي التكيف مع مهام جديدة إلى تدهور كبير في الأداء على المهام التي تم تعلّمها سابقًا. تعتمد الأساليب القائمة عادةً على تحديثات منخفضة الرتبة وفعّالة من حيث المعاملات، مما يحدّ من قدرة النموذج على التعبير ويضيف معاملات إضافية لكل مهمة، مما يؤدي إلى مشاكل في قابلية التوسع. لمعالجة هذه القيود، نقترح نهجًا جديدًا للضبط الدقيق الكامل المستمر يستفيد من التحليل المفرد التكيفي (SVD). يحدد منهجنا ديناميكيًا فضاءات فرعية منخفضة الرتبة للمعاملات الخاصة بكل مهمة، ويقيّد التحديثات لتكون متعامدة مع الاتجاهات الحرجة المرتبطة بالمهام السابقة، مما يقلّل التداخل بشكل فعّال دون زيادة في عبء المعاملات أو تخزين تدرجات المهام السابقة. قمنا بتقييم نهجنا على نطاق واسع على معايير التعلّم المستمر القياسية باستخدام كلا من نماذج المُشفّر-المفكّك (T5-Large) والنماذج المفكّكة فقط (LLaMA-2 7B)، عبر مهام متنوعة تشمل التصنيف، والتوليد، والاستدلال. تجريبيًا، يحقق منهجنا نتائج رائدة، بمتوسط دقة أعلى بنسبة تصل إلى 7% مقارنة بخطوط الأساس الحديثة مثل O-LoRA، ويحافظ بشكل ملحوظ على القدرات اللغوية العامة للنموذج، ودقة اتباع التعليمات، والسلامة طوال عملية التعلّم المستمر، من خلال تقليل النسيان إلى مستويات شبه معدومة. يوفر إطار SVD التكيفي لدينا توازنًا فعّالًا بين مرونة النموذج والاحتفاظ بالمعرفة، مقدّمًا حلًا عمليًا، ومبنيًا على أساس نظري، وقابلًا للتوسع حسابيًا لسيناريوهات التعلّم المستمر في النماذج اللغوية الكبيرة.

كيف يعمل OSF

يقوم OSF بتفكيك كل مصفوفة أوزان إلى مكوّنات عالية الرتبة (مثبّتة) ومكوّنات منخفضة الرتبة (قابلة للتدريب) باستخدام SVD:

W = U_high * S_high * V_high^T + U_low * S_low * V_low^T

حيث:

  • U_high, S_high, V_high: الحفاظ على الاتجاهات المهمة من المهام السابقة (مجمّدة)
  • U_low, S_low, V_low: تتيح التكيف مع مهام جديدة (قابلة للتدريب)

أثناء التدريب، تُسقط التدرّجات بحيث تكون متعامدة على الفضاء الجزئي ذي الرتبة العالية، مما يضمن عدم تعارض التحديثات مع المعرفة المكتسبة سابقًا.

الاستخدام الأساسي

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()

خيارات التهيئة

وحدات الهدف

يمكنك تحديد الوحدات المستهدفة بعدة طرق:

# 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 defaults

إعداد الرتبة الفعالة

تحكّم في الفروع الفرعية المحفوظة/القابلة للتدريب:

# 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/default

ملاحظة: قيمة effective_rank في OSF هي الرتبة المحفوظة (المجمّدة)، وليست الرتبة القابلة للتدريب. الرتبة القابلة للتدريب تساوي min(weight.shape) - effective_rank. وهذا يختلف عن r في LoRA، الذي يحدد الرتبة القابلة للتدريب مباشرةً.

نصائح التدريب للتعلم المستمر

التعلم التسلسلي للمهام

صُمم OSF خصيصًا لتعلم المهام بشكل تسلسلي. بين المهام، أعد حساب SVD بحيث يعكس الفضاء الجزئي المحفوظ أحدث الأوزان. إحدى الطرق البسيطة هي إعادة تغليف النموذج الأساسي المحدّث بـ OSF مرة أخرى:

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

تخصيص الميزانية لسلاسل المهام

عند التدريب على تسلسل معروف من n مهام، تُعدّ إحدى الاستراتيجيات الفعّالة هي تخصيص سعة النموذج تدريجياً لتحقيق التوازن بين تعلّم المهام الجديدة والحفاظ على المعرفة السابقة:

  • المهمة 1: استخدام السعة الكاملة (تدريب كل شيء)
  • المهمة 2: تجميد 1/n من سعة النموذج، وتدريب السعة المتبقية (n-1)/n
  • المهمة 3: تجميد 2/n من سعة النموذج، وتدريب السعة المتبقية (n-2)/n
  • المهمة n: تجميد (n-1)/n من سعة النموذج، واستخدام 1/n من السعة للمهمة النهائية

تضمن هذه الطريقة حصول كل مهمة على سعة تعلم كافية مع الحفاظ تدريجيًا على المزيد من المعرفة من المهام السابقة.

# 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])

أفضل الممارسات

  1. اختيار الرتبة الفعّالة: ابدأ بـ effective_rank=None (يُعيّن تلقائيًا الرتبة إلى 50% من بُعد الوزن الأصغر لكل وحدة هدف) وعدّلها بناءً على تعقيد المهمة
  2. معدل التعلم: استخدم معدلات تعلم أصغر (1e-5 إلى 1e-4) مقارنةً بالضبط الدقيق القياسي
  3. أهمية المهمة: استخدم rank_pattern لتخصيص سعة أكبر للوحدات الحرجة
  4. بنية النموذج: يعمل OSF بشكل أفضل مع بنيات التحويلات (transformers) التي تتميز بفصل واضح بين الانتباه (attention) وطبقات الشبكات العصبية متعددة الطبقات (MLP)
  5. تخطيط السعة: تسلسلات المهام المعروفة، استخدم تخصيص الميزانية التدريجي (تجميد 1/n، 2/n، …، (n-1)/n) لموازنة اللدونة والاستقرار

اعتبارات الذاكرة

يُعدّل OSF الأوزان في مكانها ولا يضيف أي معاملات، مما يجعله موفّرًا للذاكرة:

# 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 count

الاستخدام المتقدم

وحدات الهدف المخصصة

للنماذج ذات البنى غير القياسية:

config = OSFConfig(
    target_modules=["dense", "intermediate.dense"],  # Custom layer names
    effective_rank=12,
    rank_pattern={"dense": 8, "intermediate.dense": 16}
)

التكامل مع طرق أخرى

يمكن دمج OSF مع تقنيات أخرى:

# Use with gradient checkpointing for memory efficiency
model.gradient_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)

نظرة عامة على الاختبارات

واجهة برمجة التطبيقات

OSFConfig

فئة peft.OSFConfig

< >

( 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 )

المعاملات

  • effective_rank (int أو float، اختياري) — رتبة SVD المحفوظة (الفضاء الجزئي “العالي”). يتم تجميد اتجاهات القيم المفردة العليا الـeffective_rank وإبقاؤها عبر المهام؛ بينما تشكل الأبعاد المتبقية الفضاء الجزئي منخفض الرتبة القابل للتدريب. إذا كانت None، فإن القيمة الافتراضية تساوي 50% من بُعد الوزن الأصغر لكل وحدة هدف. ملاحظة: يختلف هذا عن r في LoRA (الرتبة القابلة للتدريب). في OSF، تكون الرتبة القابلة للتدريب هي min(weight.shape) - effective_rank.
  • target_modules (Union[list[str], str]، اختياري) — أسماء الوحدات التي سيتم تطبيق OSF عليها. يمكن أن تكون قائمة بأسماء الوحدات أو “all-linear”.
  • rank_pattern (dict[str, int|float]، اختياري) — قاموس يحتوي على أنماط تعبيرية منتظمة (regex) لتجاوز effective_rank لوحدات محددة. يمكن أن تكون القيم أعدادًا صحيحة مطلقة أو كسور ضمن المجال (0, 1]، وتُفسَّر ككسر من بُعد المصفوفة الأصغر لكل هدف.

إعدادات لتدريب دقيق في فضاء فرعي متعامد (OSF).

OSFModel

فئة peft.OSFModel

< >

( modelconfigadapter_namelow_cpu_mem_usage: bool = Falsestate_dict: dict[str, torch.Tensor] | None = None )

مُحسِّنٌ بسيطٌ يطبّق ضبط الدقة في فضاء فرعي متعامد.

دوال مساعدة

تفكيك الأوزان

peft.tuners.osf.utils.decompose_weight_matrix

< >

( weight: torch.Tensortop_k: int )

أجرِ تحليل القيم المفردة (SVD) لـweight وقسّمه إلى أجزاء مجمّدة وأجزاء قابلة للتدريب.

إسقاط التدرج

peft.tuners.osf.utils.project_gradient_to_orthogonal_space

< >

( svd_dict: dict[str, Any] )

U_low وV_low إلى أن تكون متعامدة مع فضاء الرتبة العالية.

Update on GitHub