الفصل 1: نهج التخصيص الدقيق التقليدي
تحديث جميع معلمات النموذج
يتضمن التخصيص الدقيق التقليدي تحديث كل معلمة قابلة للتدريب في النموذج أثناء التدريب. يوفر هذا أقصى قدر من المرونة لتكييف النماذج مع المهام الجديدة.
كيف يعمل التخصيص الدقيق الكامل
حلقة التدريب
- التمرير الأمامي: يتدفق البيانات عبر النموذج بأكمله
- حساب الخسارة: مقارنة التنبؤ بالهدف
- التمرير الخلفي: حساب التدرجات لجميع المعلمات
- تحديث الأوزان: تطبيق التدرجات لتحديث جميع الأوزان
- التكرار: الاستمرار حتى التقارب
مثال تدريب كامل
import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
TrainingArguments,
Trainer,
DataCollatorForLanguageModeling,
)
from datasets import load_dataset
# تحميل النموذج والمحول
model_name = "meta-llama/Llama-3.1-8B"
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
# تحميل النموذج - جميع المعلمات قابلة للتدريب افتراضيًا
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16, # استخدام bf16 لكفاءة الذاكرة
device_map="auto",
)
# التحقق من أن جميع المعلمات قابلة للتدريب
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
total_params = sum(p.numel() for p in model.parameters())
print(f"Trainable: {trainable_params:,} / {total_params:,} = 100%")
# إعداد مجموعة البيانات
dataset = load_dataset("databricks/dolly-15k", split="train[:1000]")
def format_instruction(example):
return {
"text": f"### Instruction:\n{example['instruction']}\n\n### Response:\n{example['response']}"
}
dataset = dataset.map(format_instruction)
def tokenize(example):
return tokenizer(
example["text"],
truncation=True,
max_length=512,
padding="max_length",
)
tokenized_dataset = dataset.map(tokenize, remove_columns=dataset.column_names)
# تكوين التدريب
training_args = TrainingArguments(
output_dir="./llama-full-ft",
num_train_epochs=3,
per_device_train_batch_size=1, # محدود بالذاكرة
gradient_accumulation_steps=16, # محاكاة حجم الدفعة 16
learning_rate=2e-5,
weight_decay=0.01,
warmup_ratio=0.03,
logging_steps=10,
save_strategy="epoch",
bf16=True, # استخدام bfloat16
gradient_checkpointing=True, # توفير الذاكرة
optim="adamw_torch_fused", # محسن فعال
)
# إنشاء المدرب
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset,
data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=False),
)
# تدريب
trainer.train()
# حفظ
model.save_pretrained("./llama-full-ft-final")
tokenizer.save_pretrained("./llama-full-ft-final")
شرح المكونات الرئيسية
معدل التعلم
learning_rate = 2e-5 # النطاق الشائع: 1e-5 إلى 5e-5
للتخصيص الدقيق الكامل، استخدم معدلات تعلم أقل من PEFT:
- مرتفع جدًا: يتباعد النموذج أو ينسى التدريب المسبق
- منخفض جدًا: التدريب بطيء، قد لا يتكيف بشكل كافٍ
اضمحلال الوزن
weight_decay = 0.01 # تنظيم لمنع الإفراط في التخصيص
يمنع اضمحلال الوزن النموذج من الإفراط في التخصيص عن طريق معاقبة الأوزان الكبيرة.
التسخين
warmup_ratio = 0.03 # 3% من خطوات التدريب
زيادة معدل التعلم تدريجيًا في البداية لتحقيق استقرار التدريب.
التحقق من التدرج
gradient_checkpointing = True # مبادلة الحساب بالذاكرة
إعادة حساب التنشيطات أثناء التمرير الخلفي بدلاً من تخزينها—يوفر حوالي 30% من الذاكرة.
اختيارات المحسن
| المحسن | الذاكرة | السرعة | الجودة |
|---|---|---|---|
| AdamW | عالية | سريع | الأفضل |
| Adam 8-bit | متوسطة | متوسطة | جيدة |
| SGD | منخفضة | بطيء | يتطلب ضبط |
| Adafactor | منخفضة | متوسطة | جيدة |
# AdamW القياسي
optim = "adamw_torch"
# AdamW المدمج (أسرع)
optim = "adamw_torch_fused"
# Adam 8-bit (ذاكرة أقل)
optim = "adamw_8bit"
# Adafactor (بدون حالات زخم)
optim = "adafactor"
ديناميكيات التدريب
منحنى الخسارة
Epoch 1: انخفاض سريع في خسارة التدريب
(النموذج يتكيف مع البيانات الجديدة)
Epoch 2: استقرار خسارة التدريب
(مراقبة خسارة التحقق من الإفراط في التخصيص)
Epoch 3: احتمال الإفراط في التخصيص
(خسارة التدريب لا تزال تنخفض، قد تزيد خسارة التحقق)
مراقبة التدريب
# استخدام Weights & Biases
training_args = TrainingArguments(
# ... معلمات أخرى ...
report_to="wandb",
run_name="llama-full-ft-experiment-1",
)
المقاييس الرئيسية للمراقبة:
- خسارة التدريب: يجب أن تنخفض
- خسارة التحقق: يجب أن تنخفض ولكن راقب التباعد عن خسارة التدريب
- معيار التدرج: قد تشير الارتفاعات إلى عدم استقرار
- معدل التعلم: تحقق من عمل التسخين والانخفاض
التدريب بدقة مختلطة
لماذا استخدام الدقة المختلطة؟
# نصف الذاكرة، غالبًا تدريب أسرع
bf16 = True # مفضل للبطاقات الرسومية الأحدث (Ampere+)
# أو
fp16 = True # للبطاقات الرسومية الأقدم
| الدقة | الذاكرة | النطاق | الاستقرار |
|---|---|---|---|
| float32 | 4 بايت | كامل | الأعلى |
| bfloat16 | 2 بايت | كامل | عالي |
| float16 | 2 بايت | محدود | متوسط |
لدى Float16 نطاق أضيق ويمكن أن يسبب تجاوز/تحت التدفق. يحافظ BFloat16 على نطاق float32 مع تقليل الدقة، مما يجعله أكثر استقرارًا.
الحفظ والتحميل
أثناء التدريب (نقاط التحقق)
training_args = TrainingArguments(
save_strategy="steps",
save_steps=500,
save_total_limit=3, # الاحتفاظ بآخر 3 نقاط تحقق فقط
)
بعد التدريب
# حفظ النموذج الكامل
model.save_pretrained("./final-model")
tokenizer.save_pretrained("./final-model")
# لاحقًا، تحميله
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("./final-model")
مزايا التخصيص الدقيق الكامل
أقصى تخصيص
يمكن تعديل جميع المعلمات لمهمتك.
جودة محتملة أعلى
لا توجد قيود من الأوزان المجمدة.
البساطة
لا حاجة لتكوين محولات.
إخراج مدمج
ملف نموذج واحد، لا يوجد عبء محول في الاستدلال.
العيوب
متطلبات ذاكرة عالية
الحاجة إلى تخزين النموذج، التدرجات، وحالات المحسن.
خطر النسيان الكارثي
يمكن أن يفقد المعرفة المدربة مسبقًا.
مكلف
يتطلب موارد GPU كبيرة.
تدريب بطيء
يجب تحديث كل معلمة.
متى يجب استخدام التخصيص الدقيق الكامل
| حالة الاستخدام | التوصية |
|---|---|
| الحاجة إلى جودة قصوى | ✅ تخصيص دقيق كامل |
| محدودية الموارد | ❌ استخدم PEFT |
| التجريب السريع | ❌ استخدم PEFT |
| الإنتاج على نطاق واسع | ⚠️ النظر في التوازنات |
| البحث/المقارنة | ✅ تخصيص دقيق كامل |
النقاط الرئيسية
✅ التخصيص الدقيق الكامل يحدث لكل معلمات النموذج
✅ يتطلب ذاكرة GPU كبيرة (النموذج + التدرجات + المحسن)
✅ استخدم الدقة المختلطة والتحقق من التدرج لتقليل الذاكرة
✅ معدلات تعلم أقل من PEFT (1e-5 إلى 5e-5)
✅ مراقبة الإفراط في التخصيص مع خسارة التحقق
✅ الأفضل لأقصى تخصيص عندما تسمح الموارد
الخطوات التالية
تابع إلى الفصل 2: متطلبات الحوسبة لفهم الاحتياجات الدقيقة للذاكرة والحوسبة.
تحقق سريع
قبل المتابعة، تأكد من أنك تستطيع الإجابة على:
- ما هي المكونات الأربعة الرئيسية المخزنة في ذاكرة GPU أثناء التدريب؟
- لماذا يفضل bfloat16 غالبًا على float16؟
- ما هو نطاق معدل التعلم النموذجي للتخصيص الدقيق الكامل؟