إنتقل إلى المحتوى الرئيسي

الفصل 1: مقدمة في PEFT

جعل التخصيص الدقيق متاحًا​

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


المشكلة التي يحلها PEFT​

تحديات التخصيص الكامل​

  • نموذج 7B: يحتاج إلى ~60-80GB VRAM للتخصيص الكامل
  • نموذج 13B: يحتاج إلى ~110-160GB VRAM
  • نموذج 70B: يحتاج إلى ~600GB+ VRAM

هذا يمنع معظم الممارسين من تخصيص النماذج الأكبر.


حل PEFT​

الفكرة الرئيسية​

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

كيف يعمل​

بدلاً من تحديث جميع المعلمات:

# التخصيص الكامل (جميع المعلمات)
for param in model.parameters():
param.requires_grad = True # تحديث كل شيء

# PEFT (فقط المحولات)
for name, param in model.named_parameters():
param.requires_grad = False # تجميد النموذج الأساسي

# إضافة محول صغير قابل للتدريب
adapter = LoRAAdapter(rank=16) # ~0.1% من المعلمات

فوائد PEFT​

1. تقليل الذاكرة بشكل كبير​

النموذجالتخصيص الكاملPEFTالتوفير
7B~80GB~6-14GB82-92%
13B~160GB~10-26GB84-94%
70B~600GB~48-140GB77-92%

2. تدريب أسرع​

التخصيص الكامل: 100% من المعلمات محدثة في كل خطوة
PEFT: أقل من 1% من المعلمات محدثة في كل خطوة
→ حساب تدرج أسرع
→ تحديث أوزان أسرع
→ عرض نطاق ذاكرة أقل

3. لا يوجد نسيان كارثي​

# النموذج الأساسي مجمد = المعرفة الأصلية محفوظة
base_weights = model.get_base_weights() # لم يتم تعديلها أبدًا
adapter_weights = model.get_adapter_weights() # فقط هذه تتغير

4. محولات متعددة​

# نموذج أساسي واحد، محولات متعددة لمهام مختلفة
model.load_adapter("customer-support") # المهمة 1
model.load_adapter("code-generation") # المهمة 2
model.load_adapter("summarization") # المهمة 3
# فقط قم بتبديل المحولات أثناء التشغيل!

المفاهيم الأساسية​

المعلمات المجمدة​

المعلمات التي لا تتلقى تحديثات تدرج أثناء التدريب.

# تجميد معلمة
param.requires_grad = False

# تحقق من المعلمات القابلة للتدريب
for name, param in model.named_parameters():
if param.requires_grad:
print(f"Trainable: {name}")

المعلمات القابلة للتدريب​

فقط المجموعة الصغيرة من المعلمات التي يتم تحديثها أثناء تدريب PEFT.

المحولات​

وحدات إضافية تضاف إلى النموذج المجمد وتحتوي على المعلمات القابلة للتدريب.


مكتبة PEFT​

توفر مكتبة PEFT من Hugging Face وصولًا موحدًا إلى جميع طرق PEFT الرئيسية:

from peft import (
LoraConfig,
PrefixTuningConfig,
PromptTuningConfig,
IA3Config,
AdaLoraConfig,
get_peft_model,
PeftModel,
)

# تكوين PEFT
peft_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj"],
)

# تطبيق على النموذج
model = get_peft_model(base_model, peft_config)

# تحقق من المعلمات القابلة للتدريب
model.print_trainable_parameters()
# Output: trainable params: 4,194,304 || all params: 6,742,609,920 || trainable%: 0.0622

الوظائف الرئيسية​

الوظيفةالغرض
get_peft_model()تغليف النموذج الأساسي مع PEFT
print_trainable_parameters()عرض عدد القابلة للتدريب
save_pretrained()حفظ المحول فقط
merge_and_unload()دمج المحول في الأساسي
load_adapter()تحميل محول محفوظ

مقارنة المعلمات​

from transformers import AutoModelForCausalLM
from peft import LoraConfig, get_peft_model

# تحميل النموذج الأساسي
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.1-8B")

# حساب المعلمات الأساسية
total_params = sum(p.numel() for p in model.parameters())
print(f"Total parameters: {total_params:,}") # ~8,000,000,000

# تطبيق LoRA
lora_config = LoraConfig(r=16, lora_alpha=32, target_modules=["q_proj", "v_proj"])
model = get_peft_model(model, lora_config)

# حساب القابلة للتدريب
trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"Trainable: {trainable:,}") # ~4,000,000
print(f"Percentage: {100 * trainable / total_params:.4f}%") # ~0.05%

فوائد التخزين​

حفظ المحول فقط​

# النموذج الكامل: ~15GB (نموذج 7B في fp16)
model.save_pretrained("./full-model")

# محول LoRA فقط: ~10-50MB
model.save_pretrained("./lora-adapter", save_embedding_layers=False)

محولات متعددة = تخزين ضئيل​

النموذج الأساسي: 15GB (مشترك)
المحول A: 20MB (المهمة 1)
المحول B: 20MB (المهمة 2)
المحول C: 20MB (المهمة 3)
الإجمالي: 15.06GB لثلاثة نماذج متخصصة

مقابل التخصيص الكامل: 45GB لثلاثة نماذج منفصلة

مثال سريع​

إكمال تدريب PEFT في أقل من 50 سطرًا:

from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model
from trl import SFTTrainer
from datasets import load_dataset

# تحميل النموذج والمحول
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.1-8B")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B")
tokenizer.pad_token = tokenizer.eos_token

# تكوين LoRA
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
lora_dropout=0.05,
task_type="CAUSAL_LM",
)

# تطبيق PEFT
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()

# تحميل مجموعة البيانات
dataset = load_dataset("databricks/dolly-15k", split="train[:1000]")

# تدريب
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
dataset_text_field="text",
max_seq_length=512,
)
trainer.train()

# حفظ المحول
model.save_pretrained("./my-lora-adapter")

النقاط الرئيسية​

✅ يدرب PEFT أقل من 1% من المعلمات مع الحفاظ على الجودة

✅ توفير في الذاكرة بنسبة 80-95% مقارنة بالتخصيص الكامل

✅ تبقى أوزان النموذج الأساسي مجمدة، مما يمنع النسيان

✅ يمكن لمحولات متعددة مشاركة نموذج أساسي واحد

✅ توفر مكتبة PEFT وصولًا موحدًا إلى جميع الطرق

✅ ملفات المحولات صغيرة (~10-50MB) مقابل النماذج الكاملة (~15GB+)


الخطوات التالية​

تابع إلى الفصل 2: PEFT مقابل التخصيص الكامل لفهم التنازلات بالتفصيل.


تحقق سريع​

قبل المتابعة، تأكد من أنك تستطيع الإجابة على:

  1. ما هي النسبة المئوية للمعلمات التي يدربها PEFT عادةً؟
  2. لماذا لا يسبب PEFT نسيانًا كارثيًا؟
  3. ما هي الوظيفة الرئيسية لإنشاء نموذج PEFT؟