تخصصات التعلم العميق

تحسين أداء الشبكات العصبية

الدرس الثاني: تحسين أداء الشبكات العصبية — دليل شامل للمبتدئين
Lesson 02 · Improving Deep Neural Networks

الدرس الثاني: تحسين أداء الشبكات العصبية

بعد أن تعلّمت كيف تُبنى وتُدرَّب شبكة عصبية، يأتي السؤال التالي: كيف أجعلها أفضل؟ هذا الدليل يشرح 9 محاور عملية — من اختيار قيم البداية للأوزان، إلى التنظيم (Regularization)، والمحسّنات، وجدولة معدل التعلّم — بأسلوب بسيط جدًا مع تشبيهات من الحياة وأمثلة رقمية وكود PyTorch.

✍ عبدالرحمن الرفاعي
9 محاور
مبتدئون
أمثلة + كود
01 المحور الأول

Initialization — تهيئة الأوزان

عندما تُنشئ شبكة عصبية جديدة، كل وزن (weight) وكل انحياز (bias) يحتاج قيمة بداية. السؤال: من أين نأتي بهذه القيم؟

تشبيه من الحياة

تخيّل أنك تبدأ سباقًا من نقطة البداية. إذا بدأت قريبًا جدًا من خط النهاية (أوزان كبيرة) ستتجاوز الهدف وتضيع. وإذا بدأت بعيدًا جدًا (أوزان صفر أو متطابقة) لن تتحرك أبدًا أو ستتحرك الجميع بنفس الاتجاه. التهيئة الصحيحة = نقطة بداية ذكية.

لماذا لا نبدأ بأصفار؟

إذا جعلت كل الأوزان = 0، كل عصبون في الطبقة نفسها سيحسب نفس القيمة، ويأخذ نفس gradient، ويتحدّث بنفس الطريقة — يبقون متطابقين للأبد (symmetry problem). لذلك نحتاج عشوائية.

Random Initialization — التهيئة العشوائية

الفكرة البسيطة: اختر أرقامًا عشوائية صغيرة لكل وزن.

W ~ Uniform(-0.01, 0.01)   أو   W ~ Normal(0, 0.01)
مثال رقمي

شبكة بسيطة: طبقة دخل (3 ميزات) → طبقة مخفية (2 عصبونات).

  • الوزن W بحجم 3×2 — نملأه بأرقام عشوائية مثل: [[0.005, -0.008], [0.003, 0.012], [-0.007, 0.001]]
  • كل عصبون يبدأ مختلفًا → يتعلّم أشياء مختلفة ✓

المشكلة: إذا كانت الشبكة عميقة (10+ طبقات)، الأرقام العشوائية الصغيرة جدًا تسبب Vanishing Gradient، والكبيرة جدًا تسبب Exploding Gradient. هنا يأتي Xavier و He.

Xavier Initialization (Glorot)

اقترح Xavier Glorot (2010): اختر التباين بحيث يبقى تباين الإشارة ثابتًا بين الطبقات — لا تكبر ولا تصغر.

Xavier:   W ~ Uniform( -√(6/(n_in + n_out)), √(6/(n_in + n_out)) )

حيث n_in = عدد مدخلات الطبقة، n_out = عدد مخرجاتها.

مثال رقمي — Xavier

طبقة: 100 مدخل → 50 مخرج. الحد = √(6/(100+50)) = √(6/150) ≈ 0.2

كل وزن يُسحب عشوائيًا من المجال [-0.2, +0.2]. مناسب مع Sigmoid و Tanh.

He Initialization

اقترح Kaiming He (2015) لدوال ReLU: ReLU تقطع النصف السالب (يصبح صفر)، فيفقد التباين نصفه تقريبًا. لذلك نحتاج تباينًا أكبر:

He:   W ~ Normal(0, √(2 / n_in))
مثال رقمي — He

طبقة: 256 مدخل. الانحراف المعياري = √(2/256) = √(0.0078) ≈ 0.088

