كيفية إنشاء الشبكة العصبية الخاصة بك من الصفر في بايثون. أبسط شبكة عصبية في بايثون كيفية إنشاء ذكاء اصطناعي في بايثون

13.04.2022

يمكنك هذا الأسبوع قراءة حالة محفزة للغاية من أحد طلاب GeekBrains الذي درس المهنة، حيث تحدث عن أحد أهدافه التي أدت إلى المهنة - الرغبة في تعلم مبدأ العمل وتعلم كيفية إنشاء روبوتات الألعاب بنفسك.

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

المرحلة 1. خيبة الأمل

عندما نتحدث عن إنشاء روبوتات بسيطة، تمتلئ أعيننا بالبريق، وتومض مئات الأفكار في رؤوسنا حول ما يجب أن تكون قادرة على فعله. ومع ذلك، عندما يتعلق الأمر بالتنفيذ، يتبين أن مفتاح كشف نمط السلوك الفعلي هو الرياضيات. نعم، نعم، الذكاء الاصطناعي أكثر تعقيدًا من الكتابة برامج التطبيق- المعرفة بتصميم البرمجيات وحدها لن تكون كافية بالنسبة لك.

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

المرحلة 2. القبول

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

المرحلة 3. التطوير

الآن دعنا ننتقل مباشرة إلى نظرية الذكاء الاصطناعي. ويمكن تقسيمها تقريبًا إلى 3 فئات:

  • الذكاء الاصطناعي الضعيف - الروبوتات التي نراها العاب كمبيوترأو مساعدين بسيطين مثل سيري. إنهم إما يؤدون مهام متخصصة للغاية أو يمثلون مجموعة ضئيلة من هذه المهام، وأي عدم القدرة على التنبؤ بالتفاعل يحيرهم.
  • الذكاء الاصطناعي القوي عبارة عن آلات يمكن مقارنتها بذكاء الدماغ البشري. لا يوجد حاليًا ممثلون حقيقيون لهذه الفئة، لكن أجهزة الكمبيوتر مثل Watson قريبة جدًا من تحقيق هذا الهدف.
  • الذكاء الاصطناعي المثالي هو المستقبل، وهو عقل آلي سيتجاوز قدراتنا. إنها مخاطر مثل هذه التطورات التي يحذر منها ستيفن هوكينج وإيلون ماسك وسلسلة أفلام Terminator.

بطبيعة الحال، يجب أن تبدأ بأبسط الروبوتات. للقيام بذلك، تذكر اللعبة القديمة الجيدة "Tic Tac Toe" عند استخدام حقل 3 × 3 وحاول أن تكتشف بنفسك الخوارزميات الأساسية للعمل: احتمالية الفوز بإجراءات خالية من الأخطاء، والأماكن الأكثر نجاحًا في الملعب للوصول إليها وضع قطعة، والحاجة إلى تقليص اللعبة إلى التعادل، وما إلى ذلك.

عشرات الألعاب وتحليل تصرفاتك، ربما ستتمكن من تحديد جميع الجوانب المهمة وإعادة كتابتها في كود الجهاز. إذا لم يكن الأمر كذلك، استمر في التفكير، وسيكون هذا الرابط هنا في حالة حدوث ذلك.

بالمناسبة، إذا تعلمت أخيرًا لغة بايثون، فيمكنك إنشاء روبوت بسيط إلى حد ما من خلال الرجوع إلى هذا الدليل التفصيلي. بالنسبة للغات الأخرى، مثل C++ أو Java، لن تواجه أي مشكلة في العثور على المواد خطوة بخطوة. بمجرد أن تشعر أنه لا يوجد شيء خارق وراء إنشاء الذكاء الاصطناعي، يمكنك إغلاق متصفحك بأمان وبدء التجارب الشخصية.

المرحلة 4. الإثارة

الآن بعد أن بدأت الأمور في الظهور، ربما تريد إنشاء شيء أكثر جدية. ستساعدك الموارد التالية في ذلك:

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

المرحلة 5. العمل

الآن بعد أن أصبحت لديك فكرة واضحة عن كيفية إنشاء الذكاء الاصطناعي وما يجب استخدامه، فقد حان الوقت لنقل معرفتك إليه مستوى جديد. أولاً، سيتطلب ذلك دراسة تخصص يسمى "التعلم الآلي". ثانيًا، عليك أن تتعلم كيفية العمل مع المكتبات المناسبة للغة البرمجة المختارة. بالنسبة إلى Python التي ننظر إليها، فهي Scikit-learn وNLTK وSciPy وPyBrain وNumpy. ثالثا، في التنمية لا توجد طريقة للتغلب على . حسنًا، والأهم من ذلك، أنه يمكنك الآن قراءة الأدبيات المتعلقة بالذكاء الاصطناعي مع فهم كامل للمسألة:

  • الذكاء الاصطناعي للألعاب، إيان ميلينجتون؛
  • أنماط برمجة اللعبة، روبرت نايستورم؛
  • خوارزميات الذكاء الاصطناعي وهياكل البيانات والمصطلحات في Prolog وLisp وJava، جورج لوغر، ويليام ستوبفيلد؛
  • علم الأعصاب الإدراكي الحسابي، راندال أورايلي، يوكو موناكاتا؛
  • الذكاء الاصطناعي: نهج حديث، ستيوارت راسل، بيتر نورفيج.

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

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

