📘 الأساسيات — الرياضيات والشبكات العصبية المجلد ١ من ٥
📖 كتاب الذكاء الاصطناعي الشامل

🧠 الأساسيات
الرياضيات والشبكات العصبية

المجلد الأول — من الصفر إلى الاحتراف

رحلة متكاملة تأخذك من المفاهيم الأساسية في الذكاء الاصطناعي والرياضيات إلى بناء وتدريب الشبكات العصبية بنفسك. كل مفهوم يُشرح بطريقتين: شرح حدسي بمثال من الحياة اليومية و شرح رياضي دقيق.

٨ فصول
٤٠+ مثال برمجي
١٠٠+ مفهوم مشروح
١ مشروع تطبيقي

📋 فهرس المحتويات

الفصل الأول

🤖 مقدمة في الذكاء الاصطناعي والتعلم العميق

من تاريخ الأفكار إلى ثورة التطبيقات الحديثة

ما هو الذكاء الاصطناعي؟

الذكاء الاصطناعي (Artificial Intelligence — AI) هو فرع من علوم الحاسوب يهدف إلى بناء أنظمة قادرة على أداء مهام تتطلب عادةً ذكاءً بشريًا. هذه المهام تشمل الرؤية، فهم اللغة، اتخاذ القرارات، وحتى الإبداع. الفكرة الأساسية هي: هل يمكن للآلة أن تفكر؟

تخيل أنك تعلّم طفلاً

عندما تعلّم طفلاً التعرف على القطط، لا تعطيه كتاب قواعد. بدلاً من ذلك، تُريه صورًا كثيرة للقطط وتقول له "هذه قطة". بعد مشاهدة آلاف الصور، يبدأ الطفل في تمييز القطط بنفسه — يتعرف على الأذنين المدببتين، الشاربين، والحركة المميزة. هذا بالضبط ما يفعله التعلم العميق، لكن باستخدام الرياضيات بدلاً من الخلايا العصبية البيولوجية.

التعلم العميق (Deep Learning) هو فرع من فروع التعلم الآلي (Machine Learning) يعتمد على الشبكات العصبية الاصطناعية متعددة الطبقات. كلما زاد عدد الطبقات، زادت قدرة النموذج على فهم الأنماط المعقدة — تمامًا كما أن دماغك يحتوي على مليارات الخلايا العصبية المترابطة.

التعريف الرياضي

نموذج التعلم العميق هو دالة f(x; θ) تأخذ مدخلاً x (مثل صورة) ومعاملات θ (الأوزان) وتنتج مخرَجًا ŷ (توقع). نضبط θ لتقليل الفرق بين ŷ والقيمة الحقيقية y.

ŷ = f(x; θ) = fL(fL−1(...f1(x; θ1)...; θL−1); θL)

حيث L هو عدد الطبقات، وكل طبقة fi هي تحويل رياضي قابل للاشتقاق.

الفرق بين AI — ML — Deep Learning

الذكاء الاصطناعي (AI): المجال الواسع — أي آلة تحاكي الذكاء البشري.
التعلم الآلي (ML): جزء من AI — آلات تتعلم من البيانات دون برمجة صريحة.
التعلم العميق (DL): جزء من ML — شبكات عصبية متعددة الطبقات تتعلم تمثيلات هرمية.


تاريخ التعلم العميق — رحلة ٨٠ عامًا

قد تظن أن التعلم العميق وليد العقد الأخير، لكن جذوره تمتد إلى أربعينيات القرن الماضي. هذه رحلة سريعة عبر المحطات الرئيسية:

السنة الحدث الأهمية
١٩٤٣ McCulloch & Pitts — أول نموذج رياضي للخلايا العصبية ولادة فكرة الشبكات العصبية
١٩٥٨ Rosenblatt — Perceptron أول آلة تتعلم من الأخطاء
١٩٦٩ Minsky & Papert — "Perceptrons" أثبتوا حدود الـ Perceptron → الشتاء الأول
١٩٨٦ Rumelhart, Hinton & Williams — Backpropagation ثورة التعلم متعدد الطبقات
١٩٩٨ LeCun — LeNet-5 أول CNN للتعرف على الأرقام
٢٠٠٦ Hinton — Deep Belief Networks ولادة مصطلح "Deep Learning"
٢٠١٢ AlexNet — فوز ساحق في ImageNet بداية ثورة DL الحديثة
٢٠١٤ GANs (Goodfellow) شبكات توليدية منافسة
٢٠١٧ Transformer (Vaswani et al.) أساس GPT و BERT وكل النماذج الحديثة
٢٠٢٠+ GPT-3, GPT-4, Claude, Gemini LLMs — نماذج لغوية عملاقة

لماذا انتصر التعلم العميق الآن وليس قبل ٣٠ عامًا؟

ثلاثة عوامل اجتمعت: (١) البيانات الضخمة — الإنترنت وفر ملايين الصور والنصوص. (٢) القوة الحاسوبية — معالجات GPU تسمح بحساب ملايين العمليات بالتوازي. (٣) خوارزميات محسّنة — مثل Adam و Batch Normalization التي جعلت تدريب الشبكات العميقة مستقرًا.


أنواع التعلم في الذكاء الاصطناعي

١. التعلم الخاضع للإشراف (Supervised Learning)

تملك بيانات مع تسميات (labels) — كل مثال له إجابة صحيحة. تعلّم النموذج توقع الإجابة من المدخلات. مثل: صور قطط مكتوب عليها "قطة".

  • التصنيف (Classification): توقع فئة (قط/كلب، spam/not spam)
  • الانحدار (Regression): توقع قيمة رقمية (سعر منزل، درجة حرارة)

٢. التعلم غير الخاضع للإشراف (Unsupervised Learning)

بيانات بدون تسميات. النموذج يكتشف الأنماط بنفسه. مثل تجميع العملاء حسب سلوكهم الشرائي.

  • التجميع (Clustering): K-Means, DBSCAN
  • تقليل الأبعاد (Dimensionality Reduction): PCA, t-SNE

٣. التعلم المعزز (Reinforcement Learning — RL)

يتفاعل النموذج (الوكيل) مع بيئة ويتلقى مكافآت أو عقوبات. يتعلم اتخاذ قرارات تزيد المكافأة التراكمية. مثل AlphaGo ولعبة الشطرنج.

٤. التعلم شبه الخاضع للإشراف (Semi-supervised Learning)

كمية صغيرة من البيانات الموسومة + كمية كبيرة غير موسومة. النموذج يستخدم البيانات غير الموسومة لتحسين فهمه.

🗺️ خريطة أنواع التعلم الآلي
الشكل ١: هرمية مجالات الذكاء الاصطناعي — من AI العام إلى DL المتخصص

تطبيقات التعلم العميق في العالم الحقيقي

التعلم العميق لم يعد أكاديميًا بحتًا — إنه في كل شيء حولك:

🖼️الرؤية الحاسوبيةالتعرف على الوجوه، السيارات ذاتية القيادة، تشخيص طبي بالصور
🗣️معالجة اللغةترجمة آلية، ChatGPT، مساعدات صوتية
🎵توليد المحتوىتوليد صور (DALL-E)، موسيقى، فيديوهات
⚕️الرعاية الصحيةاكتشاف الأورام، تحليل جيني، تصميم أدوية
🏦الماليةكشف الاحتيال، التداول الخوارزمي، تقييم المخاطر
🚗النقلسيارات ذاتية القيادة، تحسين مسارات لوجستية

📌 خلاصة الفصل الأول

  • الذكاء الاصطناعي يحاكي الذكاء البشري؛ التعلم العميق فرع منه يستخدم شبكات عصبية متعددة الطبقات
  • تاريخ الشبكات العصبية يمتد من ١٩٤٣، لكن الثورة حدثت بعد ٢٠١٢ بفضل البيانات والقدرة الحاسوبية
  • هناك ٤ أنواع رئيسية للتعلم: خاضع للإشراف، غير خاضع للإشراف، معزز، وشبه خاضع للإشراف
  • التعلم العميق يُستخدم اليوم في الرؤية، اللغة، الصحة، المالية، والنقل
الفصل الثاني

🧮 الرياضيات الأساسية للتعلم العميق

الجبر الخطي، التفاضل والتكامل، الاحتمالات — ثلاث ركائز لا غنى عنها

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

الجبر الخطي — لغة الشبكات العصبية

الجبر الخطي هو العمود الفقري للتعلم العميق. كل شيء — من الصورة التي تدخل الشبكة إلى الأوزان التي تتعلمها — هو مصفوفة أو مُتَّجِه (vector).

المُتَّجِهات (Vectors)

المُتَّجِه هو مجرد قائمة أرقام. في الرياضيات، نكتبه كعمود:

v = [v₁, v₂, ..., vₙ]ᵗ

كل صورة ملونة بحجم ٢٥٦×٢٥٦ بكسل يمكن تمثيلها كمُتَّجِه طوله ١٩٦,٦٠٨ (= 256 × 256 × 3 قنوات لونية). هذا المُتَّجِه هو مدخل الشبكة.

المُتَّجِه كموقع على الخريطة

تخيل أنك في مدينة. موقعك يُحدد بإحداثيين: (x, y). هذا مُتَّجِه ثنائي الأبعاد. إذا أضفنا سرعة الرياح ودرجة الحرارة، يصبح مُتَّجِهًا رباعي الأبعاد. الشبكات العصبية تعمل مع مُتَّجِهات بمئات الآلاف من الأبعاد — "مساحات" لا يمكننا تصورها لكن يمكننا حسابها.

