تخطَّ إلى المحتوى

🤖 شرح الذكاء الاصطناعي وتعلّم الآلة

دوال التنشيط (Activation Functions)

الدرس 28 من 50· ⏱ 7 دقائق قراءة· 🗓 آخر تحديث: ١٩ سبتمبر ٢٠٢٦

بعد أن فهمت الشبكات العصبية — الأساسيات، تأتي هذه الصفحة لتشرح لماذا نضع دالة غير خطّية بعد كل ضرب مصفوفات. الإجابة المختصرة: بدونها، الشبكة كلها تصبح معادلة خطّية واحدة مهما زاد عدد الطبقات.

المشكلة: لماذا لا تكفي الطبقة الخطّية؟

الانحدار الخطي الذي درسته في الانحدار الخطي هو تحويل خطّي:

y = W · x + b

لو وضعنا طبقة خطّية أخرى فوقه:

h = W₁ · x + b₁
y = W₂ · h + b₂

عوّض h في y:

y = W₂ · (W₁ · x + b₁) + b₂
y = (W₂ · W₁) · x + (W₂ · b₁ + b₂)

النتيجة: تحويل خطّي واحد مكافئ تمامًا للشبكة المكوّنة من طبقتين. إضافة المزيد من الطبقات الخطّية لن يزيد القدرة التعبيرية — النتيجة دائمًا معادلة خطّية.

هذا يعني: شبكة من 100 طبقة خطّية = شبكة من طبقة خطّية واحدة، في القدرة على تمثيل الدوال.

الحل: دالة تنشيط غير خطّية

نُدخل بين كل ضرب مصفوفات وأخرى دالة غير خطّية:

h = activation(W₁ · x + b₁)
y = W₂ · h + b₂

activation هنا ليست ضربًا في ثابت ولا جمعًا — هي دالة تغيّر العلاقة. أشهرها: ReLU، Sigmoid، Tanh، Softmax.

ReLU — Rectified Linear Unit

أبسط دالة وأكثرها استخدامًا في الطبقات المخفية.

ReLU(z) = max(0, z)
  • إذا z > 0 → أعد z كما هي.
  • إذا z ≤ 0 → أعد 0.
import numpy as np

def relu(z):
    return np.maximum(0, z)

print(relu(2.0))    # 2.0
print(relu(-1.5))   # 0.0
print(relu(0.0))    # 0.0

منحنى ReLU:

y
↑           /
|          /
|         /
|        /
|       /
|______/________→ z
       0

لماذا ReLU شائعة؟

  • رخيصة حسابيًا: مقارنة وإرجاع صفر أو z.
  • خفّفت مشكلة تلاشي التدرّج (vanishing gradient) التي كانت تعطّل Sigmoid في الشبكات العميقة.
  • عمليًا تعطي نتائج ممتازة في طبقات المخفية لمعظم المهام.

عيب ReLU

dying ReLU: إذا أصبح z سالبًا باستمرار لعصبون معيّن، يصبح مخرَجه دائمًا صفرًا، ومُشتقّ ReLU يساوي صفرًا في المنطقة السالبة — فالعصبون يتوقّف عن التعلّم. يُعالَج عادةً بـ Leaky ReLU التي تسمح بميل خفيف في المنطقة السالبة.

Sigmoid — الاحتمال الثنائي

σ(z) = 1 / (1 + e^(-z))

المخرَج دائمًا بين 0 و 1، لذا تُستخدم لتمثيل احتمال.

def sigmoid(z):
    return 1.0 / (1.0 + np.exp(-z))

print(sigmoid(0.0))    # 0.5
print(sigmoid(2.0))    # ≈ 0.8808
print(sigmoid(-2.0))   # ≈ 0.1192
print(sigmoid(10.0))   # ≈ 0.99995 (شببع)
print(sigmoid(-10.0))  # ≈ 0.000045

منحنى Sigmoid:

y
1.0 ┤        ___________
    │     /
0.5 ┤──/
    │/
0.0 ┤/
    └───────────────→ z
   -∞          0          +∞

متى نستخدم Sigmoid؟

في طبقة المخرَج حين يكون لديك تصنيف ثنائي (احتمال ينتمي للصنف 1). مثلًا: هل الرسالة spam أم لا؟

عيب Sigmoid في الطبقات المخفية

  • في الأطراف (z كبير جدًا أو صغير جدًا)، المُشتقّ يقترب من الصفر → التدرّج يتلاشى، التعلّم يتباطأ.

Tanh — hyperbolic tangent

tanh(z) = (e^z - e^(-z)) / (e^z + e^(-z))

المخرَج بين -1 و 1، ومتماثل حول الصفر.

def tanh(z):
    return np.tanh(z)

print(tanh(0.0))    # 0.0
print(tanh(2.0))    # ≈ 0.9640
print(tanh(-2.0))   # ≈ -0.9640

منحنى tanh:

y
 1 ┤        ___________
   │     /
 0 ┤──/
   │/
-1 ┤/
   └───────────────→ z
  -∞          0          +∞

مقارنة Sigmoid و Tanh

الميزةSigmoidTanh
المدى0 إلى 1-1 إلى 1
متماثل حول الصفر؟لانعم
الاستخدام الشائعمخرَج ثنائيبعض الطبقات المخفية (RNN تاريخيًا)

في الطبقات المخفية الحديثة، ReLU تتفوّق عمليًا على الاثنين في معظم الحالات.

Softmax — توزيع احتمالات متعدد الأصناف

softmax(zᵢ) = e^(zᵢ) / Σⱼ e^(zⱼ)

تأخذ متجهًا (logits) وتُرجع توزيع احتمالات مجموعه 1.