الخطوة 1. الخلايا العصبية وطريقة التغذية الأمامية

إذن ما هي "الشبكة العصبية"؟ دعونا ننتظر هذا ونتعامل مع خلية عصبية واحدة أولاً.

تشبه الخلية العصبية وظيفة: فهي تأخذ عدة قيم كمدخلات وترجع واحدة.

تمثل الدائرة أدناه خلية عصبية اصطناعية. يتلقى 5 ويعيد 1. الإدخال هو مجموع المشابك العصبية الثلاثة المتصلة بالخلية العصبية (ثلاثة أسهم على اليسار).

على الجانب الأيسر من الصورة نرى قيمتين إدخال ( أخضر) والإزاحة (مظللة باللون البني).

يمكن أن تكون بيانات الإدخال عبارة عن تمثيلات رقمية لخاصيتين مختلفتين. على سبيل المثال، عند إنشاء مرشح للبريد العشوائي، قد يعني ذلك وجود أكثر من كلمة مكتوبة بأحرف كبيرة ووجود كلمة "فياجرا".

يتم ضرب قيم الإدخال بما يسمى "الأوزان"، 7 و 3 (مظللة باللون الأزرق).

الآن نضيف القيم الناتجة مع الإزاحة ونحصل على رقم، في حالتنا 5 (مظلل باللون الأحمر). هذا هو مدخلات الخلايا العصبية الاصطناعية لدينا.

ثم تقوم الخلية العصبية ببعض العمليات الحسابية وتنتج قيمة الإخراج. لقد حصلنا على 1 بسبب القيمة المقربة للسيني عند النقطة 5 هي 1 (سنتحدث عن هذه الوظيفة بمزيد من التفصيل لاحقًا).

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

رسم توضيحي للشبكة العصبية من ويكيبيديا.

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

الخطوة 2. السيني

بعد أن شاهدت دروس Welch Labs، من الجيد الاطلاع على الأسبوع الرابع من دورة كورسيرا للتعلم الآلي حول الشبكات العصبية لمساعدتك على فهم كيفية عملها. تتعمق الدورة كثيرًا في الرياضيات وتعتمد على Octave، بينما أفضل لغة Python. ولهذا السبب، قمت بتخطي التمارين وحصلت على كل المعرفة اللازمة من مقاطع الفيديو.

يقوم السيني ببساطة بتعيين القيمة الخاصة بك (على المحور الأفقي) إلى نطاق من 0 إلى 1.

كانت أولويتي الأولى هي دراسة السيني، كما ظهر في العديد من جوانب الشبكات العصبية. لقد عرفت شيئًا عنها بالفعل منذ الأسبوع الثالث من الدورة المذكورة أعلاه، لذلك شاهدت الفيديو من هناك.

لكنك لن تتمكن من تحقيق الكثير باستخدام مقاطع الفيديو وحدها. من أجل الفهم الكامل، قررت ترميزه بنفسي. لذلك بدأت في كتابة تطبيق لخوارزمية الانحدار اللوجستي (التي تستخدم السيني).

استغرق الأمر يومًا كاملاً، وكانت النتيجة غير مرضية. لكن لا يهم، لأنني اكتشفت كيف يعمل كل شيء. يمكن رؤية الكود.

ليس من الضروري القيام بذلك بنفسك، لأنه يتطلب معرفة خاصة - الشيء الرئيسي هو أنك تفهم كيفية عمل السيني.

الخطوة 3. طريقة الانتشار العكسي

إن فهم كيفية عمل الشبكة العصبية من الإدخال إلى الإخراج ليس بالأمر الصعب. من الصعب جدًا فهم كيفية تعلم الشبكة العصبية من مجموعات البيانات. المبدأ الذي استخدمته يسمى

نحن نشهد الآن طفرة حقيقية في الشبكات العصبية. يتم استخدامها للتعرف والتوطين ومعالجة الصور. تستطيع الشبكات العصبية بالفعل القيام بأشياء كثيرة غير متاحة للبشر. نحن بحاجة إلى الانخراط في هذا الأمر بأنفسنا! لنفكر في شبكة نيوترونية يمكنها التعرف على الأرقام في الصورة المدخلة. الأمر بسيط جدًا: طبقة واحدة فقط ووظيفة التنشيط. وهذا لن يسمح لنا بالتعرف على جميع الصور الاختبارية، ولكن يمكننا التعامل مع الغالبية العظمى منها. كبيانات سوف نستخدم مجموعة بيانات MNIST، المعروفة في عالم التعرف على الأرقام.

للعمل معها في بايثون هناك مكتبة python-mnist. للتثبيت:

تثبيت النقطة بيثون-mnist

الآن يمكننا تحميل البيانات

من استيراد mnist MNIST mndata = MNIST("/path_to_mnist_data_folder/") tr_images, tr_labels = mndata.load_training() test_images, test_labels = mndata.load_testing()

تحتاج إلى تنزيل الأرشيفات بالبيانات بنفسك، وتحديد المسار إلى الدليل معهم إلى البرنامج. الآن تحتوي متغيرات tr_images وtest_images على صور لتدريب الشبكة واختبارها، على التوالي. والمتغيرات tr_labels وtest_labels هي تسميات بالتصنيف الصحيح (أي أرقام من الصور). جميع الصور بحجم 28x28. لنقم بتعيين متغير بالحجم.