عمليات المُتَّجِهات الأساسية

الجمع: نجمع كل عنصر مع نظيره.

v + w = [v₁ + w₁, v₂ + w₂, ..., vₙ + wₙ]

الضرب في قيمة قياسية (Scalar Multiplication):

α · v = [α·v₁, α·v₂, ..., α·vₙ]

الضرب القياسي (Dot Product): — أهم عملية في التعلم العميق!

v · w = Σᵢ vᵢ × wᵢ = v₁w₁ + v₂w₂ + ... + vₙwₙ

لماذا الضرب القياسي مهم جدًا؟

الضرب القياسي يقيس التشابه بين مُتَّجِهين. في الشبكات العصبية، نضرب المدخلات في الأوزان ثم نجمعها — هذا هو بالضبط الضرب القياسي. كل خلية عصبية تحسب z = w · x + b.

المصفوفات (Matrices)

المصفوفة هي ترتيب مستطيل من الأرقام. إذا كان المُتَّجِه هو قائمة، فالمصفوفة هي جدول.

A = [[a₁₁, a₁₂, ..., a₁ₙ], [a₂₁, a₂₂, ..., a₂ₙ], ... [aₘ₁, aₘ₂, ..., aₘₙ]]

حجم المصفوفة هو m × n — m صف و n عمود.

ضرب المصفوفات — جوهر التعلم العميق

ضرب مصفوفة A (حجمها m×n) مع مصفوفة B (حجمها n×p) يعطي مصفوفة C (حجمها m×p):

Cᵢⱼ = Σₖ Aᵢₖ · Bₖⱼ

تخيل أنك تدير مصنعًا

لديك ٣ مصانع (صفوف) و ٥ منتجات (أعمدة). المصفوفة A تخبرك كم تنتج每个 مصنع من كل منتج. المصفوفة B تخبرك سعر كل منتج في ٤ مدن مختلفة. ضرب A × B يعطيك: كم تربح كل مصنع إذا باع في كل مدينة. ضرب المصفوفات هو اختصار لحساب مئات الآلاف من العمليات مرة واحدة — وهذا ما تفعله GPU ببراعة.

ضرب المصفوفات في الشبكات العصبية

في طبقة متصلة بالكامل (Fully Connected Layer):

z = W · x + b

حيث W مصفوفة الأوزان (حجمها: عدد الخلايا في الطبقة الحالية × عدد الخلايا في الطبقة السابقة)، x هو مُتَّجِه المدخلات، و b هو مُتَّجِه التحيز (bias). الناتج z يمر عبر دالة تنشيط لإنتاج مخرجات الطبقة.

مصفوفة الوحدة (Identity Matrix)

مصفوفة مربعة بقطر من الآحاد وباقي العناصر أصفار. I · v = v — مثل الرقم ١ في الضرب العادي.

مقلوب المصفوفة (Matrix Inverse)

إذا كان A · A⁻¹ = I، فإن A⁻¹ هي مقلوب A. مفيد لحل أنظمة المعادلات، لكنه نادر الاستخدام في التعلم العميق لأن حسابه مكلف للأبعاد العالية.

مصفوفة التحويل (Transpose)

قلب المصفوفة: الصفوف تصير أعمدة والأعمدة صفوفًا. Aᵢⱼᵗ = Aⱼᵢ. في NumPy: A.T.

القيم الذاتية والمتَّجِهات الذاتية (Eigenvalues & Eigenvectors)

بالنسبة لمصفوفة مربعة A، المُتَّجِه الذاتي v هو مُتَّجِه غير صفري يحقق:

A · v = λ · v

حيث λ هي القيمة الذاتية (eigenvalue). تفسير: تطبيق المصفوفة A على المُتَّجِه v يغير طوله فقط (بمقدار λ) دون تغيير اتجاهه.

القيم الذاتية كمرونة المطاط

تخيل أنك تمد قطعة مطاط في اتجاه معين. القيمة الذاتية هي مقدار التمدد في ذلك الاتجاه. المُتَّجِه الذاتي هو اتجاه التمدد. في التعلم العميق، القيم الذاتية لـ Hessian matrix (مصفوفة المشتقات الثانية) تخبرنا عن مدى انحناء سطح الخطأ — مفيد جدًا لفهم سرعة التقارب.

تحليل القيمة المفردة (SVD — Singular Value Decomposition)

أي مصفوفة A (حتى غير المربعة) يمكن تحليلها إلى:

A = U · Σ · Vᵗ

حيث U و V مصفوفتان متعامدتان، و Σ مصفوفة قطرية تحتوي على القيم المفردة. SVD هو أساس تقليل الأبعاد (PCA) وضغط النماذج.

ملخص الجبر الخطي

  • المُتَّجِهات: قوائم أرقام — تمثل المدخلات، المخرجات، الأوزان
  • الضرب القياسي: يقيس التشابه — أساس كل خلية عصبية: w·x + b
  • المصفوفات: جداول أرقام — تمثل الأوزان بين الطبقات
  • ضرب المصفوفات: يعالج كل الأمثلة دفعة واحدة بدلاً من مثال مثال
  • القيم الذاتية و SVD: أدوات تحليل متقدمة لفهم بنية البيانات والنماذج

إذا كان لدينا مُتَّجِهين: v = [1, 2, 3] و w = [4, 5, 6]

احسب:
أ) v + w
ب) 3 · v
ج) v · w (الضرب القياسي)
د) إذا كانت المصفوفة W = [[1, 0, -1], [2, 1, 1]]، احسب W · v


التفاضل والتكامل — محرك التعلم

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

المشتقة (Derivative) — معدل التغير

المشتقة تخبرنا: كم تتغير قيمة y عندما نغير x بمقدار صغير؟

f'(x) = df/dx = lim_{h→0} [f(x + h) − f(x)] / h

المشتقة كمقياس السرعة

إذا كنت في سيارة، الموقع هو دالة في الزمن: x(t). السرعة هي مشتقة الموقع: v(t) = dx/dt. إذا كانت السرعة كبيرة، فأنت تغير موقعك بسرعة. في التعلم العميق: المشتقة تخبرنا في أي اتجاه يجب تغيير الأوزان لتقليل الخطأ.

قواعد الاشتقاق الأساسية

الدالة المشتقة مثال
c (ثابت)٠d/dx(5) = 0
xⁿn·xⁿ⁻¹d/dx(x³) = 3x²
نفسها!
ln(x)١/xd/dx(ln(x)) = 1/x
sin(x)cos(x)
cos(x)−sin(x)

قاعدة السلسلة (Chain Rule) — أهم قاعدة في التعلم العميق

قاعدة السلسلة تخبرنا كيف نشتق دوالاً مركبة: f(g(x)). هي قلب الانتشار العكسي (Backpropagation).

d/dx [f(g(x))] = f'(g(x)) · g'(x)

أو بشكل أبسط: مشتقة الدالة الخارجية × مشتقة الدالة الداخلية.

قاعدة السلسلة كخط تجميع

تخيل مصنعًا بمراحل: المواد الخام (x) → آلة ١ → منتج نصف مصنع → آلة ٢ → منتج نهائي. إذا أردت تحسين الجودة، تحتاج أن تعرف: كيف يؤثر تغيير في المواد الخام على المنتج النهائي؟ هذا هو ضرب المشتقات عبر المراحل — كل مشتقة تخبرك كم تؤثر التغييرات في مرحلة على المرحلة التالية.

مثال: قاعدة السلسلة في الشبكة العصبية

افترض أن لدينا دالة بسيطة:

y = f(g(x)) حيث g(x) = wx + b و f(z) = z²

لحساب dy/dx:

dy/dx = f'(g(x)) · g'(x) = 2(wx + b) · w

هذا هو بالضبط ما تفعله backpropagation — لكن لسلسلة من مئات الدوال المركبة!

المشتقة الجزئية (Partial Derivative)

عندما يكون لدينا دالة بعدة متغيرات f(x, y, z)، المشتقة الجزئية ∂f/∂x تخبرنا: كم تتغير f عندما نغير x فقط ويثبت y و z.

التدرج (Gradient) — سهم التوجيه

التدرج هو مُتَّجِه يحتوي على جميع المشتقات الجزئية:

∇f = [∂f/∂x₁, ∂f/∂x₂, ..., ∂f/∂xₙ]

التدرج يشير إلى اتجاه أقصى زيادة للدالة. في التعلم العميق، نتحرك في عكس اتجاه التدرج (نزول التدرج) لتقليل الخطأ.

التكامل — نظرة سريعة

التكامل هو عكس الاشتقاق — يقيس المساحة تحت المنحنى. يستخدم في التعلم العميق لحساب الاحتمالات (تكامل دالة الكثافة)، وفي بعض خوارزميات التحسين، لكنه أقل حضورًا من التفاضل.

احسب مشتقة الدالة: f(x) = (3x² + 2x)⁵

استخدم قاعدة السلسلة. تلميح: f(g(x)) حيث g(x) = 3x² + 2x و f(z) = z⁵


الاحتمالات والإحصاء — لغة عدم اليقين

التعلم العميق يتعامل مع عدم اليقين — لا يمكننا أبدًا التأكد ١٠٠٪ من توقعاتنا. الاحتمالات هي اللغة التي نستخدمها للتعبير عن هذا عدم اليقين.

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