أوزان عشوائية حول 0 بانحراف ~0.088 — أكبر من Xavier لأن ReLU «يقتل» نصف الإشارات.

جدول مقارنة سريع
الطريقةمتى تستخدمها؟دالة التفعيل
Random صغيرشبكات ضحلة (1–2 طبقة) فقطأي
Xavier / Glorotشبكات متوسطة العمقSigmoid, Tanh
He / Kaimingالخيار الافتراضي اليومReLU, LeakyReLU, GELU
# PyTorch — التهيئة التلقائية import torch.nn as nn # He (افتراضي لـ Linear + ReLU) layer = nn.Linear(256, 128) # يستخدم Kaiming تلقائيًا مع ReLU # تهيئة يدوية nn.init.kaiming_normal_(layer.weight, mode='fan_in', nonlinearity='relu') nn.init.zeros_(layer.bias) # Xavier لـ Tanh layer2 = nn.Linear(100, 50) nn.init.xavier_uniform_(layer2.weight)
02 المحور الثاني

Regularization — التنظيم

النموذج القوي جدًا يحفظ بيانات التدريب حرفيًا (مثل طالب يحفظ الإجابات بدل فهم المادة) — هذا يسمى Overfitting. التنظيم = تقنيات تجعل النموذج «أبسط» ويتعمّم أفضل على بيانات جديدة.

تشبيه من الحياة

طالب يحفظ 1000 سؤال بالحرف → يجيبها ممتاز في الامتحان التدريبي، لكن يفشل في امتحان جديد بصياغة مختلفة. التنظيم = أن يفهم القواعد العامة بدل الحفظ.

L1 Regularization

نضيف لدالة الخسارة مجموع القيم المطلقة للأوزان:

Loss_total = Loss_original + λ · Σ|w_i|

λ (لامدا) = قوة التنظيم. كلما كبرت λ، الأوزان تصغر أكثر.

النتيجة: كثير من الأوزان تصبح بالضبط صفر → النموذج يختار ميزات مهمة فقط (feature selection تلقائي).

مثال بسيط

أوزان قبل L1: [0.8, -0.3, 0.05, 0.02, -0.7]. بعد تدريب مع L1 قوي: [0.6, -0.2, 0, 0, -0.5] — الأوزان الصغيرة اختفت.

L2 Regularization

نضيف مجموع مربعات الأوزان:

Loss_total = Loss_original + λ · Σ(w_i)²

لا يجعل الأوزان صفرًا بالضبط، لكن يجعلها صغيرة — يمنع وزنًا واحدًا من السيطرة على القرار.

مثال رقمي

وزن واحد = 10. مساهمته في L2 = 10² = 100 — عقوبة كبيرة! النموذج يُجبر على تقليله إلى مثلاً 0.5 (مساهمة = 0.25 فقط).

Weight Decay

في المحسّنات الحديثة، L2 يُطبَّق غالبًا كـ Weight Decay مباشرة في خطوة التحديث:

w_new = w_old - lr · gradient - lr · λ · w_old

كل خطوة، الأوزان «تذبل» قليلًا نحو الصفر. في PyTorch:

optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-4) # weight_decay=1e-4 يعادل L2 مع λ=1e-4

ملاحظة مهمة: مع Adam العادي، weight_decay ≠ L2 بالضبط. لذلك ظهر AdamW (نشرحه في المحور الثالث) الذي يفصل بينهما بشكل صحيح.

Dropout

أثناء التدريب، نُطفئ عشوائيًا نسبة من العصبونات (مثلاً 50%) في كل خطوة. كل عصبون له احتمال p أن يُعطَّل.

Dropout = 50% — نصف العصبونات تُطفأ عشوائيًا ● = نشط  |  ✕ = مطفأ (يُعاد تفعيله في الخطوة التالية) أثناء الاختبار: كل العصبونات نشطة (مع scaling)
Dropout يجبر الشبكة على عدم الاعتماد على عصبون واحد
تشبيه

