بعد أن يفهم الانتشار العكسي كيف نحسب التدرّجات، يبقى السؤال: كيف نستخدمها لتحديث الأوزان؟ وكيف نمنع النموذج من الحفظ بدل التعلّم؟
Gradient Descent — القاعدة الأساسية
الفكرة بسيطة:
w_new = w_old - learning_rate · ∂L/∂w
- تحرّك الوزن في الاتجاه المعاكس للتدرّج (لأن التدرّج يشير إلى اتجاه زيادة L).
learning_rate(معدّل التعلّم) يتحكّم في حجم الخطوة.
مثال محسوب:
import torch
w = torch.tensor([1.0, 2.0], requires_grad=True)
loss = (w ** 2).sum() # L = w1² + w2² = 1 + 4 = 5
loss.backward()
print("التدرّجات:", w.grad) # [2, 4]
sgd = torch.optim.SGD([w], lr=0.1)
sgd.step()
print("بعد الخطوة:", w) # [0.8, 1.6]
w1: 1.0 - 0.1·2 = 0.8. w2: 2.0 - 0.1·4 = 1.6. بالتدريج نقترب من w=[0,0] الذي يصغّر L.
أنواع Optimizers
1. SGD — Stochastic Gradient Descent
أبسط optimizer: يستخدم عيّنة أو دفعة واحدة لكل تحديث.
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
"Stochastic" تعني عشوائي: بدل حساب التدرّج على كامل البيانات (مكلّف)، نُقدّره من دفعة صغيرة (batch). هذا يجعل التدريب أسرع وأكثر ضوضاءً، والضوضاء أحيانًا تساعد على تخطّي الحدّ الأدنى المحلّي.
2. SGD with Momentum
يضيف زخمًا للخطوات — مثل كرة تتدحرج في منحدر:
v = momentum · v + ∂L/∂w
w = w - lr · v
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
الفائدة:
- يُسرّع الحركة في الاتجاه المتّسق.
- يُقلّل التذبذب في الأودية الضيّقة.
- يساعد على تخطّي نقاط السرج (saddle points).
3. Adam — Adaptive Moment Estimation
الأكثر شيوعًا في التدريب العملي. يجمع:
- Momentum (المتوسّط المتحرك الأوّل للتدرّجات).
- RMSProp (تتبّع مربّع التدرّجات لتكييف معدّل التعلّم لكل وزن).
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
متى يتفوّق Adam؟
- بداية التدريب: يتقدّم سريعًا.
- شبكات Transformers: الخيار الافتراضي.
- بيانات ضوضائية: تكييف التعلّم لكل وزن يساعد.
متى قد لا يكون Adam الأفضل؟
- بعض مهام الرؤية الكلاسيكية مع SGD+momentum يتفوّق.
- مع learning rate خاطئ، Adam قد لا يتعافى.
- في بعض أبحاث الـ generalization، SGD+momentum أفضل على بيانات محدودة.
قاعدة عملية: ابدأ بـ Adam و
lr=1e-3. إذا لم يتقدّم، جرّب SGD+momentum معlr=0.01وmomentum=0.9. لا توجد وصفة واحدة تناسب كل الحالات.
4. AdaGrad و RMSProp (موجودان لكن أقلّ شيوعًا اليوم)
- AdaGrad: يُكيّف LR لكل وزن حسب تدرّجاته السابقة. يميل إلى LR صغيرة جدًا بسرعة.
- RMSProp: يصلح مشكلة AdaGrad بمتوسّط متحرّك أُسّي.
Learning Rate — أهمّ hyperparameter
LR صغير جدًا → التدريب يتباطأ أو يتجمّد. LR كبير جدًا → الخسارة تتذبذب أو تتباعد.
lr صغير جدًا → خطوات صغيرة بطيئة → قد لا يصل أبدًا
lr مناسب → تقدّم مستقر → حلّ جيد
lr كبير جدًا → يقفز فوق الحل → يتذبذب أو يتباعد
مخطّط شائع (مبسّط)
Loss
↑
│ \
│ \ lr كبير lr متوسّط lr صغير
│ \____________ ╲____________
│ \ ╲____________
│ \ ╲____
└──────────────────────────────────────────────→ steps
جدولة LR (Learning Rate Schedule)
أحيانًا نُقلّل LR تدريجيًا أثناء التدريب:
# في PyTorch
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
# كل 30 epoch، اضرب LR في 0.1
أو warmup: ابدأ بـ LR صغيرة، ثمّ ارفعها تدريجيًا — شائع في تدريب Transformers.
Batch Size — علاقتها بـ LR
قاعدة تقريبية: عند ضرب batch_size في k، يمكن ضرب LR في k أيضًا (لأن التدرّجات تُحسب على بيانات أكثر استقرارًا).
batch=32, lr=1e-3 → متوسّط
batch=256, lr=8e-3 → (تقريبًا نفس سرعة التدريب، تدرّجات أكثر استقرارًا)
هذه قاعدة تقريبية وليست دقيقة. التجربة العملية هي الحَكَم.
Regularization — منع overfitting
إذا كان النموذج يحفظ بيانات التدريب بدل تعلّم الأنماط العامة، فالحلول:
1. L2 Regularization (Weight Decay)
يضيف مُصطلحًا للخسارة يعاقب الأوزان الكبيرة:
L_total = L_data + λ · Σ wᵢ²
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4)
weight_decay في PyTorch يطبّق L2 penalty على الأوزان (تقنيًا decoupled، لكن النتيجة قريبة).
2. L1 Regularization
يعاقب القيمة المطلقة للأوزان:
L_total = L_data + λ · Σ |wᵢ|
يتميّز بأنه يدفع الأوزان غير المفيدة إلى صفر بالضبط (sparsity). أقلّ شيوعًا من L2.
3. Dropout
أثناء التدريب، يُعطّل نسبة عشوائية من الخلايا في كل خطوة:
import torch.nn as nn
layer = nn.Sequential(
nn.Linear(128, 64),
nn.ReLU(),
nn.Dropout(p=0.3), # 30% من الخلايا معطّلة عشوائيًا
)
لماذا يعمل؟ يجبر الشبكة على عدم الاعتماد على خلية واحدة، فيتعلّم تمثيلات أكثر قوة. أثناء التقييم (model.eval())، لا يُطبَّق Dropout.
4. Early Stopping
توقّف التدريب حين يبدأ الأداء على validation set بالتدهور، حتى لو loss على التدريب يستمرّ في النزول.
best_val_loss = float("inf")
patience = 5
counter = 0
for epoch in range(max_epochs):
# ... تدريب
val_loss = evaluate(model, val_loader)
if val_loss < best_val_loss:
best_val_loss = val_loss
torch.save(model.state_dict(), "best.pt")
counter = 0
else:
counter += 1
if counter >= patience:
print("Early stopping!")
break
تذكّر: لا تقيّم على test set أثناء اختيار النموذج. استخدم validation set. الفصل بين train/val/test شرح في تقسيم البيانات و Cross-Validation.
5. (مذكور للاكتمال) Data Augmentation
تقنيًا ليست regularization، لكنها تمنع overfitting بنفس الفعالية في مهام الرؤية: تدوير، قلب، قصّ عشوائي للصور.
وصفة عملية
import torch
import torch.nn as nn
model = nn.Sequential(
nn.Linear(784, 256),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(256, 10),
)
# Adam افتراضي + weight decay
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4)
criterion = nn.CrossEntropyLoss()
for epoch in range(50):
model.train() # يُفعّل Dropout
for x, y in train_loader:
optimizer.zero_grad() # تصفير التدرّجات القديمة
y_hat = model(x)
loss = criterion(y_hat, y)
loss.backward() # حساب التدرّجات
optimizer.step() # تحديث الأوزان
model.eval() # يُعطّل Dropout
with torch.no_grad():
val_loss = evaluate(model, val_loader)
🔍 تدريب كامل وآمن في Training Loop في PyTorch.
كيف تختار؟
| الحالة | اقتراح |
|---|---|
| نموذج صغير/متوسّط، بيانات كافية | Adam, lr=1e-3 |
| مشاكل رؤية كلاسيكية | SGD + momentum, lr=0.01 |
| Transformers | Adam (أو AdamW)، lr=1e-4 → 5e-5 |
| Overfitting واضح | Dropout + weight_decay |
| Validation loss يرتفع | Early stopping |
أخطاء شائعة
- "Adam دائمًا يتقارب أسرع": ليس بالضرورة. بعض النماذج تفضّل SGD. جرّب وقِس.
- "lr صغير = تعلّم آمن": lr صغير جدًا قد يتجمّد التدريب تمامًا.
- "Dropout يُحسّن دائمًا": إذا كان النموذج underfitting أصلًا، Dropout يزيد المشكلة.
- "Early stopping = تخلّي عن التدريب": لا، هو استخدام validation لاختيار نقطة جيدة قبل overfitting.
- "weight_decay = L2 regularization الكلاسيكية": تقنيًا مختلف قليلًا في PyTorch (decoupled)، لكن النتيجة متشابهة في معظم الحالات.
الخطوات التالية
- CNN — الشبكات العصبية الالتفافية — تطبيق هذه المفاهيم على الصور.
- Training Loop في PyTorch — تجميع كل ما سبق.
- Overfitting و Bias-Variance — لماذا نحتاج Regularization أصلًا.
- معمارية Transformers — تحسينات حديثة.
🔍 لاختيار hyperparameter عمليًا، راجع Model Selection و Tuning (المبادئ نفسها تنطبق على PyTorch).