def softmax(z):
    # shift for numerical stability
    z_shifted = z - np.max(z)
    exps = np.exp(z_shifted)
    return exps / np.sum(exps)

logits = np.array([2.0, 1.0, 0.1])
probs = softmax(logits)

print(probs)
print(f"المجموع: {probs.sum():.6f}")

النتيجة المتوقّعة:

[0.6590, 0.2424, 0.0986]
المجموع: 1.000000

متى نستخدم Softmax؟

دائمًا في طبقة المخرَج حين يكون لديك تصنيف متعدد الأصناف (احتمال لكل صنف، مجموعها 1). مثلًا: تصنيف صورة إلى قطة/كلب/عصفور.

ملاحظة: في PyTorch، nn.CrossEntropyLoss يدمج LogSoftmax + NLLLoss، فلا تطبّق Softmax يدويًا قبله. سنتناول ذلك في Loss و Optimizer في PyTorch.

ملخّص بصري

الدالةالمدىالاستخدام الشائع
ReLU[0, +∞)الطبقات المخفية (الافتراضي)
Sigmoid(0, 1)مخرَج تصنيف ثنائي
Tanh(-1, 1)بعض الحالات (RNN تاريخيًا)
Softmax(0, 1)، مجموع 1مخرَج تصنيف متعدد الأصناف

أيّ دالة أختار؟ (لا توجد قاعدة مطلقة)

كقاعدة عامة:

  1. الطبقات المخفية: ابدأ بـ ReLU. سريعة ومستقرّة.
  2. مخرَج ثنائي (احتمال): Sigmoid.
  3. مخرَج متعدد الأصناف: Softmax.
  4. مخرَج انحدار (رقم): بدون دالة تنشيط (هوية).

لكن هذه ليست قواعد مطلقة:

  • في بعض مهام الرؤية، GELU أو SiLU تتفوّق على ReLU.
  • في بعض مهام الـ RNN، Tanh أفضل من ReLU.
  • في المخرَج الثنائي، BCEWithLogitsLoss أفضل من Sigmoid + BCELoss (لأسباب عدديّة)، فتترك السينيوم خارج الرسم البياني. سنتناول ذلك في Loss Functions.

افهم المبدأ، ثم اختر حسب السياق والنتائج التجريبية.

اختبار سريع: هل الشبكة فعلًا غير خطّية؟

بدون دالة تنشيط:

import numpy as np

x = np.array([-2.0, 1.0])

# 3 طبقات خطّية متتالية (نفس الأوزان التي استخدمناها في الدرس السابق)
W1 = np.array([[0.5, 0.3], [0.2, 0.7]])
W2 = np.array([[0.4, 0.1], [0.6, 0.9]])
W3 = np.array([[0.3, 0.5], [0.8, 0.2]])

# بطبقات خطّية فقط — لا تنشيط
y_linear = W3 @ (W2 @ (W1 @ x))
y_linear_2 = (W3 @ W2 @ W1) @ x   # نفس النتيجة: تركيب خطّي

print("بالطبقات:", y_linear)
print("بمصفوفة واحدة:", y_linear_2)
print("متطابقان؟", np.allclose(y_linear, y_linear_2))

النتيجة: المتجهان متطابقان — 3 طبقات خطّية = طبقة واحدة في القدرة.

مع ReLU بين الطبقات:

def relu(z):
    return np.maximum(0, z)

# pre-activation للطبقة الأولى = [-0.7, 0.3] → relu = [0, 0.3]
h1 = relu(W1 @ x)
# pre-activation للطبقة الثانية = [0.03, 0.27] → كلها موجبة
h2 = relu(W2 @ h1)

y_relu = W3 @ h2
print("مع ReLU:", y_relu)

النتيجة الفعلية (تحقّق منها بنفس الكود):

بالطبقات:    [-0.15 -0.23]
بمصفوفة واحدة: [-0.15 -0.23]   ← متطابقان
مع ReLU:     [0.144 0.078]      ← مختلف تمامًا

هذا هو الفرق الجوهري: الشبكة مع ReLU ليست مكافئة لتحويل خطّي واحد. non-linearity تصنع قدرة تعبيرية جديدة.

أخطاء شائعة

  • "Sigmoid أفضل لأنها تعطي احتمال": في الطبقات المخفية لا — استخدم ReLU. Sigmoid في المخرَج فقط.
  • "أطبّق Sigmoid ثم Binary Cross Entropy": في PyTorch، استخدم BCEWithLogitsLoss واترك logits خام (أكثر استقرارًا عدديًا).
  • "أطبّق Softmax ثم CrossEntropyLoss": في PyTorch، CrossEntropyLoss يتوقّع logits خام، فهو يطبّق Softmax داخليًا.
  • "ReLU سيئة لأنها تقتل النصف السالب": ReLU خيار ممتاز في الطبقة المخفية. dying ReLU مشكلة حقيقية لكن تُعالَج بـ Leaky ReLU أو تهيئة جيدة.

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

🔍 ستلتقي ReLU و Sigmoid و Softmax داخل PyTorch في Loss و Optimizer في PyTorch وفي مشروع مشروع: مصنّف صور.

شرح دوال التنشيط (Activation Functions) — الذكاء الاصطناعي وتعلّم الآلة بالعربي
دوال التنشيط (Activation Functions)الذكاء الاصطناعي وتعلّم الآلة بالعربي · The Code Fix

📚 لمزيد من التعمّق في الذكاء الاصطناعي وتعلّم الآلة، راجِع توثيق scikit-learn الرسمي.

هل كان هذا الدرس مفيدًا؟