فريق كرة قدم: في كل مباراة تدريب، نصف اللاعبين «إصابات وهمية» — الباقون يتعلمون اللعب بدونهم. النتيجة: لا يعتمد الفريق على نجم واحد.

model = nn.Sequential( nn.Linear(784, 256), nn.ReLU(), nn.Dropout(p=0.5), # يُطفئ 50% أثناء التدريب فقط nn.Linear(256, 10) )

Early Stopping

نراقب validation loss أثناء التدريب. إذا بدأ يرتفع (بينما train loss ما زال ينخفض) = overfitting. نتوقف مبكرًا ونحفظ أفضل نموذج.

مثال — متى نتوقف؟
  • Epoch 10: val_loss = 0.35 ← أفضل حتى الآن ✓
  • Epoch 15: val_loss = 0.38 ← بدأ يرتفع
  • Epoch 20: val_loss = 0.42 ← يرتفع أكثر
  • القرار: توقف عند Epoch 10 واحفظ تلك الأوزان (patience = 5 epochs)

L1

أوزان تختفي (sparse). مفيد لاختيار الميزات.

L2 / Weight Decay

أوزان صغيرة. الأكثر شيوعًا في التطبيق.

Dropout

يُطفئ عصبونات عشوائيًا. قوي للطبقات الكبيرة.

Early Stopping

توقف عندما val_loss يتدهور. مجاني وفعّال!

03 المحور الثالث

Optimization Algorithms — خوارزميات التحسين

بعد حساب الـ gradient، كيف نحدّث الأوزان؟ SGD البسيط هو الأساس — لكن المحسّنات المتقدمة تجعل التدريب أسرع وأكثر استقرارًا.

تشبيه — النزول من جبل ضبابي

أنت في قمة جبل (loss عالي) وتريد الوصول للوادي (loss منخفض). Gradient = اتجاه الانحدار الأشد. المحسّن = كيف تمشي: بخطوات صغيرة ثابتة؟ بزخم؟ بخطوات تتكيف مع التضاريس؟

SGD — Stochastic Gradient Descent

في كل خطوة، نحسب gradient على batch صغير (مثلاً 32 مثال) بدل كل البيانات:

w_new = w_old - lr · ∇Loss_batch
مثال رقمي — خطوة SGD واحدة

وزن w = 2.0، gradient = 0.5، learning rate = 0.1

w_new = 2.0 - 0.1 × 0.5 = 1.95

المشكلة: المسار متذبذب (zigzag) خاصة في الوديان الضيقة. الحل: Momentum.

Momentum

نضيف «زخمًا» — كالكرة المتدحرجة: تتسارع في الاتجاه المتسق وتتباطأ عند التذبذب:

v = β · v + ∇Loss    (β ≈ 0.9)
w_new = w_old - lr · v
مثال — لماذا Momentum أفضل؟

بدون Momentum: gradient يتذبذب [+0.5, -0.4, +0.6, -0.5] → تقدم بطيء.

مع Momentum (β=0.9): المتجهات المتناقضة تُلغى، المتسقة تتراكم → مسار أسرع وأنعم نحو الحل.

RMSProp

يتكيف معدل التعلّم لكل وزن حسب تاريخ gradients. الأوزان التي gradientsها كبيرة → خطوات أصغر. الصغيرة → خطوات أكبر:

s = β · s + (1-β) · (∇Loss)²
w_new = w_old - lr / √(s + ε) · ∇Loss

ممتاز للشبكات العميقة و RNN — يحل مشكلة gradients المتفاوتة الأحجام.

Adam — Adaptive Moment Estimation

يجمع Momentum (متوسط gradient) + RMSProp (متوسط gradient²). الخيار الافتراضي لمعظم المشاريع:

m = β₁·m + (1-β₁)·∇Loss   (الزخم)
v = β₂·v + (1-β₂)·(∇Loss)²   (التكيف)
w_new = w_old - lr · m̂ / (√v̂ + ε)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))

β₁=0.9, β₂=0.999, ε=1e-8 — قيم افتراضية تعمل جيدًا في أغلب الحالات.

