الشبكات العصبية والتعلم العميق ، الفصل 3 ، الجزء 2: لماذا يساعد التنظيم على تقليل إعادة التدريب؟


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


من حيث المعنى ، نحن هنا ندرس ظاهرة العالم الحقيقي ، و x و y تدل على البيانات الحقيقية. هدفنا هو بناء نموذج يسمح لنا بالتنبؤ بـ y كدالة لـ x. يمكن أن نحاول استخدام شبكة عصبية لإنشاء مثل هذا النموذج ، لكنني أقترح شيئًا أكثر بساطة: سأحاول أن أقدم نموذج y على كثير الحدود في x. سأفعل ذلك بدلاً من الشبكات العصبية ، لأن استخدام كثير الحدود يجعل التفسير واضحًا بشكل خاص. حالما نتعامل مع قضية كثير الحدود ، سننتقل إلى الجمعية الوطنية. هناك عشر نقاط على الرسم البياني أعلاه ، مما يعني أنه يمكننا إيجاد متعدد الحدود الفريد من الترتيب التاسع y = a 0 x 9 + a 1 x 8 + ... + a 9 الذي يناسب البيانات تمامًا. وهنا هو الرسم البياني لهذا كثير الحدود.


ضرب الكمال. ولكن يمكننا الحصول على تقريب جيد باستخدام النموذج الخطي y = 2x


أيهما أفضل؟ أيهما أكثر احتمالا ليكون صحيحا؟ أيهما سيعمم بشكل أفضل على أمثلة أخرى لنفس ظاهرة العالم الحقيقي؟

أسئلة صعبة. ولا يمكن الإجابة عليها بالضبط دون معلومات إضافية حول ظاهرة العالم الحقيقي الأساسية. ومع ذلك ، فلنلقِ نظرة على احتمالين: (1) نموذج ذو كثير الحدود من الترتيب التاسع يصف حقًا ظاهرة العالم الحقيقي ، وبالتالي ، يتعمم بشكل مثالي ؛ (2) النموذج الصحيح هو y = 2x ، لكن لدينا ضوضاء إضافية مرتبطة بخطأ القياس ، وبالتالي فإن النموذج لا يصلح تمامًا.

بداهة ، لا يمكن للمرء أن يقول أي من الاحتمالين صحيح (أو أنه لا يوجد واحد ثالث). منطقيا ، قد يكون أي منهم صحيحا. والفرق بينهما غير بديهي. نعم ، بناءً على البيانات المتاحة ، يمكن القول أن هناك فرقًا بسيطًا بين الطرز. لكن لنفترض أننا نريد التنبؤ بقيمة y المقابلة لبعض القيمة الكبيرة x ، أكبر بكثير من أي من تلك الموضحة في الرسم البياني. إذا حاولنا القيام بذلك ، فسيظهر فرق كبير بين تنبؤات النموذجين ، حيث أن المصطلح x 9 يسيطر على كثير الحدود من الترتيب التاسع ، ويبقى النموذج الخطي خطيًا.

إحدى وجهات النظر حول ما يحدث هي الإشارة إلى أنه يجب استخدام تفسير أبسط في العلوم ، إن أمكن. عندما نجد نموذجًا بسيطًا يشرح العديد من النقاط المرجعية ، نريد فقط الصراخ: "Eureka!" بعد كل شيء ، فمن غير المرجح أن يظهر تفسير بسيط بحتة عن طريق الصدفة. نشك في أن النموذج يجب أن ينتج بعض الحقيقة المرتبطة بهذه الظاهرة. في هذه الحالة ، يبدو نموذج y = 2x + ضوضاء أبسط بكثير من y = a 0 x 9 + a 1 x 8 + ... سيكون من المدهش إذا نشأت البساطة عن طريق الصدفة ، لذلك نشك في أن y = 2x + الضوضاء تعبر عن بعض الحقيقة الكامنة. من وجهة النظر هذه ، يدرس نموذج الطلب التاسع ببساطة تأثير الضوضاء المحلية. على الرغم من أن نموذج الطلب التاسع يعمل بشكل مثالي مع هذه النقاط المرجعية المحددة ، فإنه لا يمكن تعميمه على نقاط أخرى ، ونتيجة لذلك سيكون للنموذج الخطي مع الضوضاء إمكانات تنبؤية أفضل.

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

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

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

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

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

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

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

تعود هذه المشكلات إلى مشكلة الحث ، حيث قام الفيلسوف الاسكتلندي ديفيد هيوم بتفسير معروف لها في كتاب " دراسة عن الإدراك البشري " (1748). مشكلة الاستقراء هي موضوع " نظرية عدم وجود وجبات مجانية " لديفيد والبرت وويليام ماكريدي (1977).

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