الاحتمال P(A): رقم بين ٠ و ١ يعبر عن احتمال وقوع حدث A.

  • P(A) = ٠: مستحيل
  • P(A) = ١: مؤكد
  • P(A) = ٠.٥: احتمال ٥٠٪

التوزيعات الاحتمالية

التوزيع الاحتمالي يصف كيف تتوزع احتمالات القيم المختلفة لمتغير عشوائي.

التوزيع النوع مثال في DL
Uniform (منتظم)مستمر / متقطعتهيئة عشوائية للأوزان
Normal (Gaussian)مستمرتوزيع الأخطاء، تهيئة Xavier
BernoulliمتقطعDropout — قرار إبقاء أو إسقاط خلية
Categoricalمتقطعتصنيف إلى فئات متعددة
Exponentialمستمرفترات الانتظار بين الأحداث

متوسط وقيمة متوقعة (Mean / Expectation)

المتوسط الحسابي:

μ = E[X] = Σᵢ xᵢ · P(xᵢ) (للمتقطع) أو ∫ x · p(x) dx (للمستمر)

التباين والانحراف المعياري (Variance & Standard Deviation)

التباين يقيس مدى انتشار القيم حول المتوسط:

Var(X) = E[(X − μ)²] = E[X²] − μ²

الانحراف المعياري: σ = √Var(X)

قاعدة بايز (Bayes' Rule) — قلب التعلم

قاعدة بايز تخبرنا كيف نُحِدِّث معتقداتنا عند رؤية دليل جديد:

P(A|B) = P(B|A) · P(A) / P(B)
  • P(A): الاحتمال القبلي (prior) — ما نعتقده قبل رؤية الدليل
  • P(B|A): الإمكان (likelihood) — احتمال رؤية الدليل إذا كان A صحيحًا
  • P(A|B): الاحتمال البعدي (posterior) — ما نعتقده بعد رؤية الدليل

بايز في حياتك اليومية

تستيقظ وتسمع صوتًا خارج النافذة. تقول: "ربما مطر؟". هذا هو الاحتمال القبلي (في بلدك، احتمال المطر ٢٠٪). تنظر من النافذة وترى السحب الداكنة — هذا دليل جديد. تحدث اعتقادك: "على الأرجح مطر الآن". هذا هو الاحتمال البعدي. التعلم العميق يفعل هذا — يبدأ بمعتقدات عشوائية ويُحدِّثها مع كل مثال تدريبي.

الإنتروبيا (Entropy) — قياس عدم اليقين

الإنتروبيا تقيس كم المعلومات أو عدم اليقين في توزيع احتمالي:

H(p) = −Σᵢ pᵢ · log₂(pᵢ)

الإنتروبيا و"خمن الرقم"

في لعبة تخمين رقم بين ١ و ٨، كل تخمين يقلل uncertainty. إذا لعبت مع شخص يختار دائمًا الرقم ٤ (احتمال ١٠٠٪ للرقم ٤)، الإنتروبيا = ٠ — لا uncertainty. أما إذا كان يختار عشوائيًا بين ١-٨، الإنتروبيا = log₂(8) = ٣ بت — أقصى عدم يقين.

الإنتروبيا المتقاطعة (Cross-Entropy) — دالة الخسارة الأكثر شيوعًا

تقيس الفرق بين توزيعين (الحقيقي والمتوقع):

H(p, q) = −Σᵢ pᵢ · log₂(qᵢ)

في التصنيف: p هو التوزيع الحقيقي (فئة واحدة)، و q هو توقع النموذج. تقليل cross-entropy = تحسين دقة التصنيف.

ملخص الاحتمالات

  • التوزيعات تحكم عالم البيانات — Normal للتجميع، Bernoulli لـ Dropout
  • المتوسط أين تتوقع، والتباين مدى الثقة
  • قاعدة بايز: تحديث المعتقدات بدليل جديد — جوهر التعلم
  • الإنتروبيا تقيس عدم اليقين؛ cross-entropy هي دالة الخسارة القياسية
الفصل الثالث

🐍 بايثون لعلم البيانات — الأدوات العملية

NumPy للجبر الخطي، PyTorch للشبكات العصبية، TensorFlow للانتاج

الآن بعد أن فهمت الرياضيات، حان الوقت للترجمة إلى كود. في هذا الفصل سنغطي المكتبات الثلاث الأساسية التي ستحتاجها كباحث أو مهندس تعلم عميق.

NumPy — المصفوفات والعمليات الحسابية

NumPy هي المكتبة الأساسية للحسابات الرقمية في بايثون. كل مكتبات التعلم العميق (PyTorch، TensorFlow، JAX) مبنية على فلسفة NumPy.

إنشاء المصفوفات (Arrays)

# إنشاء مصفوفة من قائمة بايثون
import numpy as np

a = np.array([1, 2, 3, 4, 5])
print(a)       # [1 2 3 4 5]
print(a.shape)  # (5,) - مُتَّجِه طوله ٥

# مصفوفة ثنائية الأبعاد (مصفوفة)
A = np.array([[1, 2], [3, 4], [5, 6]])
print(A.shape)  # (3, 2) - 3 صفوف و 2 عمود

# مصفوفات خاصة
zeros = np.zeros((3, 4))     # 3×4 كلها أصفار
ones  = np.ones((2, 3))      # 2×3 كلها آحاد
I     = np.eye(4)               # مصفوفة وحدة 4×4
rand  = np.random.randn(3, 3) # 3×3 أرقام عشوائية (توزيع طبيعي)

العمليات الأساسية

# العمليات الحسابية - عنصر بعنصر
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])

print(x + y)   # [5 7 9]
print(x * y)   # [4 10 18] - ضرب عنصر بعنصر، ليس ضرب مصفوفات!
print(x ** 2)  # [1 4 9]

# ضرب المصفوفات (الحقيقي!)
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
C = A @ B      # أو np.dot(A, B)
print(C)       # [[19 22], [43 50]]

# الضرب القياسي (dot product)
v = np.array([1, 2, 3])
w = np.array([4, 5, 6])
print(v @ w)    # 32 = 1×4 + 2×5 + 3×6

الـ Broadcasting — ميزة NumPy السحرية

تسمح بإجراء عمليات بين مصفوفات بأحجام مختلفة. بايثون تكرر المصفوفة الأصغر تلقائيًا لتلائم الأكبر.

# Broadcasting: إضافة قيمة لكل عنصر
arr = np.array([[1, 2, 3],
              [4, 5, 6]])
print(arr + 10)  # يضيف 10 لكل عنصر

# إضافة مُتَّجِه لكل صف
row = np.array([10, 20, 30])
print(arr + row) # [[11 22 33], [14 25 36]]

التقطيع (Indexing & Slicing)

arr = np.array([[1, 2, 3, 4],
              [5, 6, 7, 8],
              [9, 10, 11, 12]])

print(arr[0, :])     # الصف الأول: [1 2 3 4]
print(arr[:, 1])     # العمود الثاني: [2 6 10]
print(arr[1:, 2:])   # من الصف 1 والعمود 2: [[7 8], [11 12]]

التجميع (Aggregations)

data = np.random.randn(1000, 50)  # 1000 عينة، 50 خاصية

print(data.mean())     # المتوسط العام (قريب من 0)
print(data.std())      # الانحراف المعياري (قريب من 1)
print(data.sum(axis=0))  # مجموع كل عمود → مُتَّجِه طوله 50
print(data.max(axis=1))  # أعلى قيمة في كل صف → مُتَّجِه طوله 1000

نصيحة أداء

استخدم عمليات NumPy المدمجة بدلاً من الحلقات (loops) في بايثون. حلقة for في بايثون تعالج عنصرًا تلو الآخر (ملايين المرات). عمليات NumPy مكتوبة بلغة C وتنفذ على مستوى المصفوفة (مرة واحدة — أسرع بمئات المرات).


PyTorch — التوترات والتفاضل التلقائي

PyTorch هو الإطار الأكثر شعبية للبحث والتعليم في التعلم العميق. فلسفته: "تنفيذ فوري" (eager execution) — كل أمر ينفذ مباشرة كما هو مكتوب.

التوترات (Tensors)

الـ Tensor هو المصفوفة المعمَّمة: عدد من الأبعاد.

  • Scalar (بعد ٠): torch.tensor(5)
  • Vector (بعد ١): torch.tensor([1, 2, 3])
  • Matrix (بعد ٢): torch.tensor([[1,2],[3,4]])
  • 3D Tensor: torch.randn(3, 224, 224) — ٣ صور، كل منها 224×224
  • 4D Tensor: torch.randn(32, 3, 224, 224) — دفعة (batch) من ٣٢ صورة ملونة
import torch
import numpy as np

# إنشاء التوترات
x = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)

# من NumPy إلى PyTorch والعكس
np_arr = np.array([1, 2, 3])
pt_tensor = torch.from_numpy(np_arr)    # NumPy → PyTorch
back_to_np = pt_tensor.numpy()           # PyTorch → NumPy

# التوترات على GPU
if torch.cuda.is_available():
    x_gpu = x.cuda()                     # انقل إلى GPU
    print(x_gpu.device)

التفاضل التلقائي (Autograd) — قلب PyTorch

الخاصية الثورية في PyTorch: يتتبع كل العمليات التي تجريها على التوترات ويبني رسمًا بيانيًا للحسابات (computational graph)، ثم يحسب المشتقات تلقائيًا!