AdamW

يصلح مشكلة Adam مع Weight Decay: يفصل تحديث الأوزان عن تقليل الأوزان (decoupled weight decay). أفضل للتنظيم مع Adam — المعيار في Transformers و LLMs.

optimizer = torch.optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)

Nadam — Nesterov + Adam

يجمع Adam مع Nesterov Momentum — «انظر للأمام» قبل القفز: يحسب gradient عند النقطة المتوقعة بعد خطوة الزخم. أحيانًا أسرع تقاربًا من Adam في بداية التدريب.

أي محسّن أختار؟
المحسّنمتى؟ملاحظة
SGD + MomentumCNN كبيرة، عندما تريد أقصى دقةيحتاج ضبط lr بعناية
Adamالبداية الافتراضية، معظم المشاريعسريع ويعمل «من الصندوق»
AdamWTransformers, NLP, مع weight decayالأفضل مع التنظيم
RMSPropRNN, بيانات تسلسليةأقل شيوعًا من Adam اليوم
Nadamتجارب — بديل لـ Adamليس افتراضيًا في معظم الأطر
04 المحور الرابع

Hyperparameter Tuning — ضبط المعاملات الفائقة

Parameters = الأوزان (يتعلّمها النموذج). Hyperparameters = إعدادات أنت تختارها قبل التدريب. اختيارها الخاطئ = نموذج بطيء أو فاشل.

Learning Rate — معدل التعلّم

أهم hyperparameter على الإطلاق. يحدد حجم الخطوة في كل تحديث.

كبير جدًا (0.1+): Loss يتذبذب أو ينفجر — يتجاوز الحل.
صغير جدًا (1e-6): Loss ينخفض ببطء شديد — قد لا يصل للحل.
مناسب (1e-3 إلى 1e-4): Loss ينخفض بسلاسة.
نصيحة: ابد بـ 0.001 (Adam) أو 0.01 (SGD) واضبط.
تجربة عملية

على MNIST مع Adam:

  • lr = 0.1 → Loss يقفز: 2.3, 0.8, 5.1, 1.2... (غير مستقر)
  • lr = 0.001 → Loss: 2.3 → 0.5 → 0.15 → 0.08 (ممتاز)
  • lr = 0.00001 → Loss: 2.3 → 2.1 → 2.0 → 1.95 (بطيء جدًا)

Batch Size — حجم الدفعة

كم مثالًا نعالج قبل تحديث الأوزان؟

صغير (16–32)

تحديثات أكثر = تنوع أكبر. أبطأ لكن أحيانًا يتعمّم أفضل. يحتاج GPU أصغر.

متوسط (64–128)

توازن جيد — الأكثر شيوعًا.

كبير (256–1024)

أسرع على GPU. gradients أقل ضوضاء. قد يحتاج lr أكبر.

قاعدة: عند مضاعفة batch size، جرّب مضاعفة learning rate (linear scaling rule).

Epochs — عدد الدورات

كم مرة نمر على كل بيانات التدريب؟

  • قليل (5–10): Underfitting محتمل
  • كثير (100+): Overfitting محتمل — استخدم Early Stopping
  • الأفضل: تدرب كثيرًا مع Early Stopping (مثلاً max 100 epoch، patience 10)

Number of Layers — عدد الطبقات

كل طبقة = مستوى تجريد أعلى. MNIST بسيط: 2–3 طبقات تكفي. ImageNet: عشرات الطبقات (ResNet-50 = 50 طبقة).

تجربة MNIST
  • 1 طبقة مخفية (128): دقة ~95%
  • 2 طبقة (256 → 128): دقة ~97%
  • 5 طبقات بدون تنظيم: دقة train 99% لكن val 94% (overfitting!)

Hidden Units — عدد العصبونات

عرض كل طبقة مخفية. أكثر = قدرة تمثيل أعلى + خطر overfitting + تكلفة حسابية.