في الواقع ، فإن شبكاتنا تقوم بالفعل بتعميم أفضل بكثير مما كان متوقعًا مسبقًا. تحتوي الشبكة التي تحتوي على 100 خلية عصبية مخفية على حوالي 80،000 معلمة. لدينا فقط 50000 صورة في بيانات التدريب. هذا هو نفس محاولة تمديد كثير الحدود من 80000 طلب على 50000 نقطة مرجعية. بكل المؤشرات ، يجب إعادة تدريب شبكتنا بشكل رهيب. ومع ذلك ، كما رأينا ، فإن هذه الشبكة في الواقع تعمم بشكل جيد. لماذا يحدث هذا؟ هذا ليس واضحا تماما. تم الافتراض بأن "ديناميات التعلم عن طريق التدرج التدريجي في الشبكات متعددة الطبقات تخضع للتنظيم الذاتي". إنها ثروة كبيرة ، ولكنها أيضًا حقيقة مزعجة إلى حد ما ، حيث أننا لا نفهم سبب حدوث ذلك. في غضون ذلك ، سنتخذ نهجا عمليا ، وسوف نستخدم التنظيم كلما كان ذلك ممكنا. سيكون هذا مفيدًا للجمعية الوطنية.

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

تقنيات التنظيم الأخرى


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

تنظيم L1


في هذا النهج ، نقوم بتعديل دالة التكلفة غير المنتظمة بإضافة مجموع القيم المطلقة للأوزان:

C=C0+ frac lambdan sumw|w| العلامة95

العلامة



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

للقيام بذلك ، انظر إلى المشتقات الجزئية لوظيفة التكلفة. التمييز (95) ، نحصل على:

 frac جزئيةC جزئيةw= frac جزئيةC0 جزئيةw+ frac lambdan rmsgn(w) tag96

جزئيةجزئيةجزئيةجزئية،



حيث sgn (w) هي علامة w ، أي ، +1 إذا كانت w موجبة ، و -1 إذا كانت سالبة. باستخدام هذا التعبير ، نقوم بتعديل الانتشار الخلفي قليلاً بحيث ينفذ نزول الانحدار العشوائي باستخدام التنظيم L1. قاعدة التحديث النهائي للشبكة التي تمت صياغتها L1:

w rightarroww=w frac eta lambdan mboxsgn(w) eta frac الجزئيC0 الجزئيw tag97

الجزئيالجزئي



حيث ، كالعادة ، يمكن تقدير ∂C / ∂w اختيارياً باستخدام متوسط ​​قيمة الرزمة الصغيرة. قارن هذا مع قاعدة تحديث التنظيم L2 (93):

w rightarroww=w left(1 frac eta lambdan right) eta frac الجزئيC0 الجز ئ ي ث ا ل ع ل ا م ة 98 



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

لقد سهلت قليلاً مشكلة واحدة في المناقشة السابقة - المشتق الجزئي ∂C / ∂w غير محدد عند w = 0. هذا لأن الوظيفة | w | هناك "kink" الحاد عند النقطة w = 0 ؛ لذلك ، لا يمكن التمييز بينها. لكن هذا ليس مخيفا. نحن فقط نطبق القاعدة المعتادة غير المنتظمة لنسب الانحدار العشوائي عند w = 0. حدسي ، لا يوجد شيء خاطئ في ذلك - يجب أن يقلل التنظيم من الأوزان ، ومن الواضح أنه لا يمكن تقليل الأوزان التي تساوي بالفعل 0. بتعبير أدق ، سوف نستخدم المعادلتين (96) و (97) بشرط أن sgn (0) = 0. هذا سوف يعطينا قاعدة مريحة وصغيرة للنسب الانحداري العشوائي مع L1 التنظيم.

استثناء [التسرب]


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

لنفترض أننا نحاول تدريب شبكة:


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


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

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

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

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

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

وبطبيعة الحال ، فإن المقياس الحقيقي لفائدة الاستبعاد هو نجاحه الهائل في تحسين كفاءة الشبكات العصبية. في العمل الأصليحيث تم تقديم هذه الطريقة ، تم تطبيقها على العديد من المهام المختلفة. نحن مهتمون بشكل خاص بحقيقة أن المؤلفين طبقوا الاستثناء على تصنيف الأرقام من MNIST ، باستخدام شبكة توزيع مباشر بسيطة مماثلة لتلك التي درسناها. تلاحظ الورقة أنه حتى ذلك الحين ، كانت أفضل نتيجة لهذه البنية هي دقة 98.4 ٪. قاموا بتحسينه إلى 98.7٪ باستخدام مزيج من الاستبعاد وشكل معدّل من التنظيم L2. تم الحصول على نتائج مثيرة للإعجاب بنفس القدر للعديد من المهام الأخرى ، بما في ذلك التعرف على الأنماط والكلام ومعالجة اللغة الطبيعية. كان الاستثناء مفيدًا بشكل خاص في تدريب الشبكات العميقة الكبيرة ، حيث تنشأ مشكلة إعادة التدريب غالبًا.

توسيع مجموعة بيانات التدريب بشكل مصطنع


لقد رأينا سابقًا أن دقة تصنيف MNIST قد انخفضت إلى 80 بالمائة ، عندما استخدمنا 1000 صورة تدريب فقط. ولا عجب ، فمع وجود بيانات أقل ، ستلبي شبكتنا خيارات أقل لكتابة الأرقام بواسطة الأشخاص. دعونا نحاول تدريب شبكتنا المكونة من 30 خلية عصبية مخفية ، وذلك باستخدام أحجام مختلفة من مجموعة التدريب للنظر في التغير في الكفاءة. نقوم بتدريب باستخدام حجم الحزمة المصغرة وهو 10 ، وسرعة التعلم 0.5 = 0.5 ، ومعلمة التنظيم 5.0 = 5.0 ، ووظيفة التكلفة مع إنتروبيا. سنقوم بتدريب شبكة من 30 عصور باستخدام مجموعة كاملة من البيانات ، وزيادة عدد العصور بما يتناسب مع الانخفاض في حجم بيانات التدريب. لضمان نفس عامل تخفيض الوزن لمجموعات مختلفة من بيانات التدريب ، سوف نستخدم معامل التنظيم λ = 5 ،0 مع مجموعة تدريب كاملة ، والحد بشكل متناسب مع انخفاض في أحجام البيانات.


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


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

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



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