# التفاضل التلقائي (Autograd)
x = torch.tensor([2.0], requires_grad=True)  # أخبر PyTorch: تتبع المشتقات
y = x ** 2                                   # y = x²
z = y + 3                                    # z = x² + 3

z.backward()                                # احسب dz/dx
print(x.grad)                               # 4.0 — لأن dz/dx = 2x = 4

التفاضل التلقائي في مثال عملي

تخيل أنك تريد تعلم المعامل w في الدالة y = wx. لديك نقاط بيانات حقيقية (x, y). الخطأ = (wx − y)². مع كل خطوة:

  1. تحسب التوقع: y_pred = wx
  2. تحسب الخطأ: loss = (y_pred − y)²
  3. تدعو loss.backward() — PyTorch يحسب d(loss)/dw تلقائيًا
  4. تحدث w: w = w − lr · dw — نتحرك عكس التدرج لتقليل الخطأ
# انحدار خطي بسيط بالكامل مع Autograd
import torch

# بيانات افتراضية: y = 2x + 1
x = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
y = torch.tensor([[3.0], [5.0], [7.0], [9.0]])

# المعاملات مع تتبع المشتقات
w = torch.randn(1, 1, requires_grad=True)
b = torch.zeros(1, requires_grad=True)

learning_rate = 0.01

for epoch in range(100):
    # Forward pass: توقع
    y_pred = x @ w + b
    
    # حساب الخطأ (Mean Squared Error)
    loss = ((y_pred - y) ** 2).mean()
    
    # Backward pass: احسب المشتقات تلقائيًا
    loss.backward()
    
    # تحديث الأوزان (بدون تتبع لهذه الخطوة)
    with torch.no_grad():
        w -= learning_rate * w.grad
        b -= learning_rate * b.grad
        
        # امسح التدرجات للخطوة التالية
        w.grad.zero_()
        b.grad.zero_()
    
    if epoch % 20 == 0:
        print(f"Epoch {epoch}: loss = {loss.item():.4f}")

print(f"المعامل w ≈ {w.item():.2f} (الحقيقي: 2.0)")
print(f"المعامل b ≈ {b.item():.2f} (الحقيقي: 1.0)")

بناء شبكة عصبية في PyTork

import torch.nn as nn
import torch.nn.functional as F

# تعريف شبكة عصبية بسيطة (تصنيف)
class SimpleClassifier(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super().__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, num_classes)
    
    def forward(self, x):
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x

model = SimpleClassifier(input_size=784, 
                         hidden_size=128, 
                         num_classes=10)
print(model)

TensorFlow / Keras — للانتاج والتوسع

TensorFlow من Google هو إطار قوي للإنتاج. Keras هي الـ API عالي المستوى الذي يبني ويشغّل الشبكات ببساطة.

import tensorflow as tf
from tensorflow import keras

# بناء نموذج متسلسل (Sequential API)
model = keras.Sequential([
    keras.layers.Dense(128, activation='relu', input_shape=(784,)),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(10, activation='softmax')
])

# تجميع النموذج
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# عرض الهيكل
model.summary()

الفرق بين PyTorch و TensorFlow

الميزة PyTorch TensorFlow / Keras
فلسفة التنفيذEager (فوري) — طبيعي، يشبه بايثون عاديةGraph-mode سابقًا، الآن eager بشكل افتراضي
المرونةعالية جدًا — مناسب للبحثمتوسطة — مناسب للإنتاج
النشر (Deployment)TorchScript, ONNXTF Serving, TF Lite, TF.js — ممتاز
التوزيع (Distributed)DistributedDataParalleltf.distribute.Strategy
من يستخدمه؟Meta, Tesla, DeepMind (البحث)Google, Uber, Airbnb (الإنتاج)
التعلمأسهل للمبتدئين — أكثر "بايثونية"منحن تعلم أكثر حدة لكن لوائح واضحة

📌 أي مكتبة تختار؟

  • للتعلُّم والتجربة: PyTorch — الأكثر شيوعًا في الأبحاث والمختبرات
  • للإنتاج: TensorFlow/Keras — أدوات نشر أفضل
  • للمشاريع الجديدة: PyTorch — ٨٠٪ من أبحاث ٢٠٢٤ تستخدم PyTorch
  • نصيحة: تعلّم PyTorch أولاً، ثم TensorFlow — المهارات تنتقل
الفصل الرابع

🧠 الشبكات العصبية من الصفر

من الخلية العصبية الواحدة إلى الشبكات متعددة الطبقات

الخلية العصبية — Perceptron

الـ Perceptron هو أبسط وحدة بناء في الشبكات العصبية. صممه Frank Rosenblatt في ١٩٥٨. هو نموذج رياضي يقلّد الخلية العصبية البيولوجية.

الخلية العصبية (Perceptron)

تأخذ عدة مدخلات x₁, x₂, ..., xₙ، لكل منها وزن w₁, w₂, ..., wₙ، وتحسب المجموع الموزون ثم تطبق دالة تنشيط:

output = φ(Σᵢ wᵢ xᵢ + b)

حيث φ هي دالة التنشيط (مثل الخطوة أو السيني) و b هو التحيز (bias).

الخلية العصبية كجهاز تصويت

تخيل لجنة من الخبراء يصوتون على قرار ما. كل خبير له وزن (أهمية صوته). إذا كان مجموع الأصوات الموزونة يتجاوز عتبة معينة، يُتخذ القرار (نعم). هذا بالضبط ما تفعله الخلية العصبية: مجموع موزون + عتبة → قرار.

مثال حقيقي: هل ستمطر اليوم؟
المتغيرات: (١) غيوم داكنة — وزن كبير، (٢) رطوبة عالية — وزن متوسط، (٣) رياح قوية — وزن صغير. إذا كان المجموع الموزون > عتبة → "نعم، ستمطر".

تنفيذ Perceptron في بايثون

# يا perceptron من الصفر
import numpy as np

class Perceptron:
    def __init__(self, input_size, lr=0.01, epochs=100):
        self.lr = lr
        self.epochs = epochs
        self.weights = np.zeros(input_size)
        self.bias = 0
    
    def activation(self, x):
        # دالة خطوة (step) - تنشيط ثنائي
        return 1 if x >= 0 else 0
    
    def predict(self, x):
        z = np.dot(x, self.weights) + self.bias
        return self.activation(z)
    
    def fit(self, X, y):
        for epoch in range(self.epochs):
            errors = 0
            for xi, target in zip(X, y):
                pred = self.predict(xi)
                error = target - pred
                
                # تحديث الأوزان: w = w + lr * error * x
                self.weights += self.lr * error * xi
                self.bias += self.lr * error
                errors += int(error != 0)
            
            if errors == 0:
                print(f"التقارب في epoch {epoch}")
                break

# اختبار: بوابة AND منطقية
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([0, 0, 0, 1])

p = Perceptron(input_size=2)
p.fit(X, y)

for xi in X:
    print(f"{xi} → {p.predict(xi)}")

حدود Perceptron — مشكلة XOR

أثبت Minsky & Papert (١٩٦٩) أن Perceptron لا يمكنه حل مشكلة XOR (التباين الحصري: ٠,١→١ و ١,٠→١ لكن ٠,٠→٠ و ١,١→٠). لماذا؟ لأن XOR ليست قابلة للفصل خطيًا — لا يوجد خط مستقيم يمكنه فصل النقاط. هذا الاكتشاف أدى إلى "الشتاء الأول" للشبكات العصبية. الحل؟ طبقات متعددة!


دوال التنشيط — إضفاء اللاخطية

بدون دوال التنشيط، كل الطبقات يمكن دمجها في طبقة خطية واحدة (ضرب مصفوفات متتالية = مصفوفة واحدة). دوال التنشيط تضيف اللاخطية (nonlinearity) — وهي ما يسمح للشبكة بتعلم أنماط معقدة.

١. Sigmoid (السيني)

σ(x) = ١ / (١ + e⁻ˣ)

تحجز القيم بين ٠ و ١. مفيدة للاحتمالات لكنها تعاني من مشكلة اختفاء التدرج (Vanishing Gradient) — للقيم الكبيرة أو الصغيرة جدًا، المشتقة قريبة من الصفر → توقف التعلُّم.

٢. Tanh

tanh(x) = (eˣ − e⁻ˣ) / (eˣ + e⁻ˣ)

تحجز القيم بين -١ و ١. أفضل من Sigmoid لأنها متمركزة حول الصفر، لكنها تعاني من اختفاء التدرج أيضًا.

٣. ReLU — الخيار الافتراضي

ReLU(x) = max(0, x)

أبسط وأنجح دالة تنشيط. الميزة: للقيم الموجبة، المشتقة = ١ → لا اختفاء للتدرج! العيب: "Dying ReLU" — الخلايا التي تصبح قيمها سالبة تتوقف عن التعلُّم للأبد.

٤. Leaky ReLU

LeakyReLU(x) = max(0.01·x, x)

حل مشكلة Dying ReLU: بدلاً من الصفر للقيم السالبة، نضربها في ٠.٠١.

٥. Softmax — للتصنيف متعدد الفئات

softmax(zᵢ) = eᶻⁱ / Σⱼ eᶻʲ

تحول متجهاً من أرقام إلى توزيع احتمالي (جميعها ≥ ٠ ومجموعها = ١). تستخدم في الطبقة الأخيرة للتصنيف.