ابدأ صغيرًا (64, 128) وزِد تدريجيًا. راقب: إذا train accuracy عالية و val منخفضة → قلّل العصبونات أو أضف Dropout.

استراتيجية الضبط للمبتدئ
  1. ابدأ بإعدادات «معروفة أنها تعمل» (Adam, lr=1e-3, batch=64)
  2. اضبط learning rate أولًا (الأهم)
  3. ثم batch size و architecture
  4. أخيرًا regularization (dropout, weight decay)
  5. غيّر معاملًا واحدًا في كل تجربة — وإلا لن تعرف ما الذي ساعد!
05 المحور الخامس

Batch Normalization — تطبيع الدفعات

تقنية ثورية (2015) تُطبَّق بعد الطبقة الخطية وقبل دالة التفعيل. تُعيد ضبط (normalize) مخرجات كل طبقة.

Internal Covariate Shift — ماذا تعني؟

أثناء التدريب، أوزان الطبقة الأولى تتغير → مخرجاتها تتغير → الطبقة الثانية ترى «توزيعًا مختلفًا» في كل خطوة. كأنك تحاول الإصابة بهدف يتحرك باستمرار.

تشبيه

طباخ يتعلّم وصفة: كل يوم تتغير جودة المكونات (طبقة سابقة) — يصعب التعلّم. Batch Norm = توحيد جودة المكونات قبل كل طباخ.

كيف يعمل؟

لكل mini-batch، لكل عصبون:

μ = متوسط الدفعة  |  σ² = تباين الدفعة
x̂ = (x - μ) / √(σ² + ε)
y = γ · x̂ + β   (γ, β قابلان للتعلّم)

γ و β يسمحان للشبكة بـ «إلغاء» التطبيع إذا احتاجت — المرونة محفوظة.

Benefits — الفوائد

تدريب أسرع

يمكن استخدام learning rates أكبر — يتقارب أسرع.

استقرار

يقلل حساسية التهيئة — He أقل أهمية مع BN.

تنظيم خفيف

يقلل overfitting قليلًا (ليس بديلاً لـ Dropout).

شبكات أعمق

يسمح بتدريب طبقات أكثر بدون انهيار gradient.

Training vs Inference — الفرق الحاسم

الوضعμ و σالسلوك
Trainingمن الـ batch الحالييُحسب fresh كل خطوة
Inference (اختبار/إنتاج)متوسطات متراكمة (running mean/var)ثابتة — لا تعتمد على batch

في PyTorch: model.train() vs model.eval() يتحكمان بهذا تلقائيًا.

model = nn.Sequential( nn.Linear(256, 128), nn.BatchNorm1d(128), # بعد Linear، قبل ReLU nn.ReLU(), nn.Linear(128, 10) ) model.train() # Batch Norm يستخدم إحصائيات الدفعة model.eval() # Batch Norm يستخدم running statistics
06 المحور السادس

Learning Rate Scheduling — جدولة معدل التعلّم

بدل lr ثابت طوال التدريب، نغيّره مع الوقت. الفكرة: خطوات كبيرة في البداية (بعيد عن الحل) → خطوات صغيرة في النهاية (دقة أعلى).

تشبيه

البحث عن منزل في مدينة: في البداية تمشي بسرعة بين الأحياء. عندما تقترب، تتمشى ببطء بين الشوارع. في النهاية، خطوات صغيرة جدًا أمام الباب.

Step Decay — الانخفاض المرحلي

كل N epoch، اقسم lr على مثلاً 10:

lr = initial_lr × 0.1^(epoch // step_size)
مثال

initial_lr = 0.01، step_size = 30

  • Epoch 0–29: lr = 0.01
  • Epoch 30–59: lr = 0.001
  • Epoch 60+: lr = 0.0001
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)

Cosine Annealing — التلاشي الجيبي

lr ينخفض بمنحنى جيب التمام (cosine) بسلاسة من القيمة العظمى إلى صفر:

Epochs → LR Cosine Annealing — انخفاض سلس
منحنى ناعم — شائع في تدريب النماذج الحديثة
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100)