هذه الفكرة قوية جدا ، وتستخدم على نطاق واسع. دعونا نلقي نظرة على نتائج العمل العلميالذين طبقوا عدة أشكال من هذه الفكرة على MNIST. كانت إحدى بنيات الشبكات التي نظرت فيها مماثلة لتلك التي نستخدمها - شبكة توزيع مباشرة مع 800 خلية عصبية مخفية ، باستخدام دالة التكلفة مع إنتروبيا. من خلال إطلاق هذه الشبكة مع مجموعة التدريب MNIST القياسية ، حصلوا على دقة تصنيف 98.4 ٪. ولكن بعد ذلك قاموا بتوسيع بيانات التدريب ، ليس فقط باستخدام التناوب الذي وصفته أعلاه ، ولكن أيضًا نقل الصور وتشويهها. بعد تدريب الشبكة على البيانات المتقدمة ، زادوا من دقتها إلى 98.9 ٪. جربوا أيضا مع ما يسمى "تشويه مرن" ، نوع خاص من تشويه الصورة ، مصمم للقضاء على الاهتزازات العشوائية لعضلات اليد. باستخدام التشوهات المرنة لتوسيع البيانات ، حققوا دقة 99.3 ٪. في جوهرها ، وسعت تجربة شبكتهم ،يعطيها مختلف الاختلافات المكتوبة بخط اليد الموجودة في الكتابة اليدوية الحقيقية.

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

ممارسة


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

استطراد البيانات الضخمة ومعنى مقارنة دقة التصنيف


دعنا نلقي نظرة مرة أخرى على كيفية اختلاف دقة NS لدينا اعتمادا على حجم مجموعة التدريب:


لنفترض أنه بدلاً من استخدام NS ، سنستخدم تقنية أخرى للتعلم الآلي لتصنيف الأرقام. على سبيل المثال ، دعونا نحاول استخدام طريقة آلة ناقلات الدعم (SVM) ، والتي التقينا بها لفترة وجيزة في الفصل 1. وكما هو الحال ، لا تقلق إذا لم تكن معتادًا على SVM ، فنحن لسنا بحاجة إلى فهم تفاصيلها. سوف نستخدم SVM من خلال مكتبة scikit-learn. إليك كيف تختلف فعالية SVM مع حجم مجموعة التدريب. للمقارنة ، وضعت على الجدول الزمني ونتائج الجمعية الوطنية.


ربما أول ما يلفت انتباهك - NS يفوق SVM في أي حجم من مجموعة التدريب. هذا أمر جيد ، على الرغم من أنه لا يستحق استخلاص استنتاجات بعيدة المدى من هذا ، حيث أنني استخدمت إعدادات تعلم scikit المحددة مسبقًا ، وقد عملنا بجدية على NS لدينا. حقيقة أقل حيوية ، ولكنها أكثر إثارة للاهتمام ، والتي تتبع من الرسم البياني ، هي أنه إذا قمنا بتدريب SVM لدينا باستخدام 50000 صورة ، ستعمل بشكل أفضل (دقة 94.48 ٪) من NS لدينا المدربين مع 5000 صورة ( 93.24٪). بمعنى آخر ، فإن زيادة حجم بيانات التدريب تعوض أحيانًا عن الاختلاف في خوارزميات MO.

قد يحدث شيء أكثر إثارة للاهتمام. افترض أننا نحاول حل مشكلة باستخدام خوارزميات MO و A و B. في بعض الأحيان يحدث أن الخوارزمية A تسبق الخوارزمية B على مجموعة واحدة من بيانات التدريب ، والخوارزمية B تسبق الخوارزمية A على مجموعة أخرى من بيانات التدريب. لم نر هذا أعلاه - ثم تتقاطع الرسوم البيانية - لكن هذا يحدث . الإجابة الصحيحة على السؤال: "هل الخوارزمية أ أعلى من الخوارزمية B؟" في الواقع ، هذا: "ما هي مجموعة بيانات التدريب التي تستخدمها؟"