الدالة الصيغة المدى المشتقة متى تستخدم؟
Sigmoid١/(١+e⁻ˣ)(٠, ١)σ(x)(١−σ(x))طبقة أخيرة لتصنيف ثنائي
Tanhtanh(x)(-١, ١)١−tanh²(x)شبكات RNN
ReLUmax(٠, x)[٠, ∞)١ لو x>٠ إلا ٠الخيار الافتراضي للطبقات المخفية
Leaky ReLUmax(٠.٠١x, x)٠.٠١ أو ١عند مشكلة Dying ReLU
Softmaxeᶻⁱ/Σeᶻʲ(٠, ١)خاصةطبقة أخيرة لتصنيف متعدد
# دوال التنشيط في بايثون
import numpy as np

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

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

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

def leaky_relu(x, alpha=0.01):
    return np.where(x > 0, x, alpha * x)

def softmax(x):
    ex = np.exp(x - np.max(x))  # طرح القيمة القصوى للاستقرار العددي
    return ex / ex.sum(axis=-1, keepdims=True)

الشبكات متعددة الطبقات (MLP)

Multi-Layer Perceptron (MLP) هو شبكة من عدة طبقات من الخلايا العصبية، حيث كل خلية في طبقة متصلة بكل خلية في الطبقة التالية (Fully Connected).

هيكل MLP

  • طبقة الإدخال (Input Layer): عدد الخلايا = عدد الخصائص في البيانات
  • طبقة (طبقات) مخفية (Hidden Layers): حيث يحدث التعلم
  • طبقة الإخراج (Output Layer): عدد الخلايا = عدد الفئات (للتصنيف) أو ١ (للانحدار)

MLP كسلسلة من التحولات

تخيل أنك تريد تصنيف الصور. الطبقة الأولى تتعلم الحواف (خطوط أفقية/عمودية). الطبقة الثانية تتعلم الأشكال (دوائر، مربعات). الطبقة الثالثة تتعلم الأجزاء (عيون، آذان). كل طبقة تبني على ما تعلمته الطبقة قبلها — هذا هو "التعمق" في التعلم العميق.

تنفيذ MLP من الصفر

import numpy as np