Warmup — الإحماء

في أول K خطوة، lr يبدأ من صفر تقريبًا ويرتفع تدريجيًا للقيمة المستهدفة. مهم جدًا في تدريب Transformers و LLMs الكبيرة — يمنع انفجار gradients في البداية.

مثال Warmup

target_lr = 0.001، warmup_steps = 1000

  • Step 0: lr = 0
  • Step 500: lr = 0.0005
  • Step 1000: lr = 0.001 (ثم يبدأ Cosine decay مثلاً)

Cyclic LR — معدل دوري

lr يتذبذب بين حد أدنى وأعلى بشكل دوري. الفكرة: أحيانًا lr الكبير يساعد «القفز» من minimas محلية. أقل شيوعًا من Cosine لكن مفيد في بعض التجارب.

Step Decay: بسيط وفعّال — ابدأ به.
Cosine: الأفضل للتدريب الطويل — Transformers, Vision.
Warmup: ضروري للنماذج الكبيرة — اختياري لـ MNIST.
Cyclic: للتجريب — ليس افتراضيًا.
07 المحور السابع

Debugging Deep Networks — تشخيص مشاكل الشبكات

كل ممارس تعلم عميق يواجه هذه المشاكل. المفتاح: راقب المنحنيات (train vs validation loss/accuracy) واعرف ماذا تعني.

Underfitting — نقص الملاءمة

النموذج بسيط جدًا — لا يتعلّم حتى من بيانات التدريب.

الأعراض
  • Train loss عالي ولا ينخفض كثيرًا
  • Train accuracy منخفضة (مثلاً 60% على MNIST)
  • Val loss قريب من train loss (كلاهما سيء)

الحلول: زِد الطبقات/العصبونات، قلّل regularization، زِد epochs، ارفع learning rate قليلًا، جرّب architecture أقوى.

Overfitting — الإفراط في الملاءمة

النموذج حفظ بيانات التدريب — يفشل على بيانات جديدة.

الأعراض
  • Train loss منخفض جدًا (قريب من 0)
  • Val loss يرتفع بينما train ينخفض
  • Train accuracy 99% لكن val accuracy 85%

الحلول: Dropout، Weight Decay، Early Stopping، بيانات أكثر، Data Augmentation، نموذج أصغر.

Underfitting Overfitting كلاهما عالي Train ↓ Val ↑ — ذهبي = Train  |  تركواز = Validation —
شكل المنحنيات يكشف المشكلة بسرعة

Vanishing Gradient — اختفاء التدرج

في الشبكات العميقة، gradient يُضرب عبر طبقات كثيرة → يصبح قريبًا من صفر → الطبقات الأولى لا تتعلّم.

الأسباب: Sigmoid/Tanh (مشتقاتها صغيرة)، تهيئة سيئة، شبكة عميقة جدًا.

الحلول: ReLU، He Initialization، Batch Norm، Residual Connections (Skip connections).

Exploding Gradient — انفجار التدرج

gradient يكبر exponentially → الأوزان تصبح NaN أو Inf.

مثال

Loss = 2.3 → 1.5 → 0.8 → NaN. أو weights = [1e15, -3e20, ...]

الحلول: Gradient Clipping (قص gradient إذا تجاوز حدًا)، تقليل lr، تهيئة أفضل.

torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)

Dead ReLU — ReLU الميت

إذا دخل ReLU قيمة سالبة كبيرة، gradient = 0 → العصبون لا يتعلّم أبدًا (ميت).

الحلول: Leaky ReLU (gradient صغير للقيم السالبة: 0.01x)، He Initialization، Batch Norm، lr أصغر.

قائمة فحص سريعة
  1. هل البيانات normalized (0–1 أو standardized)؟
  2. هل loss.backward() و optimizer.step() يُنفَّذان؟
  3. هل model.train() / model.eval() صحيح؟
  4. هل shapes المدخلات صحيحة؟
  5. ارسم train vs val loss — ماذا يقولان؟