كل هذا يجب أن يؤخذ في الاعتبار ، سواء أثناء التطوير أو عند قراءة الأوراق العلمية. تركز العديد من الأعمال على إيجاد حيل جديدة للضغط على نتائج أفضل على مجموعات بيانات القياس القياسية. "لقد أتاحت لنا تقنية الأطعمة الممتازة لدينا تحسينًا بنسبة X٪ على المجموعة المقارنة القياسية Y" - نموذج الطلب الأساسي في مثل هذه الدراسة. في بعض الأحيان تكون هذه التصريحات مثيرة للاهتمام بالفعل ، ولكن من المفيد أن نفهم أنها قابلة للتطبيق فقط في سياق مجموعة تدريب محددة. تخيل قصة بديلة حصل فيها الأشخاص الذين قاموا في البداية بإنشاء مجموعة مقارنة على منحة بحثية أكبر. يمكنهم استخدام أموال إضافية لجمع بيانات إضافية. من الممكن أن يختفي "تحسين" تقنية المخادع الفائقة في مجموعة بيانات أكبر. وبعبارة أخرى ،جوهر التحسين قد يكون مجرد حادث. من هذا ، ينبغي الأخذ في الأخلاق التالية في مجال التطبيق العملي: نحن بحاجة إلى كل من الخوارزميات المحسنة وبيانات التدريب المحسنة. لا حرج في البحث عن خوارزميات محسّنة ، ولكن تأكد من أنك لا تركز على ذلك ، مع تجاهل الطريقة الأسهل للفوز بزيادة حجم أو جودة بيانات التدريب.

مهمة


  • . ? . – , , , . , . - ? , .

النتائج


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

تهيئة الوزن


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

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


للبساطة ، تخيل أننا نحاول تدريب شبكة مع إدخال x ، حيث يتم تشغيل نصف الخلايا العصبية المدخلة ، أي أن لها قيمة 1 ، ويتم إيقاف تشغيل نصفها ، أي أنها لها قيمة 0. والحجة التالية تعمل في الحالة العامة ، ولكنها أسهل سوف نفهمه في هذا المثال بالذات. النظر في المبلغ المرجح z = ∑ j w j x j + b من المدخلات لخلايا عصبية مخفية. يختفي 500 عضو من المجموع لأن x x المقابلة هي 0. لذلك ، z هي مجموع 501 من المتغيرات العشوائية الغوسية المقيسة ، و 500 أوزان ، وإزاحة واحدة إضافية. لذلك ، فإن القيمة z نفسها لها توزيع غوسي بتوقع رياضي قدره 0 وانحراف معياري قدره √501 ≈ 22.4. وهذا يعني أن z لها توزيع غوسي واسع إلى حد ما ، بدون قمم حادة:


على وجه الخصوص ، يوضح هذا الرسم البياني أن | z ​​| من المحتمل أن تكون كبيرة جدًا ، أي z ≫ 1 أو z ≫ -1. في هذه الحالة ، سيكون إخراج الخلايا العصبية المخفية σ (z) قريبًا جدًا من 1 أو 0. وهذا يعني أن الخلايا العصبية المخفية لدينا ستكون مشبعة. وعندما يحدث هذا ، كما نعلم بالفعل ، فإن التغييرات الصغيرة في الأوزان ستنتج تغييرات صغيرة في تنشيط الخلايا العصبية المخفية. هذه التغييرات الصغيرة ، بدورها ، لن تؤثر عملياً على ما تبقى من النيوترونات في الشبكة ، وسوف نرى التغييرات الصغيرة المقابلة في وظيفة التكلفة. نتيجة لذلك ، سيتم تدريب هذه الأوزان ببطء شديد عندما نستخدم خوارزمية النسب التدرج. هذا مشابه للمهمة التي ناقشناها بالفعل في هذا الفصل ، والتي تؤدي فيها الخلايا العصبية الناتجة المشبعة بقيم غير صحيحة إلى تباطؤ التعلم. اعتدنا على حل هذه المشكلة عن طريق اختيار بذكاء وظيفة التكلفة. لسوء الحظ ، على الرغم من أن هذا ساعد في الخلايا العصبية الناتجة المشبعة ، إلا أنه لا يساعد على الإطلاق في تشبع الخلايا العصبية المخفية.

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

هل هناك طريقة لاختيار أفضل خيارات التهيئة للأوزان والإزاحة ، حتى لا نحصل على هذا التشبع ، ويمكننا تجنب التأخير في التعلم؟ لنفترض أن لدينا خلية عصبية مع عدد الأوزان الواردة n في . ثم نحتاج إلى تهيئة هذه الأوزان بتوزيعات غوسية عشوائية بتوقع رياضي قدره 0 وانحراف معياري قدره 1 / √n. وهذا يعني أننا نضغط الغاوسيين ، ونقلل من احتمال تشبع الخلايا العصبية. بعد ذلك ، نختار توزيعًا غوسيًا لعمليات الإزاحة مع توقع رياضي قدره 0 وانحراف معياري قدره 1 ، لأسباب سأعود إليها لاحقًا. بعد اتخاذ هذا الاختيار ، وجدنا مرة أخرى أن z = w j w j x j + b ستكون متغيرًا عشوائيًا مع توزيع غوسي بتوقعات رياضية تساوي 0 ، ولكن مع ذروة أكثر وضوحًا من ذي قبل. لنفترض ، كما كان من قبل ، أن 500 مدخلات هي 0 و 500 هي 1. ثم ، من السهل أن نوضح (راجع التمرين أدناه) أن z لها توزيع غوسي بتوقع رياضي قدره 0 وانحراف معياري لـ √ (3/2) = 1.22 ... يحتوي هذا الرسم البياني على ذروة أكثر وضوحًا ، لدرجة أنه حتى في الصورة أدناه ، يكون الوضع أقل من ذلك إلى حد ما ، لأنني اضطررت إلى تغيير مقياس المحور العمودي مقارنة بالرسم البياني السابق:


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