class MLP:
    def __init__(self, layer_sizes):
        # layer_sizes مثال: [784, 128, 64, 10]
        self.params = {}
        for i in range(len(layer_sizes) - 1):
            self.params[f'W{i}'] = np.random.randn(layer_sizes[i], layer_sizes[i+1]) * np.sqrt(2 / layer_sizes[i])
            self.params[f'b{i}'] = np.zeros((1, layer_sizes[i+1]))
    
    def relu(self, x):
        return np.maximum(0, x)
    
    def softmax(self, x):
        ex = np.exp(x - np.max(x, axis=-1, keepdims=True))
        return ex / np.sum(ex, axis=-1, keepdims=True)
    
    def forward(self, x):
        self.cache = {'A0': x}
        
        for i in range(len(self.params) // 2 - 1):
            z = np.dot(x, self.params[f'W{i}']) + self.params[f'b{i}']
            x = self.relu(z)
            self.cache[f'Z{i}'] = z
            self.cache[f'A{i+1}'] = x
        
        # طبقة أخيرة (بدون ReLU - مع Softmax)
        last_layer = len(self.params) // 2 - 1
        z = np.dot(x, self.params[f'W{last_layer}']) + self.params[f'b{last_layer}']
        self.cache[f'Z{last_layer}'] = z
        out = self.softmax(z)
        self.cache[f'A{last_layer+1}'] = out
        return out

📌 المفاهيم الأساسية لـ MLP

  • Fully Connected: كل خلية متصلة بكل خلية في الطبقة التالية
  • Feed-forward: المعلومات تنتقل من الأمام إلى الخلف فقط
  • أوزان منفصلة: لكل طبقة مصفوفة أوزانها وتحيزها الخاص
  • تهيئة الأوزان: مهمة جدًا — تهيئة سيئة = تدريب فاشل
  • العمق: عدد الطبقات المخفية. Closer to ١ = بسيط، أكثر = معقد
الفصل الخامس

🔄 الانتشار العكسي (Backpropagation)

آلية التعلم — كيف تتعلم الشبكة العصبية من أخطائها

Backpropagation هو الخوارزمية التي تجعل التعلم العميق ممكنًا. إنها الطريقة التي تتعلم بها الشبكة من أخطائها: تحسب مساهمة كل وزن في الخطأ الكلي، ثم تحدث الأوزان لتقليل ذلك الخطأ. هذه العملية هي تطبيق مباشر لـ قاعدة السلسلة (Chain Rule) التي تعلمناها في فصل الرياضيات.

شرح حدسي — كيف تنتشر الأخطاء للخلف؟

لعبة البلياردو

تخيل أنك تلعب البلياردو. الكرة البيضاء تضرب الكرة الحمراء، التي تضرب الكرة الزرقاء، التي تدخل في الحفرة. لكن الكرة الزرقاء أخطأت الحفرة!

كيف تصلح الأمر؟ أنت تحتاج أن تعرف: كم أثرت قوة ضربتي للكرة البيضاء على مسار الكرة الزرقاء؟ وكم أثرت زاوية الضربة؟ تتراجع خطوة بخطوة: من الخطأ النهائي ← مسار الكرة الزرقاء ← مسار الكرة الحمراء ← قوة وزاوية الضربة الأصلية.

هذا هو الانتشار العكسي بالضبط! تبدأ من الخطأ في المخرجات، وتتراجع عبر كل طبقة، محددًا مساهمة كل معامل (weight/bias) في الخطأ.

تخمين الثمن

تخيل أنك تحزر ثمن منزل. تخمينك الأول: ١٠٠,٠٠٠$. الثمن الحقيقي: ٢٠٠,٠٠٠$. الخطأ: ١٠٠,٠٠٠$. تحتاج أن تعرف: من المسؤول عن هذا الخطأ؟

  • هل المساحة في تخميني كانت صغيرة جدًا؟ (وزن المساحة كبير → خطأ كبير)
  • هل عدد الغرف كان قليلًا جدًا؟ (وزن الغرف متوسط → خطأ متوسط)
  • هل موقع المنزل أهملته بالكامل؟ (وزن الموقع صغير → خطأ صغير)

Backpropagation يوزع مسؤولية الخطأ على كل وزن حسب مساهمته، ثم يضبط الأوزان: يزيد وزن المساحة، يزيد وزن الغرف قليلاً، ويقلل وزن الموقع.


الاشتقاق الرياضي — من المخرجات إلى المدخلات

لنأخذ شبكة بسيطة جدًا: طبقة مخفية واحدة.

الشبكة المرجعية

مدخل: x ← طبقة مخفية: h = ReLU(W₁x + b₁) ← مخرج: ŷ = W₂h + b₂ ← خطأ MSE: L = ½(ŷ − y)²

الخطوة ١: مشتقة الخسارة بالنسبة للمخرجات

∂L/∂ŷ = ŷ − y

هذا هو "إشارة الخطأ" الأولية. إذا كان التوقع أعلى من الحقيقة، ∂L/∂ŷ موجبة → نحتاج تقليل ŷ.

الخطوة ٢: مشتقة الخسارة بالنسبة لأوزان الطبقة الأخيرة (W₂)

∂L/∂W₂ = (∂L/∂ŷ) · (∂ŷ/∂W₂) = (ŷ − y) · hᵗ

hᵗ هو ناتج الطبقة المخفية منقولًا. قاعدة السلسلة: مشتقة L بالنسبة لـ ŷ مضروبة في مشتقة ŷ بالنسبة لـ W₂.

الخطوة ٣: مشتقة الخسارة بالنسبة لتحيز الطبقة الأخيرة (b₂)

∂L/∂b₂ = ∂L/∂ŷ · ١ = ŷ − y

الخطوة ٤: تمرير الخطأ إلى الطبقة المخفية

نحتاج ∂L/∂h — كيف يؤثر ناتج الطبقة المخفية على الخطأ:

∂L/∂h = W₂ᵗ · (∂L/∂ŷ) = W₂ᵗ · (ŷ − y)

لاحظ: نضرب في W₂ᵗ (وليس W₂) — هذا هو "الانتشار للخلف": الأوزان تُستخدم في الاتجاه المعاكس.

الخطوة ٥: مشتقة بالنسبة لأوزان الطبقة المخفية (W₁)

نحتاج تمرير الخطأ عبر دالة ReLU. مشتقة ReLU: d/dx ReLU(x) = 1 إذا x > 0 وإلا ٠.

∂L/∂W₁ = [∂L/∂h ⊙ ReLU'(z₁)] · xᵗ

حيث هو الضرب عنصرًا بعنصر (element-wise)، و z₁ = W₁x + b₁.

النمط العام للـ Backpropagation

لكل طبقة i (من الأخيرة إلى الأولى):
١. احسب δᵢ = مشتقة الخسارة بالنسبة لمخرجات الطبقة i
٢. ∂L/∂Wᵢ = δᵢ · (مخرجات الطبقة السابقة)ᵗ
٣. ∂L/∂bᵢ = δᵢ (مجموع عبر الدفعة)
٤. δᵢ₋₁ = Wᵢᵗ · δᵢ ⊙ φ'(zᵢ₋₁) — مرر الخطأ للخلف
حيث φ هي دالة التنشيط.


تنفيذ Backpropagation في بايثون

دعنا نكمل MLP من الفصل الرابع بإضافة backpropagation كاملة:

def backward(self, y_true, output):
    """
    y_true: التسميات الحقيقية (one-hot أو indices)
    output: مخرجات النموذج من forward
    """
    m = y_true.shape[0]  # حجم الدفعة
    grads = {}
    
    # الخطأ في الطبقة الأخيرة (Cross-Entropy + Softmax gradient)
    num_layers = len(self.params) // 2
    dZ = output - y_true  # مشتقة softmax + cross-entropy مبسطة!
    
    # حلقة عكسية عبر الطبقات
    for i in reversed(range(num_layers)):
        A_prev = self.cache[f'A{i}']  # مخرجات الطبقة السابقة
        
        # مشتقات الأوزان والتحيز
        grads[f'dW{i}'] = np.dot(A_prev.T, dZ) / m
        grads[f'db{i}'] = np.sum(dZ, axis=0, keepdims=True) / m
        
        # إذا لم نكن في الطبقة الأولى، احسب dZ للطبقة السابقة
        if i > 0:
            # مشتقة ReLU: 1 للقيم الموجبة، 0 للسالبة
            Z_prev = self.cache[f'Z{i-1}']
            relu_grad = (Z_prev > 0).astype(float)
            dZ = np.dot(dZ, self.params[f'W{i}'].T) * relu_grad
    
    return grads

def update(self, grads, lr=0.01):
    """تحديث الأوزان باستخدام نزول التدرج"""
    num_layers = len(self.params) // 2
    for i in range(num_layers):
        self.params[f'W{i}'] -= lr * grads[f'dW{i}']
        self.params[f'b{i}'] -= lr * grads[f'db{i}']

لماذا softmax + cross-entropy = output − y_true؟

رياضيًا، مشتقة دالة الخسارة (cross-entropy) بعد تطبيق softmax تبسط إلى output − y_true. هذا أحد الأسباب التي تجعل هذه الثنائية شائعة جدًا — الحساب أنيق وبسيط. جرب اشتقاقها بنفسك باستخدام قاعدة السلسلة!

📌 خلاصة Backpropagation

  • الانتشار العكسي = تطبيق قاعدة السلسلة عبر الطبقات من الخلف إلى الأمام
  • كل طبقة تحسب مشتقتين: واحدة لأوزانها، وواحدة لتمرير الخطأ للطبقة السابقة
  • الخطأ ينتشر للخلف: من المخرجات ← الطبقة الأخيرة ← ... ← الطبقة الأولى
  • بدون backpropagation، لا يمكن للشبكات متعددة الطبقات أن تتعلم — إنها الخوارزمية المحورية
  • في الممارسة، PyTorch و TensorFlow يحسبانها تلقائيًا (Autograd)، لكن فهمها ضروري
الفصل السادس

⚡ تحسين الأداء — من التقارب البطيء إلى النتائج المتقنة

المحسّنات، تسوية الشبكة، وتقنيات التنظيم

نزول التدرج (Gradient Descent) وخوارزمياته

النزول من جبل في الظلام

تخيل أنك على قمة جبل في ليلة مظلمة وتريد النزول إلى الوادي. لا ترى الطريق، لكنك تشعر بانحدار الأرض تحت قدميك. نزول التدرج: تخطو في اتجاه أكبر انحدار (لأسفل). إذا كانت الخطوة كبيرة جدًا → قد تقع. إذا كانت صغيرة جدًا → يستغرق وصولك آلاف السنين. حجم الخطوة = معدل التعلم (learning rate).

Batch Gradient Descent

يحسب التدرج على كل البيانات دفعة واحدة. دقيق لكن بطيء جدًا لمجموعات البيانات الكبيرة.

θ = θ − lr · ∇J(θ) (على كل البيانات)

Stochastic Gradient Descent (SGD)

يحسب التدرج على مثال واحد عشوائي في كل مرة. سريع لكن التدرج "مزعج" (noisy) — قد لا يستقر في الحد الأدنى.

θ = θ − lr · ∇Jᵢ(θ) (على مثال واحد i)

Mini-batch Gradient Descent — الأفضل عمليًا

التوفيق بين الاثنين: دفعة صغيرة (عادةً ٣٢–٢٥٦ مثال). أسرع من Batch، أكثر استقرارًا من SGD.

θ = θ − lr · (١/m) Σᵢ ∇Jᵢ(θ) (على دفعة من m مثال)
# SGD من الصفر
def sgd_update(params, grads, lr=0.01):
    for key in params:
        params[key] -= lr * grads[key]

المحسّنات المتقدمة — أسرع وأكثر استقرارًا

SGD + Momentum

يضيف "زخمًا" للتحديث — مثل كرة تتدحرج على تل: تكتسب سرعة بمرور الوقت وتتجاوز المطبات الصغيرة.

v = β·v + (١−β)·∇J
θ = θ − lr · v

β عادةً ٠.٩. الزخم يساعد في تخطي الثنائيات المحلية الصغيرة والتقارب أسرع.

AdaGrad

يُكَيِّف معدل التعلم لكل معامل: المعاملات ذات التدرجات الكبيرة تحصل على معدل تعلم أصغر. مفيد للبيانات المتناثرة (sparse data).

RMSProp

طور من AdaGrad: يستخدم متوسط متحرك لمربعات التدرجات بدلاً من المجموع التراكمي.

s = β·s + (١−β)·(∇J)²
θ = θ − lr · ∇J / (√s + ε)

Adam (Adaptive Moment Estimation) — المحسّن الافتراضي!

يجمع بين Momentum و RMSProp مع تصحيح التحيز. هذا هو المحسّن الذي تبدأ به دائمًا — يعمل بشكل ممتاز في معظم الحالات دون ضبط معقد.

m = β₁·m + (١−β₁)·∇J # تقدير اللحظة الأولى (المتوسط)
v = β₂·v + (١−β₂)·(∇J)² # تقدير اللحظة الثانية (التباين)
m̂ = m / (١−β₁ᵗ) # تصحيح التحيز
v̂ = v / (١−β₂ᵗ)
θ = θ − lr · m̂ / (√v̂ + ε)

المعاملات الافتراضية: lr=٠.٠٠١، β₁=٠.٩، β₂=٠.٩٩٩، ε=١e⁻⁸

# Adam Optimizer من الصفر
class Adam:
    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999, eps=1e-8):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.eps = eps
        self.m = {}  # متوسط التدرج
        self.v = {}  # تباين التدرج
        self.t = 0
    
    def step(self, params, grads):
        self.t += 1
        for key in params:
            if key not in self.m:
                self.m[key] = np.zeros_like(params[key])
                self.v[key] = np.zeros_like(params[key])
            
            self.m[key] = self.beta1 * self.m[key] + (1 - self.beta1) * grads[key]
            self.v[key] = self.beta2 * self.v[key] + (1 - self.beta2) * (grads[key] ** 2)
            
            m_hat = self.m[key] / (1 - self.beta1 ** self.t)
            v_hat = self.v[key] / (1 - self.beta2 ** self.t)
            
            params[key] -= self.lr * m_hat / (np.sqrt(v_hat) + self.eps)
المحسّن معدل التعلم التكيفي؟ زخم؟ الأفضل لـ
SGDبسيط، سريع، لكن يحتاج ضبط lr بعناية
SGD+Momentumالتغلب على الثنائيات المحلية
AdaGradبيانات متناثرة (NLP, توصيات)
RMSPropعدم استقرار في التدرجات
Adamالأفضل بشكل عام — ابدأ به دائمًا

تسوية وتنظيم الشبكة — منع التجهيز الزائد

التجهيز الزائد (Overfitting) هو أن تحفظ الشبكة التدريب بدلاً من تعلُّم الأنماط العامة. كطالب يحفظ الإجابات دون فهم. الحل: تقنيات التنظيم (Regularization).

١. تنظيم L1/L2 (Weight Decay)

نضيف عقوبة للأوزان الكبيرة في دالة الخسارة:

L2: J_new = J + λ · ||W||² (أشيع)
L1: J_new = J + λ · |W| (يؤدي إلى أوزان متفرقة)

في PyTorch: optimizer = torch.optim.SGD(model.parameters(), lr=0.01, weight_decay=1e-4)

٢. Dropout — أسقط خلايا عشوائيًا!

أثناء التدريب، كل خلية لديها احتمال p أن تُسقط (تصبح صفرًا). هذا يمنع الاعتماد المفرط على خلية معينة ويجبر الشبكة على تعلم تمثيلات متكررة (Redundant).

Dropout كفريق عمل

تخيل أنك تدير فريق عمل. في كل مشروع، يغيب ٢٠٪ من الفريق عشوائيًا. مع الوقت، سيتعلم الجميع أن يكونوا ملمين بكل المهام (ليس فقط تخصصهم). هذا يخلق فريقًا أقوى وأكثر مرونة. Dropout يفعل نفس الشيء للشبكة العصبية.

# Dropout من الصفر
def dropout_forward(x, dropout_rate=0.5, training=True):
    if training:
        mask = (np.random.rand(*x.shape) > dropout_rate)
        return x * mask / (1 - dropout_rate)  # ÷ للتعويض (inverted dropout)
    else:
        return x  # أثناء الاختبار: كل الخلايا نشطة

٣. Batch Normalization — استقرار التدريب

BatchNorm تطبع مخرجات كل طبقة بحيث يكون متوسطها ≈ ٠ وتباينها ≈ ١. هذا يسمح باستخدام معدلات تعلم أكبر ويجعل التدريب أسرع وأكثر استقرارًا.

μ = (١/m) Σᵢ xᵢ ← متوسط الدفعة
σ² = (١/m) Σᵢ (xᵢ − μ)² ← تباين الدفعة
x̂ᵢ = (xᵢ − μ) / √(σ² + ε) ← تسوية
yᵢ = γ · x̂ᵢ + β ← تحويل خطي (لإستعادة التعبيرية)

γ و β معاملات قابلة للتعلُّم — الشبكة تستطيع إلغاء التسوية إذا أرادت.

٤. Early Stopping

أبسط تقنية: أوقف التدريب عندما يتوقف تحسُّن أداء التحقق (validation). راقب خسارة التحقق، وإذا لم تتحسن لـ N خطوة، أوقف التدريب واستعد أفضل وزن.

معدل التعلم الدوري (Learning Rate Scheduling)

بدلاً من معدل تعلم ثابت، يمكنك تغييره أثناء التدريب:

  • Step Decay: قلص lr بنسبة معينة كل N خطوة
  • Cosine Annealing: lr يتأرجح هابطًا (كجيب تمام) لفترات
  • ReduceLROnPlateau: قلص lr عندما تتوقف خسارة التحقق عن التحسن
  • Warmup: ابدأ بـ lr صغير وارفع تدريجيًا لتجنب صدمات البداية

📌 ترسانة التحسين

  • المحسّن: ابدأ بـ Adam (lr=٠.٠٠١)، جرّب SGD+Momentum لتحسين الأداء
  • L2 Regularization: weight_decay=١e⁻⁴ بشكل افتراضي
  • Dropout: ٠.٢–٠.٥ للطبقات المخفية، لا تستخدمه مع BatchNorm بنفس الطبقة
  • BatchNorm: أضفها بعد كل طبقة — تحسن التقارب بشكل كبير
  • Learning Rate Schedule: ReduceLROnPlateau أو Cosine Annealing
  • Early Stopping: patience=١٠ خطوات
الفصل السابع

📊 مقاييس التقييم — كيف تعرف أن نموذجك جيد؟

دوال الخسارة، دقة التصنيف، منحنيات ROC، والمزيد

بناء نموذج هو نصف الرحلة. النصف الآخر هو قياس أدائه بطريقة صحيحة. قد يكون النموذج دقيقًا ٩٩٪ لكنه غير مفيد — مثلًا إذا كان ٩٩٪ من البيانات من فئة واحدة (تصنيف غير متوازن).

دوال الخسارة — ما الذي نحاول تقليله؟

Mean Squared Error (MSE) — للانحدار

MSE = (١/n) Σᵢ (ŷᵢ − yᵢ)²

يعاقب الأخطاء الكبيرة بشدة (بسبب التربيع). حساس للقيم الشاذة (outliers). يستخدم في مشاكل الانحدار (توقع قيمة رقمية).

Mean Absolute Error (MAE)

MAE = (١/n) Σᵢ |ŷᵢ − yᵢ|

أقل حساسية للقيم الشاذة من MSE. لكن مشتقتها ثابتة (لا تصغر مع اقتراب التوقع).

Huber Loss — التوفيق بين MSE و MAE

L = ½(ŷ−y)² إذا |ŷ−y| ≤ δ
L = δ·|ŷ−y| − ½δ² فيما عدا ذلك

تربيعي للأخطاء الصغيرة، خطي للأخطاء الكبيرة — أفضل ما في العالمين.

Binary Cross-Entropy — للتصنيف الثنائي

BCE = −[y·log(ŷ) + (١−y)·log(١−ŷ)]

دالة الخسارة القياسية للتصنيف الثنائي (نعم/لا، spam/not spam). تعاقب التوقعات الواثقة والخاطئة بشدة (log يقترب من -∞ عندما ŷ→0 و y=1).

Categorical Cross-Entropy — للتصنيف المتعدد

CCE = −Σₖ yₖ·log(ŷₖ)

التعميم لفئات متعددة. مع softmax في الطبقة الأخيرة، هذه هي الخيار الافتراضي للتصنيف متعدد الفئات.

دالة الخسارة نوع المشكلة ملاحظات
MSEانحدارحساس للقيم الشاذة
MAEانحدارأقل حساسية، مشتقة ثابتة
Huberانحدارمقاوم للقيم الشاذة، الأفضل عادةً
Binary Cross-Entropyتصنيف ثنائيقياسي — استخدمه مع Sigmoid
Categorical Cross-Entropyتصنيف متعددقياسي — استخدمه مع Softmax

مقاييس التصنيف — أكثر من مجرد دقة

مصفوفة الارتباك (Confusion Matrix)

متوقع = إيجابي متوقع = سلبي
فعلي = إيجابيTP (True Positive)FN (False Negative)
فعلي = سلبيFP (False Positive)TN (True Negative)

الدقة (Accuracy)

Accuracy = (TP + TN) / (TP + TN + FP + FN)

مشكلتها: إذا كانت ٩٥٪ من الحالات سلبية، نموذج يتوقع "سلبي" دائمًا يحصل على ٩٥٪ دقة — لكنه عديم الفائدة.

Precision و Recall

Precision = TP / (TP + FP) — "من كل ما قلنا إنه إيجابي، كم كان صحيحًا؟"
Recall = TP / (TP + FN) — "من كل الإيجابي الفعلي، كم اكتشفنا؟"

متى تختار Precision ومتى Recall؟

التشخيص الطبي (سرطان): تريد Recall عاليًا — من الأفضل أن نقول "قد يكون سرطانًا" ونفحص أكثر من أن نفوته. FP مقبول، FN كارثة.

البحث في الرفوف (مكتبة): تريد Precision عالية — إذا بحثت عن "ذكاء اصطناعي"، تريد نتائج دقيقة، ليس كل كتاب يحتوي على كلمة "ذكاء". FP مزعج، FN مقبول.

F1-Score — التوفيق

F1 = ٢ · (Precision · Recall) / (Precision + Recall)

المتوسط التوافقي (harmonic mean) بين Precision و Recall. مفيد عندما تكون الفئات غير متوازنة. F1 مرتفع = توازن جيد بين الدقة والتغطية.

تطبيق عملي في بايثون

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix

y_true = [1, 0, 1, 1, 0, 1, 0, 0]
y_pred = [1, 0, 1, 0, 0, 1, 0, 1]

print(f"الدقة (Accuracy):   {accuracy_score(y_true, y_pred):.3f}")
print(f"الدقة (Precision):  {precision_score(y_true, y_pred):.3f}")
print(f"التغطية (Recall):   {recall_score(y_true, y_pred):.3f}")
print(f"F1-Score:           {f1_score(y_true, y_pred):.3f}")
print("مصفوفة الارتباك:")
print(confusion_matrix(y_true, y_pred))

منحنى ROC و AUC — مقياس شامل

منحنى ROC (Receiver Operating Characteristic)

يرسم معدل الإيجابي الصحيح (TPR = Recall) مقابل معدل الإيجابي الخاطئ (FPR = FP / (FP + TN)) مع تغيير عتبة القرار.

ROC: تحريك عتبة الحسم

تخيل أنك طبيب والحساسية تقيس "درجة الخطر" من ٠ إلى ١٠٠. إذا حددت العتبة عند ١٠ (أي درجة > ١٠ = مريض)، ستكتشف كل المرضى لكن ستصنف كثيرًا من الأصحاء كمرضى (TPR عالٍ، FPR عالٍ). إذا رفعت العتبة إلى ٨٠، ستقل الأخطاء لكن قد تفوت بعض المرضى (TPR منخفض، FPR منخفض). منحنى ROC يستكشف جميع العتبات الممكنة.

AUC (Area Under Curve)

المساحة تحت منحنى ROC — رقم بين ٠.٥ و ١.٠:

  • AUC = ١.٠: نموذج مثالي
  • AUC = ٠.٩–١.٠: ممتاز
  • AUC = ٠.٨–٠.٩: جيد جدًا
  • AUC = ٠.٧–٠.٨: مقبول
  • AUC = ٠.٥–٠.٧: ضعيف
  • AUC = ٠.٥: عشوائي (لا فائدة)

AUC يقيس قدرة النموذج على التمييز بين الفئات بغض النظر عن عتبة القرار. AUC = ٠.٩ يعني أن احتمال أن يكون مثال إيجابي عشوائي أعلى درجة من مثال سلبي عشوائي = ٩٠٪.

from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib.pyplot as plt

y_true = [0, 0, 1, 1]
y_scores = [0.1, 0.4, 0.35, 0.8]  # الاحتمالات التي يتوقعها النموذج

fpr, tpr, thresholds = roc_curve(y_true, y_scores)
auc = roc_auc_score(y_true, y_scores)

print(f"AUC = {auc:.3f}")

# رسم منحنى ROC
plt.plot(fpr, tpr, label=f'ROC (AUC = {auc:.3f})')
plt.plot([0, 1], [0, 1], 'k--')  # خط النموذج العشوائي
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('منحنى ROC')
plt.legend()
plt.show()

📌 أي مقياس تختار؟

  • فئات متوازنة: Accuracy + Confusion Matrix
  • فئات غير متوازنة: Precision / Recall / F1 (لكل فئة) + ROC AUC
  • تقييم عام: F1-Macro (متوسط F1 لكل فئة) أو ROC AUC
  • مهم جدًا: لا تختبر على بيانات التدريب! استخدم Split Train/Test أو Cross-Validation
  • للاستدلال: اختر العتبة (threshold) التي توازن بين Precision و Recall حسب حاجة عملك
الفصل الثامن — مشروع تطبيقي

🚀 بناء وتدريب شبكة عصبية للتصنيف من الصفر

تطبيق كل ما تعلمته — من الرياضيات إلى الكود النهائي

حان الوقت لتطبيق كل ما تعلمته في هذا المجلد! سنبني شبكة عصبية كاملة للتصنيف على مجموعة بيانات MNIST (الأرقام المكتوبة بخط اليد) باستخدام NumPy فقط — بدون PyTorch أو TensorFlow. ستفهم بالضبط كل جزء من الشبكة.

المشروع: تصنيف الأرقام المكتوبة بخط اليد

الهدف: بناء MLP يتعرف على الأرقام (٠–٩) من الصور.
البيانات: MNIST — ٧٠,٠٠٠ صورة ٢٨×٢٨ (رمادية).
الأدوات: NumPy فقط + (scikit-learn للتحميل فقط).
الهيكل: ٧٨٤ → ١٢٨ → ٦٤ → ١٠.
المحسّن: Adam.
دالة التنشيط: ReLU للطبقات المخفية، Softmax للمخرجات.

الخطوة ١: تحميل البيانات وتجهيزها

import numpy as np
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelBinarizer

# تحميل MNIST
print("جارٍ تحميل MNIST...")
X, y = fetch_openml('mnist_784', version=1, return_X_y=True, as_frame=False)

# تطبيع القيم إلى [0, 1]
X = X.astype(np.float32) / 255.0

# تحويل التسميات إلى one-hot
lb = LabelBinarizer()
y_onehot = lb.fit_transform(y.astype(int))

# تقسيم البيانات
X_train, X_test, y_train, y_test = train_test_split(
    X, y_onehot, test_size=0.2, random_state=42
)

print(f"شكل بيانات التدريب: {X_train.shape}")
print(f"شكل تسميات التدريب: {y_train.shape}")

الخطوة ٢: تعريف الشبكة العصبية كاملة

class NeuralNetwork:
    def __init__(self, layer_sizes, seed=42):
        np.random.seed(seed)
        self.params = {}
        self.cache = {}
        
        # تهيئة الأوزان بـ He initialization (لـ ReLU)
        for i in range(len(layer_sizes) - 1):
            fan_in = layer_sizes[i]
            fan_out = layer_sizes[i + 1]
            self.params[f'W{i}'] = np.random.randn(fan_in, fan_out) * np.sqrt(2.0 / fan_in)
            self.params[f'b{i}'] = np.zeros((1, fan_out))
    
    def relu(self, x):
        return np.maximum(0, x)
    
    def relu_grad(self, x):
        return (x > 0).astype(np.float32)
    
    def softmax(self, x):
        # للاستقرار العددي
        x_shifted = x - np.max(x, axis=1, keepdims=True)
        exp_x = np.exp(x_shifted)
        return exp_x / np.sum(exp_x, axis=1, keepdims=True)
    
    def cross_entropy_loss(self, y_pred, y_true):
        m = y_true.shape[0]
        # ε للاستقرار العددي
        eps = 1e-12
        y_pred_clipped = np.clip(y_pred, eps, 1 - eps)
        loss = -np.sum(y_true * np.log(y_pred_clipped)) / m
        return loss
    
    def forward(self, x, training=True):
        self.cache = {'A0': x}
        num_layers = len(self.params) // 2
        
        for i in range(num_layers - 1):
            z = np.dot(x, self.params[f'W{i}']) + self.params[f'b{i}']
            a = self.relu(z)
            self.cache[f'Z{i}'] = z
            self.cache[f'A{i+1}'] = a
            x = a
        
        # الطبقة الأخيرة: Softmax
        last = num_layers - 1
        z = np.dot(x, self.params[f'W{last}']) + self.params[f'b{last}']
        self.cache[f'Z{last}'] = z
        out = self.softmax(z)
        self.cache[f'A{last+1}'] = out
        return out
    
    def backward(self, y_true, output):
        num_layers = len(self.params) // 2
        m = y_true.shape[0]
        grads = {}
        
        # مشتقة softmax + cross-entropy
        dZ = output - y_true
        
        for i in reversed(range(num_layers)):
            A_prev = self.cache[f'A{i}']
            grads[f'dW{i}'] = np.dot(A_prev.T, dZ) / m
            grads[f'db{i}'] = np.sum(dZ, axis=0, keepdims=True) / m
            
            if i > 0:
                Z_prev = self.cache[f'Z{i-1}']
                dZ = np.dot(dZ, self.params[f'W{i}'].T) * self.relu_grad(Z_prev)
        
        return grads

الخطوة ٣: تدريب النموذج

# تهيئة النموذج والمحسّن
model = NeuralNetwork([784, 128, 64, 10])
optimizer = Adam(lr=0.001)

# حلقات التدريب
num_epochs = 20
batch_size = 128
num_batches = X_train.shape[0] // batch_size

for epoch in range(num_epochs):
    # خلط البيانات في كل epoch
    indices = np.random.permutation(X_train.shape[0])
    X_shuffled = X_train[indices]
    y_shuffled = y_train[indices]
    
    epoch_loss = 0
    
    for batch in range(num_batches):
        start = batch * batch_size
        end = start + batch_size
        
        X_batch = X_shuffled[start:end]
        y_batch = y_shuffled[start:end]
        
        # Forward
        output = model.forward(X_batch)
        loss = model.cross_entropy_loss(output, y_batch)
        epoch_loss += loss
        
        # Backward
        grads = model.backward(y_batch, output)
        
        # تحديث الأوزان
        optimizer.step(model.params, grads)
    
    # تقييم على مجموعة الاختبار
    test_output = model.forward(X_test, training=False)
    test_preds = np.argmax(test_output, axis=1)
    test_true = np.argmax(y_test, axis=1)
    test_acc = np.mean(test_preds == test_true)
    
    print(f"Epoch {epoch+1:2d}/{num_epochs} | Loss: {epoch_loss/num_batches:.4f} | Test Accuracy: {test_acc:.4f}")

النتائج المتوقعة

بعد ٢٠ epoch، يجب أن ترى دقة اختبار ~٩٧–٩٨٪. ليس سيئًا لشبكة مبنية من الصفر بـ NumPy فقط! للمقارنة، شبكة مشابهة في PyTorch تصل إلى ~٩٨٪.

تحديات إضافية (تطوّع)

بعد إنجاز المشروع الأساسي، جرب:
١. أضف Dropout بعد الطبقة المخفية الأولى (rate=٠.٢)
٢. أضف Batch Normalization بين الطبقات
٣. جرب هيكلًا أعمق: [784, 256, 128, 64, 10]
٤. طبّق النموذج على بيانات CIFAR-10 (صور ملونة ٣٢×٣٢)
٥. حوّل الكود إلى PyTorch — ستذهل بمدى سهولته بعد فهمك للتفاصيل

📌 ما تعلمته من هذا المشروع

  • كيف تعمل الشبكة العصبية من أول حرف إلى آخر حرف — لا صندوق أسود
  • الـ Forward pass: تحويل البيانات إلى توقعات خطوة بخطوة
  • الـ Backward pass: تطبيق قاعدة السلسلة عبر كل طبقة يدويًا
  • المحسّنات: كيف يعمل Adam من الداخل
  • أهمية التهيئة الجيدة للأوزان (He init) والتطبيع (Normalization)
  • دورة التدريب الكاملة: بيانات → Forward → Loss → Backward → تحديث → تكرر

🎯 الخلاصة — ماذا بعد؟

مبروك! 🎉 لقد أكملت المجلد الأول من كتاب الذكاء الاصطناعي الشامل. في هذه الرحلة، تعلمت:

🧮الرياضياتالجبر الخطي، التفاضل، الاحتمالات — لغة DL
🐍الأدواتNumPy, PyTorch, TensorFlow — يدك التي تعمل بها
🧠الشبكات العصبيةMLP, دوال التنشيط، Backpropagation
التحسينAdam, BatchNorm, Dropout, Regularization
📊التقييمROC AUC, F1, Precision/Recall, Confusion Matrix
🚀المشروعشبكة تصنيف أرقام كاملة من الصفر

📚 المجلدات القادمة في هذه السلسلة

المجلد ٢: 🤖 الشبكات التلافيفية (CNN) — رؤية حاسوبية
المجلد ٣: 🔄 الشبكات المتكررة (RNN) والمحولات (Transformers)
المجلد ٤: 🎨 النماذج التوليدية — GANs, VAEs, Diffusion
المجلد ٥: 🏗️ هندسة النماذج الكبيرة — LLMs, MLOps, النشر

📚 موارد إضافية للتعمق

📖Deep Learning Book (Goodfellow)المرجع الأكاديمي الأهم — مجاني على internet
🎥CS231n (Stanford)دورة الرؤية الحاسوبية — مجانية على YouTube
🎥Fast.aiتعلم DL بالتطبيق — من الأعلى للأسفل
📝PyTorch Tutorialspytorch.org/tutorials — أمثلة عملية
🧪Kaggleمسابقات و datasets للتدرب
🎓3Blue1Brownتصورات رائعة للرياضيات و DL على YouTube