08 المحور الثامن

Experiment Tracking — تتبع التجارب

عندما تجرب 20 إعدادًا مختلفًا، كيف تتذكر أيها كان الأفضل؟ أدوات التتبع تسجّل كل شيء تلقائيًا: hyperparameters، loss، accuracy، الأوزان، والرسوم.

TensorBoard

مدمج مع TensorFlow — يعمل مع PyTorch أيضًا. يعرض منحنيات loss و accuracy، histograms للأوزان، صور، وgraphs للشبكة.

from torch.utils.tensorboard import SummaryWriter writer = SummaryWriter('runs/experiment_1') for epoch in range(100): train_loss = train_one_epoch() val_acc = validate() writer.add_scalar('Loss/train', train_loss, epoch) writer.add_scalar('Accuracy/val', val_acc, epoch) writer.close() # ثم في الطرفية: tensorboard --logdir=runs

مميزات: مجاني، محلي، سهل البداية. عيوب: لا يشارك بسهولة بين الفريق.

Weights & Biases (W&B)

منصة سحابية شائعة في البحث والصناعة. تسجّل تلقائيًا، مقارنة تجارب، جداول، ولوحات جميلة.

import wandb wandb.init(project="mnist-improvement", config={ "lr": 0.001, "batch_size": 64, "optimizer": "Adam" }) for epoch in range(100): loss, acc = train_one_epoch() wandb.log({"loss": loss, "accuracy": acc, "epoch": epoch}) wandb.finish()

مميزات: مشاركة سهلة، مقارنة تجارب، artifacts. عيوب: يحتاج حساب (مجاني للاستخدام الشخصي).

MLflow

مفتوح المصدر — لتتبع تجارب ML بشكل عام (ليس deep learning فقط). يسجّل parameters، metrics، models، وبيئات التشغيل.

import mlflow with mlflow.start_run(): mlflow.log_param("lr", 0.001) mlflow.log_param("dropout", 0.5) for epoch in range(100): loss, acc = train_one_epoch() mlflow.log_metric("loss", loss, step=epoch) mlflow.pytorch.log_model(model, "model")

مميزات: مفتوح المصدر، self-hosted، يدعم نشر النماذج. عيوب: واجهة أقل جاذبية من W&B.

أي أداة للمبتدئ؟
الأداةابدأ بها إذا...
TensorBoardتتعلّم لوحدك، تريد شيئًا مجانيًا ومحليًا
W&Bتعمل في فريق، تريد مقارنة تجارب بسهولة
MLflowشركة تريد self-hosted و MLOps كامل
09 المحور التاسع

Practical Labs — مختبرات عملية

النظرية بدون تطبيق تتبخر. هنا ثلاث تجارب عملية يمكنك تنفيذها على MNIST أو CIFAR-10 خلال ساعات.

تجربة 1: تحسين نموذج حقيقي — Baseline → Improved

ابدأ بنموذج baseline ضعيف، ثم طبّق التحسينات واحدة تلو الأخرى:

الخطوةالتغييرالنتيجة المتوقعة (MNIST)
Baselineطبقة واحدة 64، SGD lr=0.01، بدون تنظيم~92% accuracy
+ He InitKaiming initialization~93%
+ Adamoptimizer = Adam(lr=1e-3)~96%
+ طبقة ثانية128 → 64~97%
+ Dropout 0.3بعد كل ReLU~97.5% (val أفضل)
+ Batch Normبعد كل Linear~98%
+ LR ScheduleCosine Annealing~98.2%
# هيكل النموذج المحسّن class ImprovedMLP(nn.Module): def __init__(self): super().__init__() self.net = nn.Sequential( nn.Linear(784, 128), nn.BatchNorm1d(128), nn.ReLU(), nn.Dropout(0.3), nn.Linear(128, 64), nn.BatchNorm1d(64), nn.ReLU(), nn.Dropout(0.3), nn.Linear(64, 10) ) def forward(self, x): return self.net(x.view(-1, 784))