ممارسة


  • تأكد من أن الانحراف المعياري لـ z = ∑ j w j x + j + b من الفقرة السابقة هو √ (3/2). اعتبارات لصالح ذلك: التباين في مجموع المتغيرات العشوائية المستقلة يساوي مجموع الفروق في المتغيرات العشوائية الفردية ؛ الفرق يساوي مربع الانحراف المعياري.

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

دعونا نقارن نتائج الأساليب القديمة والجديدة لتهيئة الأوزان باستخدام مهمة تصنيف الأرقام من MNIST. كما كان من قبل ، سوف نستخدم 30 خلية عصبية مخفية ، رزمة صغيرة بحجم 10 ، معلمة تنظيم & lambda = 5.0 ، ووظيفة تكلفة مع إنتروبيا. سنقوم تدريجياً بتقليل سرعة التعلم من η = 0.5 إلى 0.1 ، نظرًا لأن هذه الطريقة ستكون النتائج أفضل قليلاً على الرسوم البيانية. يمكنك تعلم استخدام طريقة التهيئة القديمة للوزن:

>>> import mnist_loader >>> training_data, validation_data, test_data = \ ... mnist_loader.load_data_wrapper() >>> import network2 >>> net = network2.Network([784, 30, 10], cost=network2.CrossEntropyCost) >>> net.large_weight_initializer() >>> net.SGD(training_data, 30, 10, 0.1, lmbda = 5.0, ... evaluation_data=validation_data, ... monitor_evaluation_accuracy=True) 

يمكنك أيضًا تعلم استخدام الطريقة الجديدة لتهيئة الأوزان. هذا أبسط من ذلك ، لأنه من خلال شبكة افتراضية 2 ، يتم تهيئة الأوزان باستخدام طريقة جديدة. هذا يعني أنه يمكننا حذف مكالمة net.large_weight_initializer () السابقة:

 >>> net = network2.Network([784, 30, 10], cost=network2.CrossEntropyCost) >>> net.SGD(training_data, 30, 10, 0.1, lmbda = 5.0, ... evaluation_data=validation_data, ... monitor_evaluation_accuracy=True) 

نحن مؤامرة (باستخدام برنامج weight_initialization.py):


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


في هذه الحالة ، لا يحدث منحنيان. ومع ذلك ، تقول تجاربي أنه إذا قمت بإضافة عصور أكثر بقليل ، فإن الدقة تبدأ بالتزامن تقريبًا. لذلك ، على أساس هذه التجارب ، يمكننا القول أن تحسين تهيئة الأوزان يؤدي فقط إلى زيادة سرعة التدريب ، ولكنه لا يغير من كفاءة الشبكة ككل. ومع ذلك ، في الفصل 4 ، سنرى أمثلة على NSs يتم فيها تحسين الكفاءة طويلة الأجل بشكل كبير نتيجة لتهيئة الأوزان من خلال 1 / inn في . لذلك ، فإنه لا يحسن فقط سرعة التعلم ، ولكن في بعض الأحيان فعالية الناتجة.

يساعد نهج تهيئة الأوزان من خلال 1 / inn في تحسين تدريب الشبكات العصبية. تم اقتراح تقنيات أخرى لتهيئة الأوزان ، يعتمد الكثير منها على هذه الفكرة الأساسية. لن أعتبرها هنا ، لأن 1 / inn يعمل بشكل جيد لأغراضنا. إذا كنت مهتمًا ، أوصي بقراءة المناقشة في الصفحتين 14 و 15 في ورقة 2012 التي أعدها Yoshua Benggio.

مهمة


  • مزيج من تنظيم وتحسين طريقة التهيئة الوزن. في بعض الأحيان ، يمنحنا ضبط L2 تلقائيًا نتائج مشابهة لطريقة جديدة لتهيئة الأوزان. دعنا نقول أننا نستخدم النهج القديم لتهيئة الأوزان. حدد حجة إرشادية تثبت ما يلي: (1) إذا كانت small ليست صغيرة جدًا ، فعندها في الحلقات الأولى من التدريب ، سيضعف ضعف الأوزان بشكل كامل تقريبًا ؛ (2) إذا ηλ ≪ n ، فإن الأوزان ستضعف عدد مرات e / m في الحقبة ؛ (3) إذا كانت large ليست كبيرة جدًا ، فسوف يتباطأ ضعف الأوزان عندما تنخفض الأوزان إلى حوالي 1 / √n ، حيث n هو العدد الإجمالي للأوزان في الشبكة. أثبت أن هذه الشروط مستوفاة في الأمثلة التي تم إنشاؤها من خلالها الرسوم البيانية في هذا القسم.


العودة إلى التعرف على خط اليد: رمز


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

كما هو الحال مع network.py ، نجم network2.py هو فئة الشبكة ، والتي نستخدمها لتمثيل NSs لدينا. نحن نهيئ مثيل الفئة مع قائمة بأحجام طبقات الشبكة المقابلة ، وباختيار وظيفة التكلفة ، سيكون التقاطع الافتراضي هو:

 class Network(object): def __init__(self, sizes, cost=CrossEntropyCost): self.num_layers = len(sizes) self.sizes = sizes self.default_weight_initializer() self.cost=cost 