Img_shape = (28، 28)

دعونا نحول جميع البيانات إلى صفائف numpy ونقوم بتطبيعها (قم بتغيير حجمها إلى حجم من -1 إلى 1). سيؤدي هذا إلى زيادة دقة الحسابات.

استيراد numpy كـ np لـ i في النطاق(0, len(test_images)): test_images[i] = np.array(test_images[i]) / 255 لـ i في النطاق(0, len(tr_images)): tr_images[i] = np.array(tr_images[i]) / 255

وألاحظ أنه على الرغم من أنه من المعتاد تمثيل الصور كمصفوفة ثنائية الأبعاد، إلا أننا سنستخدم مصفوفة أحادية البعد، فهي أسهل في العمليات الحسابية. الآن عليك أن تفهم "ما هي الشبكة العصبية"! وهذه مجرد معادلة مع عدد كبيرمعاملات لدينا مصفوفة إدخال مكونة من 28*28=784 عنصرًا و784 وزنًا آخر لتحديد كل رقم. أثناء تشغيل الشبكة العصبية، تحتاج إلى مضاعفة قيم الإدخال بالأوزان. أضف البيانات الناتجة وأضف الإزاحة. يتم تغذية النتيجة الناتجة إلى وظيفة التنشيط. في حالتنا سيكون Relu. هذه الدالة تساوي صفرًا لجميع الوسائط السالبة وصفرًا لجميع الوسائط الموجبة.

هناك العديد من وظائف التنشيط! ولكن هذه هي أبسط شبكة عصبية! دعونا نحدد هذه الوظيفة باستخدام numpy

ديف relu(x): إرجاع np.maximum(x, 0)

الآن، لحساب الصورة في الصورة، تحتاج إلى حساب النتيجة لمدة 10 مجموعات من المعاملات.

Def nn_calculate(img): resp = list(range(0, 10)) for i in range(0,10): r = w[:, i] * img r = relu(np.sum(r) + b[ i]) resp[i] = r return np.argmax(resp)

لكل مجموعة سوف نحصل على نتيجة الإخراج. من المرجح أن يكون الناتج ذو أعلى نتيجة هو رقمنا.

في في هذه الحالة 7. هذا كل شيء! لكن لا... بعد كل شيء، تحتاج إلى الحصول على نفس المعاملات في مكان ما. نحن بحاجة إلى تدريب شبكتنا العصبية. للقيام بذلك، يتم استخدام طريقة الانتشار العكسي. جوهرها هو حساب مخرجات الشبكة ومقارنتها بالمخرجات الصحيحة ثم طرح الأرقام اللازمة من المعاملات لتكون النتيجة صحيحة. يجب أن نتذكر أنه من أجل حساب هذه القيم، هناك حاجة إلى مشتق دالة التنشيط. وفي حالتنا، فهو يساوي صفرًا لجميع الأرقام السالبة و1 لجميع الأرقام الموجبة. دعونا نحدد المعاملات بشكل عشوائي.

W = (2*np.random.rand(10, 784) - 1) / 10 b = (2*np.random.rand(10) - 1) / 10 لـ n في النطاق(len(tr_images)): img = tr_images[n] cls = tr_labels[n] #forwardpropagation resp = np.zeros(10, dtype=np.float32) for i in range(0,10): r = w[i] * img r = relu( np.sum(r) + b[i]) resp[i] = r resp_cls = np.argmax(resp) resp = np.zeros(10, dtype=np.float32) resp = 1.0 # الانتشار الخلفي true_resp = np. الأصفار (10، dtype=np.float32) true_resp = 1.0 خطأ = resp - true_resp delta = خطأ * ((resp >= 0) * np.ones(10)) for i في النطاق(0,10): w[i ] -= np.dot(img, delta[i]) b[i] -= delta[i]

مع تقدم التدريب، ستبدأ المعاملات في الظهور كالأرقام إلى حد ما:

دعونا نتحقق من دقة العمل:

Def nn_calculate(img): resp = list(range(0, 10)) for i in range(0,10): r = w[i] * img r = np.maximum(np.sum(r) + b[ i], 0) #relu resp[i] = r return np.argmax(resp) Total = len(test_images) صالح = 0 غير صالح = بالنسبة إلى i في النطاق (0، الإجمالي): img = test_images[i] المتوقع = nn_calculate (img) صحيح = test_labels[i] إذا كان متوقعًا == صحيح: صالح = صالح + 1 آخر: غير صالح.append(("image":img, "predicted":توقع, "true":true)) print("الدقة" ()".التنسيق (صالح/إجمالي))

حصلت على 88%. ليس هذا رائعًا، ولكنه مثير جدًا للاهتمام!

يتم إنشاء الشبكات العصبية وتدريبها بشكل أساسي لغة بايثون. لذلك، من المهم جدًا أن يكون لديك فهم أساسي لكيفية كتابة البرامج فيه. سأتحدث في هذه المقالة بإيجاز ووضوح عن المفاهيم الأساسية لهذه اللغة: المتغيرات والوظائف والفئات والوحدات النمطية.

المادة مخصصة للأشخاص غير المعتادين على لغات البرمجة.