تجربة 2: مقارنة Optimizers

نفس النموذج، نفس البيانات — غيّر المحسّن فقط:

بروتوكول التجربة
  1. ثبّت: architecture, batch_size=64, epochs=20, seed=42
  2. جرّب: SGD (lr=0.01), SGD+Momentum (lr=0.01), Adam (lr=1e-3), AdamW (lr=1e-3, wd=1e-4), RMSprop (lr=1e-3)
  3. سجّل: وقت التدريب، أقل val loss، أعلى val accuracy
  4. ارسم منحنيات loss لكل محسّن على نفس الرسم

النتيجة المتوقعة: Adam/AdamW يتقاربان أسرع. SGD+Momentum قد يصل لنفس الدقة لكن يحتاج ضبط lr. SGD العادي الأبطأ.

تجربة 3: مقارنة Regularization

استخدم نموذجًا كبيرًا عمدًا (3 طبقات × 512 عصبون) لإجبار overfitting، ثم جرّب:

بدون تنظيم

Train 99.5%, Val 94% — overfitting واضح

Dropout 0.5

Train 98%, Val 97% — تحسن كبير في التعميم

Weight Decay 1e-3

Train 98.5%, Val 96.5% — تحسن معتدل

Dropout + WD + Early Stop

أفضل توازن — Val ~97.5%

قالب تقرير التجربة

لكل تجربة، سجّل في جدول أو W&B:

  • الاسم: exp_03_adam_dropout05
  • التغيير: أضفت Dropout=0.5 بعد الطبقة الثانية
  • النتيجة: val_acc تحسنت من 94% → 97%
  • الاستنتاج: Dropout فعّال لهذا الحجم من النموذج
خطة عمل — 3 أيام
  1. اليوم 1: Baseline على MNIST + TensorBoard. سجّل المنحنيات.
  2. اليوم 2: تجربة Optimizers (5 محسّنات). قارن في جدول.
  3. اليوم 3: تجربة Regularization. اكتب تقريرًا قصيرًا بما تعلّمته.
FAQ أسئلة

أسئلة شائعة للمبتدئين

هل أستخدم Dropout و Batch Norm معًا؟
نعم — شائع جدًا. الترتيب المعتاد: Linear → BatchNorm → ReLU → Dropout. لكن لا تفرط: Dropout 0.5 + BatchNorm + Weight Decay قوي قد يُضعف التعلّم. ابدأ بـ BatchNorm فقط، ثم أضف Dropout إذا ظهر overfitting.
Adam أم SGD — أيهما أفضل؟
Adam للبداية والتجارب السريعة — يعمل جيدًا «من الصندوق». SGD + Momentum + جدولة lr قد يعطي دقة أعلى قليلًا في CNN الكبيرة (مثل ImageNet) لكن يحتاج ضبطًا أكثر. للمبتدئ: Adam أو AdamW.
ما قيمة Dropout الافتراضية؟
0.5 للطبقات الكبيرة (512+). 0.2–0.3 للطبقات المتوسطة. 0.1 أو بدون للطبقة الأخيرة قبل الإخراج. لا تضع Dropout على طبقة الإخراج.
متى أستخدم Early Stopping؟
دائمًا تقريبًا! ضع max_epochs كبير (100) و patience=10–15. يوفر وقتًا ويمنع overfitting. احفظ أفضل نموذج (أقل val_loss) وليس الأخير.
Loss = NaN — ماذا أفعل؟
(1) قلّل learning rate 10×. (2) أضف gradient clipping. (3) تحقق من normalize البيانات. (4) تحقق من log(0) في loss — أضف epsilon. (5) جرّب He initialization.
هل أحتاج كل هذه التقنيات لمشروعي الأول؟
لا! للبداية: Adam + lr=1e-3 + Early Stopping يكفيان لـ MNIST. أضف Dropout عند overfitting، BatchNorm عند شبكة أعمق، وجدولة lr عند التدريب الطويل. تعلّم تقنية واحدة في كل مرة.