أول سطرين من الأسلوب __init__ هما نفس network.py ، ويتم فهمهما بأنفسهما. الخطان التاليان جديدان ، وعلينا أن نفهم بالتفصيل ما الذي يقومون به.

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

  def default_weight_initializer(self): self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]] self.weights = [np.random.randn(y, x)/np.sqrt(x) for x, y in zip(self.sizes[:-1], self.sizes[1:])] 

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

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

  def large_weight_initializer(self): self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]] self.weights = [np.random.randn(y, x) for x, y in zip(self.sizes[:-1], self.sizes[1:])] 

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

الجدة الثانية لطريقة __init__ هي تهيئة سمة التكلفة. لفهم كيفية عمل ذلك ، دعنا ننظر إلى الفصل الذي نستخدمه لتمثيل دالة تكلفة الانتروبيا (يخبر توجيهstaticmethod المترجم أن هذه الطريقة مستقلة عن الكائن ، وبالتالي لا يتم تمرير المعلمة الذاتية إلى أساليب fn و delta).

 class CrossEntropyCost(object): @staticmethod def fn(a, y): return np.sum(np.nan_to_num(-y*np.log(a)-(1-y)*np.log(1-a))) @staticmethod def delta(z, a, y): return (ay) 

دعونا معرفة ذلك. أول ما يمكن رؤيته هنا هو أنه على الرغم من أن الانتروبيا المتقاطعة هي وظيفة من وجهة نظر رياضية ، إلا أننا نطبقها كصف بيثون ، وليس كدالة بيثون. لماذا قررت أن أفعل هذا؟ في شبكتنا ، تلعب القيمة دورين مختلفين. واضح - وهو مقياس لمدى توافق تنشيط الإخراج مع الإخراج المطلوب y. يتم توفير هذا الدور بواسطة أسلوب CrossEntropyCost.fn. (بالمناسبة ، لاحظ أن استدعاء np.nan_to_num داخل CrossEntropyCost.fn يضمن أن Numpy يعالج بشكل صحيح لوغاريتم الأرقام القريبة من الصفر). ومع ذلك ، يتم استخدام وظيفة التكلفة في شبكتنا في الطريقة الثانية. نذكر من الفصل 2 أنه عند بدء تشغيل خوارزمية backpropagation ، نحتاج إلى النظر في خطأ إخراج الشبكة δ L. يعتمد شكل خطأ الإخراج على دالة التكلفة: سيكون لوظائف التكلفة المختلفة أشكال مختلفة من خطأ الإخراج. بالنسبة للإنتروبيا ، سيكون خطأ الخرج ، كما يلي من المعادلة (66) ، مساوياً لـ:

 د ه ل ر ل L = ل L - ذ ر و ز 99 



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

لسبب مشابه ، يحتوي network2.py على فئة تمثل دالة تكلفة من الدرجة الثانية. بما في ذلك هذا للمقارنة مع نتائج الفصل 1 ، حيث أننا في المستقبل سوف نستخدم بشكل رئيسي إنتروبيا. الرمز أدناه. طريقة QuadraticCost.fn هي حساب بسيط للتكلفة التربيعية المرتبطة بالإخراج a والإخراج المطلوب y. تستند القيمة التي يتم إرجاعها بواسطة QuadraticCost.delta إلى التعبير (30) لخطأ الإخراج الخاص بالقيمة التربيعية ، والتي استنتجناها في الفصل 2.

 class QuadraticCost(object): @staticmethod def fn(a, y): return 0.5*np.linalg.norm(ay)**2 @staticmethod def delta(z, a, y): return (ay) * sigmoid_prime(z) 