تحتاج أولاً إلى تثبيت بايثون. فأنت بحاجة إلى تثبيت بيئة مناسبة لكتابة البرامج في بايثون. البوابة مخصصة لهاتين الخطوتين.

إذا تم تثبيت كل شيء وتكوينه، يمكنك البدء.

المتغيرات

عامل- مفهوم أساسي في أي لغة برمجة (وليس فيها فقط). أسهل طريقة للتفكير في المتغير هي كمربع به تسمية. يحتوي هذا الصندوق على شيء (رقم، مصفوفة، كائن، ...) ذو قيمة بالنسبة لنا.

على سبيل المثال، نريد إنشاء متغير x الذي يجب أن يخزن القيمة 10. في بايثون، سيبدو رمز إنشاء هذا المتغير كما يلي:

على اليسار نحن نعلنمتغير اسمه x وهذا يعادل وضع علامة اسم على الصندوق. بعد ذلك تأتي علامة التساوي والرقم 10. تلعب علامة التساوي دورًا غير عادي هنا. وهذا لا يعني أن "س يساوي 10". المساواة في هذه الحالة تضع الرقم 10 في المربع. وبعبارة أكثر دقة، نحن تعيينالمتغير x هو الرقم 10.

الآن، في الكود أدناه يمكننا الوصول إلى هذا المتغير وكذلك تنفيذ إجراءات مختلفة معه.

يمكنك ببساطة عرض قيمة هذا المتغير على الشاشة:

X=10 طباعة(x)

تمثل print(x) استدعاء دالة. وسوف ننظر فيها أبعد من ذلك. الشيء المهم الآن هو أن هذه الوظيفة تطبع على وحدة التحكم ما هو موجود بين الأقواس. بين القوسين لدينا x. في السابق، قمنا بتعيين x القيمة 10. وهذا هو ما تتم طباعة 10 في وحدة التحكم إذا قمت بتشغيل البرنامج أعلاه.

يمكن إجراء العديد من العمليات البسيطة باستخدام المتغيرات التي تخزن الأرقام: الجمع والطرح والضرب والقسمة والأسي.

X = 2 y = 3 # إضافة z = x + y print(z) # 5 # الفرق z = x - y print(z) # -1 # المنتج z = x * y print(z) # 6 # القسمة z = x / y print(z) # 0.66666... ​​​​# الأسي z = x ** y print(z) # 8

في الكود أعلاه، نقوم أولاً بإنشاء متغيرين يحتويان على 2 و3. ثم نقوم بإنشاء متغير z الذي يخزن نتيجة العملية على x وy ويطبع النتائج على وحدة التحكم. يوضح هذا المثال بوضوح أن المتغير يمكنه تغيير قيمته أثناء تنفيذ البرنامج. لذا فإن المتغير z يغير قيمته بما يصل إلى 5 مرات.

وظائف

في بعض الأحيان يصبح من الضروري تنفيذ نفس الإجراءات مرارا وتكرارا. على سبيل المثال، في مشروعنا غالبًا ما نحتاج إلى عرض 5 أسطر من النص.

"هذا نص مهم للغاية!"
"هذا النص لا يمكن قراءته"
"الخطأ في السطر العلوي تم عن قصد"
"مرحبا وداعا"
"نهاية"

سيبدو الكود الخاص بنا كما يلي:

X = 10 y = x + 8 - 2 print("هذا نص مهم جدًا!") print("لا يمكن قراءة هذا النص") print("تم ارتكاب الخطأ في السطر العلوي عن قصد") print(" مرحبًا وداعًا") print ("النهاية") z = x + y print("هذا نص مهم جدًا!") print("لا يمكن قراءة هذا النص") print("حدث الخطأ في السطر العلوي" عن قصد") print("مرحبًا وداعًا") print("النهاية") test = z print("هذا نص مهم جدًا!") print("لا يمكن قراءة هذا النص") print("الخطأ في تم عمل السطر العلوي عن قصد") print("مرحبا وداعا") print("End")

كل هذا يبدو زائدة عن الحاجة وغير مريح للغاية. وبالإضافة إلى ذلك، كان هناك خطأ في السطر الثاني. يمكن إصلاحه، ولكن يجب تثبيته في ثلاثة أماكن في وقت واحد. ماذا لو تم استدعاء هذه الأسطر الخمسة 1000 مرة في مشروعنا؟ وكل شيء في أماكن وملفات مختلفة؟

خاصة في الحالات التي تحتاج فيها إلى تنفيذ نفس الأوامر بشكل متكرر، يمكنك إنشاء وظائف بلغات البرمجة.

وظيفة- كتلة منفصلة من التعليمات البرمجية يمكن استدعاؤها بالاسم.

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

Def print_5_lines(): print("هذا نص مهم جدًا!") print("لا يمكن قراءة هذا النص") print("حدث الخطأ في السطر العلوي عن قصد") print("مرحبًا وداعًا") طباعة ("النهاية")

لقد قمنا الآن بتعريف الدالة print_5_lines(). الآن، إذا أردنا مرة أخرى في مشروعنا إدراج خمسة أسطر، فإننا ببساطة نسمي الدالة. سيتم تنفيذ جميع الإجراءات تلقائيًا.

# حدد الوظيفة def print_5_lines(): print("هذا نص مهم جدًا!") print("لا يمكن قراءة هذا النص") print("الخطأ في السطر العلوي كان مقصودًا") print("مرحبًا وداعًا" ") print(" End") # رمز مشروعنا x = 10 y = x + 8 - 2 print_5_lines() z = x + y print_5_lines() test = z print_5_lines()

مريحة، أليس كذلك؟ لقد قمنا بتحسين إمكانية قراءة الكود بشكل جدي. بالإضافة إلى ذلك، تعد الوظائف جيدة أيضًا لأنه إذا كنت تريد تغيير بعض الإجراءات، فأنت تحتاج فقط إلى تصحيح الوظيفة نفسها. سيعمل هذا التغيير في جميع الأماكن التي يتم استدعاء وظيفتك فيها. أي أنه يمكننا تصحيح الخطأ في السطر الثاني من النص الناتج ("لا"> "لا") في نص الوظيفة. سيتم استدعاء الخيار الصحيح تلقائيًا في جميع الأماكن في مشروعنا.

وظائف مع المعلمات

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

تسمى المتغيرات التي نمررها إلى الدالة الحجج.

دعونا نكتب وظيفة بسيطة، الذي يجمع رقمين معينين له ويعيد النتيجة.

مجموع التعريف (أ، ب): النتيجة = نتيجة الإرجاع أ + ب

يبدو السطر الأول تقريبًا مثل الوظائف العادية. ولكن بين القوسين يوجد الآن متغيران. هذا حدودوظائف. تحتوي وظيفتنا على معلمتين (أي أنها تأخذ متغيرين).

يمكن استخدام المعلمات داخل دالة تمامًا مثل المتغيرات العادية. في السطر الثاني، نقوم بإنشاء نتيجة متغيرة، وهي تساوي مجموع المعلمات a و b. في السطر الثالث نعيد قيمة المتغير الناتج.

الآن، في مزيد من التعليمات البرمجية يمكننا أن نكتب شيئا من هذا القبيل:

جديد = مجموع (2، 3) طباعة (جديد)

نسمي الدالة sum ونمررها وسيطتين على التوالي: 2 و3. 2 تصبح قيمة المتغير a، و3 تصبح قيمة المتغير b. تقوم وظيفتنا بإرجاع قيمة (مجموع 2 و 3) ونستخدمها لإنشاء متغير جديد، جديد .

يتذكر. في الكود أعلاه، الرقمان 2 و3 هما وسيطات الدالة sum. وفي دالة المجموع نفسها، يكون المتغيران a وb عبارة عن معلمات. بمعنى آخر، المتغيرات التي نمررها إلى دالة عند استدعائها تسمى وسيطات. ولكن داخل الدالة، تسمى هذه المتغيرات التي تم تمريرها المعلمات. في الواقع، هذان اسمان لنفس الشيء، لكن لا ينبغي الخلط بينهما.

دعونا ننظر إلى مثال آخر. لنقم بإنشاء دالة مربعة (أ) تأخذ رقمًا واحدًا وتقوم بتربيعه:

Def Square(a): قم بإرجاع a * a

تتكون وظيفتنا من سطر واحد فقط. يقوم على الفور بإرجاع نتيجة ضرب المعلمة a بواسطة a .

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

المصفوفات

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

صفيف =

فيما يلي مثال عندما لا يحتوي المتغير على رقم، بل على كائن آخر. في هذه الحالة، يحتوي المتغير لدينا على مصفوفة. يتم ترقيم كل عنصر من عناصر المصفوفة. دعونا نحاول عرض بعض عناصر المصفوفة:

صفيف = طباعة (صفيف)

في وحدة التحكم سترى الرقم 89. لكن لماذا 89 وليس 1؟ المشكلة هي أنه في بايثون، كما هو الحال في العديد من لغات البرمجة الأخرى، يبدأ ترقيم المصفوفات من 0. لذلك، تعطينا المصفوفة ثانيةعنصر المصفوفة، وليس العنصر الأول. للاتصال بالرقم الأول، كان عليك كتابة array .

حجم الصفيف

في بعض الأحيان يكون من المفيد جدًا معرفة عدد العناصر في المصفوفة. يمكنك استخدام الدالة len() لهذا الغرض. سيتم حساب عدد العناصر وإرجاع عددها.

صفيف = طباعة (لين (صفيف))

ستعرض وحدة التحكم الرقم 4.

الشروط والدورات

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

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

في الحالة الأولى تساعد الظروف، وفي الحالة الثانية تساعد الدورات.

شروط

هناك حاجة إلى شروط لتنفيذ مجموعتين مختلفتين من الإجراءات اعتمادًا على ما إذا كانت العبارة التي يتم اختبارها صحيحة أم خاطئة.

في بايثون، يمكن كتابة الشروط باستخدام if: ... else: ... build. دعونا نحصل على متغير x = 10. إذا كانت x أقل من 10، فإننا نريد قسمة x على 2. إذا كانت x أكبر من أو تساوي 10، فإننا نريد إنشاء متغير آخر، جديد، يساوي مجموع x والرقم 100. هذا هو الشكل الذي سيبدو عليه الكود:

س = 10 إذا (س< 10): x = x / 2 print(x) else: new = x + 100 print(new)

بعد إنشاء المتغير x، نبدأ في كتابة شرطنا.

يبدأ كل شيء بالكلمة الأساسية if (مترجمة من الإنجليزية بـ "if"). بين قوسين نشير إلى التعبير الذي سيتم التحقق منه. في هذه الحالة، نتحقق مما إذا كان المتغير x أقل بالفعل من 10. إذا كان أقل من 10 بالفعل، فنقسمه على 2 ونطبع النتيجة على وحدة التحكم.

ثم يأتي الكلمة الرئيسيةآخر، وبعد ذلك تبدأ مجموعة من الإجراءات التي سيتم تنفيذها إذا كان التعبير الموجود بين قوسين بعد if خطأ.

إذا كان أكبر من أو يساوي 10، فإننا نقوم بإنشاء متغير جديد جديد، وهو ما يساوي x + 100 ونخرجه أيضًا إلى وحدة التحكم.

دورات

هناك حاجة إلى حلقات لتكرار الإجراءات عدة مرات. لنفترض أننا نريد عرض جدول بمربعات العشرة الأولى الأعداد الطبيعية. يمكن القيام به على هذا النحو.

طباعة("المربع 1 هو" + str(1**2)) طباعة ("المربع 2 هو" + str(2**2)) طباعة ("المربع 3 هو" + str(3**2)) طباعة(" "المربع 4 هو " + str(4**2)) print("المربع 5 هو " + str(5**2)) print("المربع 6 هو " + str(6**2)) print("مربع 7 هو " + str(7**2)) print("مربع 8 هو " + str(8**2)) print("مربع 9 هو " + str(9**2)) print("مربع من 10 هو " + str(10**2))

لا تتفاجأ من حقيقة أننا نضيف أسطرًا. "بداية السطر" + "النهاية" في بايثون تعني ببساطة سلاسل متسلسلة: "بداية السطر". بنفس الطريقة أعلاه، نضيف السلسلة النصية “مربع x يساوي” ونتيجة رفع الرقم إلى القوة الثانية، يتم تحويلها باستخدام الدالة str(x**2).

يبدو الرمز أعلاه زائداً عن الحاجة. ماذا لو أردنا طباعة مربعات أول 100 رقم؟ يؤلمنا الانسحاب..

في مثل هذه الحالات توجد دورات. هناك نوعان من الحلقات في بايثون: while وfor. دعونا نتعامل معهم واحدا تلو الآخر.

تكرر حلقة while الأوامر الضرورية طالما ظل الشرط صحيحًا.

X = 1 بينما x<= 100: print("Квадрат числа " + str(x) + " равен " + str(x**2)) x = x + 1

نقوم أولاً بإنشاء متغير وتخصيص الرقم 1 له، ثم نقوم بإنشاء حلقة while والتحقق مما إذا كانت x أقل من (أو تساوي) 100. إذا كان أقل (أو يساوي) فإننا نقوم بإجراءين:

  1. إخراج المربع x
  2. زيادة × بمقدار 1

بعد الأمر الثاني، يعود البرنامج إلى الحالة. إذا كان الشرط صحيحا مرة أخرى، فإننا نقوم بتنفيذ هذين الإجراءين مرة أخرى. وهكذا حتى تصبح x مساوية لـ 101. ثم سيعود الشرط خطأ ولن يتم تنفيذ الحلقة بعد ذلك.

تم تصميم حلقة for للتكرار على المصفوفات. لنكتب نفس المثال بمربعات أول مائة عدد طبيعي، ولكن من خلال حلقة for.

بالنسبة لـ x في النطاق (1,101): print("مربع الرقم " + str(x) + " is " + str(x**2))

دعونا ننظر إلى السطر الأول. نستخدم الكلمة الأساسية لإنشاء حلقة. بعد ذلك، نحدد أننا نريد تكرار إجراءات معينة لجميع x في النطاق من 1 إلى 100. ينشئ نطاق الدالة (1,101) مصفوفة مكونة من 100 رقم، تبدأ من 1 وتنتهي بـ 100.

فيما يلي مثال آخر للتكرار عبر مصفوفة باستخدام حلقة for:

لأني في: طباعة (i * 2)

يُخرج الكود أعلاه 4 أرقام: 2 و20 و200 و2000. هنا يمكنك أن ترى بوضوح كيف يأخذ كل عنصر من عناصر المصفوفة وينفذ مجموعة من الإجراءات. ثم يأخذ العنصر التالي ويكرر نفس مجموعة الإجراءات. وهكذا حتى نفاد العناصر الموجودة في المصفوفة.

الطبقات والكائنات

في الحياة الواقعية، نحن لا نتعامل مع المتغيرات أو الوظائف، ولكن مع الأشياء. قلم، سيارة، شخص، قطة، كلب، طائرة - أشياء. الآن دعونا نلقي نظرة فاحصة على القطة.

لديها بعض المعلمات. وتشمل هذه لون المعطف ولون العين ولقبها. ولكن هذا ليس كل شيء. بالإضافة إلى المعلمات، يمكن للقط القيام بإجراءات مختلفة: الخرخرة والهسهسة والخدش.

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

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

فصول

لإنشاء فئة (مخطط قطتنا)، تحتاج إلى كتابة فئة الكلمة الأساسية ثم تحديد اسم هذه الفئة:

فئة القط:

بعد ذلك نحتاج إلى سرد تصرفات هذه الفئة (إجراءات القط). الإجراءات، كما قد تكون خمنت، هي وظائف محددة داخل الفصل الدراسي. عادةً ما تسمى هذه الوظائف داخل الفصل بالطرق.

طريقة- دالة محددة داخل الفصل.

لقد سبق أن وصفنا أساليب القطة لفظيًا أعلاه: الخرخرة، والهسهسة، والخدش. الآن دعونا نفعل ذلك في بايثون.

# فئة القط فئة القط: # Purr defpurr(self): print("Purrr!") # Hiss def hiss(self): print("Shhh!") # Scratch def scrabble(self): print("Scratch-scratch" "!")

الأمر بهذه البساطة! لقد أخذنا وحددنا ثلاث وظائف عادية، ولكن داخل الفصل فقط.

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

# فئة القط فئة القط: # Purr defpurr(self): print("Purrr!") # Hiss def hiss(self): print("Shhh!") # Scratch def scrabble(self): print("Scratch-scratch" !") # الكل معًا def all_in_one(self): self.purr() self.hiss() self.scrabble()

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

لنقم الآن بتعيين خصائص قطتنا (لون الفراء، ولون العين، واللقب). كيف تفعل هذا؟ في أي فئة يمكنك تحديد الدالة __init__(). يتم استدعاء هذه الوظيفة دائمًا عندما نقوم بإنشاء كائن حقيقي من فئتنا.

في طريقة __init__() الموضحة أعلاه، قمنا بتعيين متغيرات القطة. كيف نفعل هذا؟ أولاً، نقوم بتمرير 3 وسيطات لهذه الطريقة، وهي المسؤولة عن لون المعطف ولون العين واللقب. بعد ذلك، نستخدم المعلمة self لتعيين قطتنا فورًا على السمات الثلاث الموضحة أعلاه عند إنشاء كائن.

ماذا يعني هذا الخط؟

Self.wool_color = Wool_color

على الجانب الأيسر، نقوم بإنشاء سمة لقطتنا تسمى Wool_color، ثم نقوم بتعيين هذه السمة القيمة الموجودة في معلمة Wool_color التي مررناها إلى الدالة __init__(). كما ترون، السطر أعلاه لا يختلف عن إنشاء المتغير العادي. تشير البادئة self فقط إلى أن هذا المتغير ينتمي إلى فئة Cat.

يصف- متغير ينتمي إلى فئة.

لذلك، قمنا بإنشاء فئة القطط الجاهزة. هنا هو الكود الخاص به:

# فئة القطة فئة القط: # الإجراءات التي يجب تنفيذها عند إنشاء كائن "قطة" def __init__(self, Wool_color,eyes_color, name): self.wool_color = Wool_color self.eyes_color =eyes_color self.name = name # Purr defpurr( self): print("Purrr!") # Hiss def hiss(self): print("Shhh!") # Scratch def scrabble(self): print("Scratch-scratch!") # الكل معًا def all_in_one(self) : self.purr() self.hiss() self.scrabble()

أشياء

لقد أنشأنا مخطط القط. لنقم الآن بإنشاء كائن قطة حقيقي باستخدام هذا المخطط:

My_cat = قطة("أسود"، "أخضر"، "زوسيا")

في السطر أعلاه، قمنا بإنشاء متغير my_cat ثم قمنا بتعيين كائن من فئة Cat له. يبدو كل هذا بمثابة استدعاء لبعض الوظائف Cat(...) . في الواقع، هذا صحيح. باستخدام هذا الإدخال، نسمي الطريقة __init__()‎ لفئة Cat. تأخذ الدالة __init__() في فصلنا 4 وسائط: كائن الفئة الذاتية نفسه، والذي لا يحتاج إلى تحديد، بالإضافة إلى 3 وسائط أخرى مختلفة، والتي تصبح بعد ذلك سمات لقطتنا.

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

طباعة (my_cat.wool_color) طباعة (my_cat.eyes_color) طباعة (my_cat.name)

أي أنه يمكننا الوصول إلى سمات الكائن عن طريق كتابة اسم الكائن ووضع نقطة والإشارة إلى اسم السمة المطلوبة.

يمكن تغيير سمات القطة. على سبيل المثال، دعونا نغير اسم قطتنا:

My_cat.name = "نيوشا"

الآن، إذا قمت بعرض اسم القطة في وحدة التحكم مرة أخرى، فسوف ترى Nyusha بدلاً من Zosia.

اسمحوا لي أن أذكرك أن فصل قطتنا يسمح لها بأداء إجراءات معينة. إذا قمنا بمداعبة Zosya/Nyusha، فسوف تبدأ بالخرخرة:

My_cat.purr()

سيؤدي تنفيذ هذا الأمر إلى طباعة النص "Purrr!" على وحدة التحكم. كما ترون، الوصول إلى أساليب الكائن هو بنفس سهولة الوصول إلى سماته.

وحدات

أي ملف بامتداد .py هو وحدة نمطية. حتى تلك التي تعمل فيها على هذه المقالة. لماذا هم بحاجة؟ للراحة. يقوم الكثير من الأشخاص بإنشاء ملفات ذات وظائف وفئات مفيدة. يقوم المبرمجون الآخرون بتوصيل وحدات الطرف الثالث هذه ويمكنهم استخدام جميع الوظائف والفئات المحددة فيها، وبالتالي تبسيط عملهم.

على سبيل المثال، لا تحتاج إلى إضاعة الوقت في كتابة وظائفك الخاصة للعمل مع المصفوفات. يكفي توصيل الوحدة numpy واستخدام وظائفها وفئاتها.

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

تثبيت الوحدة

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

إذا كنت تريد استخدام وحدة نمطية غير مضمنة في المجموعة القياسية، فستحتاج إلى تثبيتها. لتثبيت الوحدة، افتح سطر الأوامر (Win + R، ثم أدخل "cmd" في الحقل الذي يظهر) وأدخل الأمر فيه:

تثبيت النقطة [module_name]

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

توصيل واستخدام الوحدة

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

استيراد [module_name]

على سبيل المثال، لاستيراد وحدة تسمح لك بالعمل مع الدوال الرياضية، تحتاج إلى كتابة ما يلي:

استيراد الرياضيات

كيفية الوصول إلى وظيفة الوحدة النمطية؟ تحتاج إلى كتابة اسم الوحدة، ثم وضع نقطة وكتابة اسم الوظيفة/الفئة. على سبيل المثال، تم إيجاد مضروب 10 على النحو التالي:

عامل الرياضيات(10)

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

جيمس لوي، جورجيا للتكنولوجيا. دليل المبتدئين لإنشاء الشبكة العصبية الخاصة بك في بايثون.

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

تحتوي هذه المقالة على ما تعلمته ونأمل أن يكون مفيدًا لك أيضًا! مقالات مفيدة أخرى حول هذا الموضوع:

ما هي الشبكة العصبية؟

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

تتكون الشبكات العصبية من المكونات التالية:

  • طبقة الإدخال، س
  • كمية تعسفية طبقات مخفية
  • طبقة الإخراج، ŷ
  • عدة المقاييسو النزوحبين كل طبقة دبليو و ب
  • خيار وظائف التنشيطلكل طبقة مخفية σ ; في هذا العمل سوف نستخدم وظيفة التنشيط السيني

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

يعد إنشاء فئة الشبكة العصبية في Python أمرًا بسيطًا:

تدريب الشبكات العصبية

مخرج ŷ شبكة عصبية بسيطة ذات طبقتين:

في المعادلة أعلاه، الأوزان W والتحيز b هي المتغيرات الوحيدة التي تؤثر على الإخراج ŷ.

وبطبيعة الحال، تحدد القيم الصحيحة للأوزان والتحيزات دقة التوقعات. تُعرف عملية ضبط الأوزان والتحيزات من البيانات المدخلة باسم تدريب الشبكة العصبية.

يتكون كل تكرار لعملية التعلم من الخطوات التالية

  • حساب الناتج المتوقع ŷ، يسمى الانتشار الأمامي
  • تحديث الأوزان والتحيزات، يسمى الانتشار العكسي

يوضح الرسم البياني المتسلسل أدناه العملية:

التوزيع المباشر

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

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

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

وظيفة الخسارة

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

مجموع الأخطاء المربعة هو متوسط ​​الفرق بين كل قيمة متوقعة وقيمة فعلية.

الهدف التعليمي هو إيجاد مجموعة من الأوزان والتحيزات التي تقلل من دالة الخسارة.

الانتشار العكسي

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

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

ولنتذكر من التحليل ذلك مشتق الدالة هو ميل الدالة.

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

ومع ذلك، لا يمكننا حساب مشتق دالة الخسارة بشكل مباشر فيما يتعلق بالأوزان والتحيزات لأن معادلة دالة الخسارة لا تحتوي على أوزان وتحيزات. لذا، نحن بحاجة إلى قاعدة سلسلة للمساعدة في العملية الحسابية.

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

دعونا نضيف وظيفة الانتشار العكسي إلى كود بايثون الخاص بنا:

التحقق من تشغيل الشبكة العصبية

الآن بعد أن حصلنا على كود بايثون الكامل الخاص بنا لإجراء النشر للأمام والخلف، فلنتجول عبر شبكتنا العصبية مع مثال ونرى كيف تعمل.


مجموعة مثالية من المقاييس

يجب أن تتعلم شبكتنا العصبية مجموعة الأوزان المثالية لتمثيل هذه الوظيفة.

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

دعونا نلقي نظرة على التنبؤ النهائي (الإخراج) من الشبكة العصبية بعد 1500 تكرار.

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

لاحظ أن هناك اختلافًا طفيفًا بين التوقعات والقيم الفعلية. وهذا أمر مرغوب فيه لأنه يمنع التجهيز الزائد ويسمح للشبكة العصبية بتعميم البيانات غير المرئية بشكل أفضل.

الأفكار النهائية

لقد تعلمت الكثير أثناء عملية كتابة شبكتي العصبية من الصفر. في حين أن مكتبات التعلم العميق مثل TensorFlow وKeras تسمح لك ببناء شبكات عميقة دون فهم كامل للعمل الداخلي للشبكة العصبية، إلا أنني أجد أنه من المفيد لعلماء البيانات الطموحين الحصول على فهم أعمق لها.

لقد استثمرت الكثير من وقتي الشخصي في هذا العمل، وآمل أن تجده مفيدًا!