الآن اكتشفنا الاختلافات الرئيسية بين network2.py و network2.py. كل شيء بسيط جدا. هناك تغييرات صغيرة أخرى سأصفها أدناه ، بما في ذلك تنفيذ L2. قبل ذلك ، دعونا نلقي نظرة على رمز network2.py الكامل. ليس من الضروري دراسته بالتفصيل ، لكن الأمر يستحق فهم الهيكل الأساسي ، على وجه الخصوص ، قراءة التعليقات لفهم ما يقوم به كل جزء من أجزاء البرنامج. بالطبع ، أنا لا أحظر الخوض في هذا السؤال بقدر ما تريد! إذا فقدت ، حاول قراءة النص بعد البرنامج ، والعودة إلى الرمز مرة أخرى. بشكل عام ، ومن هنا:

 """network2.py ~~~~~~~~~~~~~~   network.py,            .   –      , ,   .     ,    .   ,       . """ ####  #  import json import random import sys #  import numpy as np ####   ,      class QuadraticCost(object): @staticmethod def fn(a, y): """ ,    ``a``    ``y``. """ return 0.5*np.linalg.norm(ay)**2 @staticmethod def delta(z, a, y): """  delta   .""" return (ay) * sigmoid_prime(z) class CrossEntropyCost(object): @staticmethod def fn(a, y): """ ,    ``a``    ``y``. np.nan_to_num    .  ,   ``a``  ``y``      1.0,   (1-y)*np.log(1-a)  nan. np.nan_to_num ,       (0.0). """ return np.sum(np.nan_to_num(-y*np.log(a)-(1-y)*np.log(1-a))) @staticmethod def delta(z, a, y): """  delta   .  ``z``    ,          delta     . """ return (ay) ####   Network class Network(object): def __init__(self, sizes, cost=CrossEntropyCost): """  sizes      .  ,      Network      ,     ,     ,    ,  [2, 3, 1].       ,   ``self.default_weight_initializer`` (.  ). """ self.num_layers = len(sizes) self.sizes = sizes self.default_weight_initializer() self.cost=cost def default_weight_initializer(self): """            0    1,       ,       .          0    1.    ,         ,           . """ self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]] self.weights = [np.random.randn(y, x)/np.sqrt(x) for x, y in zip(self.sizes[:-1], self.sizes[1:])] def large_weight_initializer(self): """          0    1.          0    1.    ,         ,           .         1,    .       . """ self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]] self.weights = [np.random.randn(y, x) for x, y in zip(self.sizes[:-1], self.sizes[1:])] def feedforward(self, a): """  ,  ``a``  .""" for b, w in zip(self.biases, self.weights): a = sigmoid(np.dot(w, a)+b) return a def SGD(self, training_data, epochs, mini_batch_size, eta, lmbda = 0.0, evaluation_data=None, monitor_evaluation_cost=False, monitor_evaluation_accuracy=False, monitor_training_cost=False, monitor_training_accuracy=False): """     -    . ``training_data`` –   ``(x, y)``,       .       ,    ``lmbda``.    ``evaluation_data``,     ,   .         ,     ,   .      :   ,    ,   ,              .  ,      30 ,        30 ,        .     ,   . """ if evaluation_data: n_data = len(evaluation_data) n = len(training_data) evaluation_cost, evaluation_accuracy = [], [] training_cost, training_accuracy = [], [] for j in xrange(epochs): random.shuffle(training_data) mini_batches = [ training_data[k:k+mini_batch_size] for k in xrange(0, n, mini_batch_size)] for mini_batch in mini_batches: self.update_mini_batch( mini_batch, eta, lmbda, len(training_data)) print "Epoch %s training complete" % j if monitor_training_cost: cost = self.total_cost(training_data, lmbda) training_cost.append(cost) print "Cost on training data: {}".format(cost) if monitor_training_accuracy: accuracy = self.accuracy(training_data, convert=True) training_accuracy.append(accuracy) print "Accuracy on training data: {} / {}".format( accuracy, n) if monitor_evaluation_cost: cost = self.total_cost(evaluation_data, lmbda, convert=True) evaluation_cost.append(cost) print "Cost on evaluation data: {}".format(cost) if monitor_evaluation_accuracy: accuracy = self.accuracy(evaluation_data) evaluation_accuracy.append(accuracy) print "Accuracy on evaluation data: {} / {}".format( self.accuracy(evaluation_data), n_data) print return evaluation_cost, evaluation_accuracy, \ training_cost, training_accuracy def update_mini_batch(self, mini_batch, eta, lmbda, n): """    ,          -. ``mini_batch`` –    ``(x, y)``, ``eta`` –  , ``lmbda`` -  , ``n`` -     .""" nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights] for x, y in mini_batch: delta_nabla_b, delta_nabla_w = self.backprop(x, y) nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)] nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)] self.weights = [(1-eta*(lmbda/n))*w-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)] self.biases = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.biases, nabla_b)] def backprop(self, x, y): """  ``(nabla_b, nabla_w)``,      C_x. ``nabla_b``  ``nabla_w`` -    numpy,   ``self.biases`` and ``self.weights``.""" nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights] #   activation = x activations = [x] #      zs = [] #     z- for b, w in zip(self.biases, self.weights): z = np.dot(w, activation)+b zs.append(z) activation = sigmoid(z) activations.append(activation) # backward pass delta = (self.cost).delta(zs[-1], activations[-1], y) nabla_b[-1] = delta nabla_w[-1] = np.dot(delta, activations[-2].transpose()) """  l      ,      . l = 1    , l = 2 – ,   .    ,   python      . """ for l in xrange(2, self.num_layers): z = zs[-l] sp = sigmoid_prime(z) delta = np.dot(self.weights[-l+1].transpose(), delta) * sp nabla_b[-l] = delta nabla_w[-l] = np.dot(delta, activations[-l-1].transpose()) return (nabla_b, nabla_w) def accuracy(self, data, convert=False): """    ``data``,      .   –        .  ``convert``  False,    –    ( )  True,   .    - ,  ``y`` -     .  ,       .           .          ?     –       ,      .   ,      .       mnist_loader.load_data_wrapper. """ if convert: results = [(np.argmax(self.feedforward(x)), np.argmax(y)) for (x, y) in data] else: results = [(np.argmax(self.feedforward(x)), y) for (x, y) in data] return sum(int(x == y) for (x, y) in results) def total_cost(self, data, lmbda, convert=False): """      ``data``.  ``convert``   False,   –  (),   True,   –   . .    ,      ``accuracy``, . """ cost = 0.0 for x, y in data: a = self.feedforward(x) if convert: y = vectorized_result(y) cost += self.cost.fn(a, y)/len(data) cost += 0.5*(lmbda/len(data))*sum( np.linalg.norm(w)**2 for w in self.weights) return cost def save(self, filename): """    ``filename``.""" data = {"sizes": self.sizes, "weights": [w.tolist() for w in self.weights], "biases": [b.tolist() for b in self.biases], "cost": str(self.cost.__name__)} f = open(filename, "w") json.dump(data, f) f.close() ####  Network def load(filename): """    ``filename``.    Network. """ f = open(filename, "r") data = json.load(f) f.close() cost = getattr(sys.modules[__name__], data["cost"]) net = Network(data["sizes"], cost=cost) net.weights = [np.array(w) for w in data["weights"]] net.biases = [np.array(b) for b in data["biases"]] return net ####   def vectorized_result(j): """  10-    1.0   j     .      (0..9)     . """ e = np.zeros((10, 1)) e[j] = 1.0 return e def sigmoid(z): """.""" return 1.0/(1.0+np.exp(-z)) def sigmoid_prime(z): """ .""" return sigmoid(z)*(1-sigmoid(z)) 

من بين التغييرات الأكثر إثارة للاهتمام هو إدراج L2 التنظيم. على الرغم من أن هذا يعد تغييرًا كبيرًا في المفاهيم ، إلا أنه من السهل تنفيذه بحيث لا تلاحظه في الكود. بالنسبة للجزء الأكبر ، وهذا ببساطة تمرير المعلمة lmbda إلى أساليب مختلفة ، وخاصة Network.SGD. يتم تنفيذ جميع الأعمال في سطر واحد من البرنامج ، والرابع من النهاية في طريقة Network.update_mini_batch. هناك نقوم بتغيير قاعدة التحديث نزول التدرج لتشمل تخفيض الوزن. التغيير ضئيل ، لكنه يؤثر بشكل خطير على النتائج!

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

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

 >>> import mnist_loader >>> training_data, validation_data, test_data = \ ... mnist_loader.load_data_wrapper() >>> import network2 >>> net = network2.Network([784, 30, 10], cost=network2.CrossEntropyCost) >>> net.SGD(training_data, 30, 10, 0.5, ... lmbda = 5.0, ... evaluation_data=validation_data, ... monitor_evaluation_accuracy=True, ... monitor_evaluation_cost=True, ... monitor_training_accuracy=True, ... monitor_training_cost=True) 

نحن نضع بيانات التقييم من خلال validation_data. ومع ذلك ، يمكننا تتبع الأداء على test_data وأي مجموعة بيانات أخرى. لدينا أيضًا أربعة أعلام تحدد الحاجة إلى تتبع التكلفة والدقة في كل من بيانات التقييم وبيانات التدريب. يتم تعيين هذه العلامات على False بشكل افتراضي ، ومع ذلك يتم تضمينها هنا لتتبع فعالية الشبكة. علاوة على ذلك ، تُرجع طريقة Network.SGD من network2.py مجموعة مكونة من أربعة عناصر تمثل نتائج التتبع. يمكنك استخدامه مثل هذا:

 >>> evaluation_cost, evaluation_accuracy, ... training_cost, training_accuracy = net.SGD(training_data, 30, 10, 0.5, ... lmbda = 5.0, ... evaluation_data=validation_data, ... monitor_evaluation_accuracy=True, ... monitor_evaluation_cost=True, ... monitor_training_accuracy=True, ... monitor_training_cost=True) 

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

تتضمن إضافات التعليمات البرمجية الأخرى طريقة Network.save ، التي تحفظ كائن الشبكة على القرص ، ووظيفة تحميله في الذاكرة. يتم الحفظ والتحميل عبر JSON ، وليس وحدات مخلل Python أو cPickle ، والتي تُستخدم عادةً لحفظها على القرص وتحميلها في الثعبان. يتطلب استخدام JSON رمزًا أكثر مما سيكون ضروريًا للمخلل أو cPickle. لفهم لماذا اخترت JSON ، تخيل أننا في مرحلة ما في المستقبل قررنا تغيير فئة شبكتنا بحيث كان هناك أكثر من الخلايا العصبية السيني. لتنفيذ هذا التغيير ، من المرجح أن نغير السمات المحددة في طريقة الشبكة .__ init__. وإذا استخدمنا المخلل للحفظ ، فلن تعمل وظيفة الحمل لدينا. باستخدام JSON مع التسلسل الصريح يجعل من السهل بالنسبة لنا لضمانيمكن تنزيل الإصدارات القديمة من كائن الشبكة.

هناك العديد من التغييرات الصغيرة في الكود ، ولكن هذه مجرد أشكال صغيرة من network.py. النتيجة النهائية هي امتداد برنامجنا المكون من 74 سطرًا إلى برنامج أكثر فاعلية من 152 سطرًا.

مهمة


  • عدِّل الرمز أدناه من خلال إدخال التنظيم L1 ، واستخدمه لتصنيف أرقام MNIST بواسطة شبكة تضم 30 خلية عصبية مخفية. هل يمكنك اختيار معلمة ضبط تسمح لك بتحسين النتيجة مقارنة بالشبكة دون التنظيم؟
  • Network.cost_derivative method network.py. . ? , ? network2.py Network.cost_derivative, CrossEntropyCost.delta. ?

Source: https://habr.com/ru/post/ar459816/


All Articles