Nano-neuron - 7 وظائف جافا سكريبت بسيطة توضح كيف يمكن للآلة "التعلم"

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


يتكون كود NanoNeuron.js من 7 وظائف جافا سكريبت بسيطة تتضمن التعلم والتدريب والتنبؤ والإشارة المباشرة والخلفية لإشارة النموذج. كان الغرض من كتابة هذه الوظائف هو إعطاء القارئ شرحًا بسيطًا (حدسيًا) بسيطًا عن كيفية "تعلم" الآلة بعد كل شيء. لا يستخدم الكود مكتبات الطرف الثالث. كما يقول المثل ، وظائف جافا سكريبت "الفانيليا" بسيطة فقط.


هذه الوظائف ليست بأي حال دليلاً شاملاً للتعلم الآلي. العديد من مفاهيم التعلم الآلي مفقودة أو مبسطة! يُسمح بهذا التبسيط للغرض الوحيد - لإعطاء القارئ الفهم والحدس الأكثر أساسية حول كيفية "تعلُّم" الآلة من حيث المبدأ ، ونتيجة لذلك ، يبدو "MAGIC of machine machine" أكثر فأكثر للقارئ كـ "MATHEMATICS من تعلم الآلة".


NanoNeuron


ما سوف نتعلمه من الخلايا العصبية النانوية لدينا


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


بالمناسبة ، صيغة تحويل الدرجات المئوية إلى درجة فهرنهايت هي كما يلي:


مئوية إلى فهرنهايت


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


نموذج النانو العصبية


لنبدأ بإنشاء وظيفة تصف نموذج العصبونات النانوية. هذا النموذج هو علاقة خطية بسيطة بين x و y ، والتي تبدو كما يلي: y = w * x + b . ببساطة ، لدينا nano-neuron هو طفل يمكنه رسم خط مستقيم في نظام الإحداثيات XY .


المتغيرات w و b هي معلمات طراز. يعرف النانو العصبي هاتين المعلمتين لوظيفة خطية فقط. هذه المعلمات هي بالضبط ما سوف نتعلمه من الخلايا العصبية النانوية لدينا خلال عملية التدريب.


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


 function NanoNeuron(w, b) { this.w = w; this.b = b; this.predict = (x) => { return x * this.w + this.b; } } 

_ (... انتظر ... الانحدار الخطي هو أنت ، أم ماذا؟) _


تحويل درجة مئوية إلى درجة فهرنهايت


يمكن تحويل درجة الحرارة بالدرجات المئوية إلى فهرنهايت وفقًا للصيغة: f = 1.8 * c + 32 ، حيث c هي درجة الحرارة بالدرجات Celsius و f هي درجة الحرارة بالدرجات فهرنهايت.


 function celsiusToFahrenheit(c) { const w = 1.8; const b = 32; const f = c * w + b; return f; }; 

نتيجة لذلك ، نريد أن يكون لدينا خلية عصبية نانو قادرة على محاكاة هذه الوظيفة بالذات. سيتعين عليه تخمين (معرفة) أن المعلمة w = 1.8 و b = 32 دون معرفة ذلك مقدمًا.


هذه هي الطريقة التي تبدو بها وظيفة التحويل على الرسم البياني. هذا ما يجب أن يتعلمه "الطفل" النانوي العصبي لدينا "لرسم":


مئوية إلى فهرنهايت التحويل


توليد البيانات


في البرمجة الكلاسيكية ، نعرف بيانات الإدخال ( x ) والخوارزمية لتحويل هذه البيانات (المعلمتان w و b ) ، لكن بيانات الإخراج ( y ) غير معروفة. يتم حساب الناتج بناءً على المدخلات باستخدام خوارزمية معروفة. على العكس من ذلك ، في التعلم الآلي ، فقط بيانات المدخلات والمخرجات ( x و y ) معروفة ، لكن خوارزمية التبديل من x إلى y معروفة (المعلمتان w و b ).


إنه توليد المدخلات والمخرجات التي سنفعلها الآن. نحن بحاجة إلى توليد بيانات لتدريب نموذجنا وبياناتنا لاختبار النموذج. سوف تساعدنا وظيفة المساعد celsiusToFahrenheit() هذا. كل مجموعة من مجموعات بيانات التدريب والاختبار هي مجموعة من الأزواج x و y . على سبيل المثال ، إذا كانت x = 2 ، ثم y = 35,6 وهكذا.


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

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


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

استطرادا. دعنا نستمر.


سوف نستخدم مجموعة بيانات TEST لتقييم مدى جودة تدريب الخلايا العصبية النانوية لدينا ، ويمكننا التنبؤ بالبيانات الصحيحة التي لم يراها أثناء تدريبه.


 function generateDataSets() { // xTrain -> [0, 1, 2, ...], // yTrain -> [32, 33.8, 35.6, ...] const xTrain = []; const yTrain = []; for (let x = 0; x < 100; x += 1) { const y = celsiusToFahrenheit(x); xTrain.push(x); yTrain.push(y); } // xTest -> [0.5, 1.5, 2.5, ...] // yTest -> [32.9, 34.7, 36.5, ...] const xTest = []; const yTest = []; //   0.5    1,       //   ,       . for (let x = 0.5; x < 100; x += 1) { const y = celsiusToFahrenheit(x); xTest.push(x); yTest.push(y); } return [xTrain, yTrain, xTest, yTest]; } 

تقدير خطأ التنبؤ


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


في حالة الخلايا العصبية النانوية ، سيتم إنتاج الخطأ (الخطأ) بين القيمة الحقيقية للقيمة y والقيمة المتوقعة prediction من خلال الصيغة:


تكلفة التنبؤ


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


ستبدو وظيفة الخطأ في هذه الحالة كما يلي:


 function predictionCost(y, prediction) { return (y - prediction) ** 2 / 2; // ie -> 235.6 } 

انتشار إشارة مباشرة


يعني انتشار الإشارة المباشرة من خلال نموذجنا عمل تنبؤات لجميع الأزواج من مجموعة بيانات التدريب yTrain و yTrain وحساب متوسط ​​الخطأ (خطأ) من هذه التنبؤات.


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


سيتم تنفيذ متوسط ​​خطأ التنبؤ بخلية nano-neuron باستخدام الصيغة التالية:


متوسط ​​التكلفة


حيث m هو عدد نسخ التدريب (في حالتنا ، لدينا 100 زوج من البيانات).


إليك كيفية تنفيذ ذلك في الكود:


 function forwardPropagation(model, xTrain, yTrain) { const m = xTrain.length; const predictions = []; let cost = 0; for (let i = 0; i < m; i += 1) { const prediction = nanoNeuron.predict(xTrain[i]); cost += predictionCost(yTrain[i], prediction); predictions.push(prediction); } //     . cost /= m; return [predictions, cost]; } 

انتشار إشارة عكس


الآن وقد عرفنا مدى صحة أو عدم صحة الخلايا العصبية النانوية في تنبؤاتها (استنادًا إلى متوسط ​​قيمة الخطأ) ، كيف يمكننا أن نجعل التنبؤات أكثر دقة؟


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


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


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


المشتقات هي موضوع كبير ومنفصل لن نغطيه في هذه المقالة. MathIsFun هو مورد رائع يمكنه توفير فهم أساسي للمشتقات.


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


منحدر مشتق


الصورة مأخوذة من MathIsFun


على سبيل المثال ، في الرسم البياني أعلاه ، ترى أنه عند النقطة (x=2, y=4) ميل المنحدر أننا نحتاج إلى التحرك للوصول إلى الحد الأدنى من الوظيفة. لاحظ أيضًا أنه كلما زاد ميل الظل ، يجب أن نتحرك بشكل أسرع إلى الحد الأدنى.


المشتقات من متوسط ​​الخطأ لدينا دالة averageCost المعلمات w و b ستبدو كما يلي:


DW


ديسيبل


حيث m هو عدد نسخ التدريب (في حالتنا ، لدينا 100 زوج من البيانات).


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


 function backwardPropagation(predictions, xTrain, yTrain) { const m = xTrain.length; //           'w'  'b'. //      0. let dW = 0; let dB = 0; for (let i = 0; i < m; i += 1) { dW += (yTrain[i] - predictions[i]) * xTrain[i]; dB += yTrain[i] - predictions[i]; } //    . dW /= m; dB /= m; return [dW, dB]; } 

التدريب النموذجي


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


لذلك ، يجب أن نكرر انتشار الأمام والخلف للإشارة عدة مرات. هذا هو trainModel() وظيفة trainModel() . إنها مثل "المعلم" لنموذج الخلايا العصبية النانوية لدينا:


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

بضع كلمات حول المعلمة alpha . هذا مجرد معامل (مضاعف) لقيم المتغيرات dW و dB ، التي نحسبها أثناء الانتشار الخلفي للإشارة. لذلك ، أظهر لنا المشتق الاتجاه إلى الحد الأدنى من وظيفة الخطأ (تخبرنا علامات قيم dW و dB بهذا). كما أوضح لنا المشتق مدى السرعة التي نحتاجها للتقدم نحو الحد الأدنى للوظيفة (القيم المطلقة لـ dW و dB تخبرنا بذلك). نحتاج الآن إلى مضاعفة حجم الخطوة بخطوة alpha لضبط سرعة نهجنا إلى الحد الأدنى (إجمالي حجم الخطوة). في بعض الأحيان ، إذا استخدمنا قيمًا كبيرة لـ alpha ، فيمكننا اتباع خطوات كبيرة بحيث يمكننا ببساطة تجاوز الحد الأدنى من الوظيفة ، وبالتالي تخطيها.


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


سنقوم بتحديث معايير نموذجنا w و b النحو التالي:


ث


ب


وهكذا يبدو التدريب نفسه:


 function trainModel({model, epochs, alpha, xTrain, yTrain}) { //     -.  . const costHistory = []; //    ()  for (let epoch = 0; epoch < epochs; epoch += 1) { //   . const [predictions, cost] = forwardPropagation(model, xTrain, yTrain); costHistory.push(cost); //   . const [dW, dB] = backwardPropagation(predictions, xTrain, yTrain); //    -,    . nanoNeuron.w += alpha * dW; nanoNeuron.b += alpha * dB; } return costHistory; } 

وضع كل الميزات معًا


الوقت لاستخدام جميع الوظائف التي تم إنشاؤها مسبقا معا.


إنشاء مثيل لنموذج النانو العصبية. في الوقت الحالي ، لا يعرف العصب النانوي شيئًا حول ماهية المعلمات w و b . لذلك دعونا نضع w و b بشكل عشوائي.


 const w = Math.random(); // ie -> 0.9492 const b = Math.random(); // ie -> 0.4570 const nanoNeuron = new NanoNeuron(w, b); 

نقوم بإنشاء مجموعات بيانات التدريب والاختبار.


 const [xTrain, yTrain, xTest, yTest] = generateDataSets(); 

الآن دعونا نحاول تدريب نموذجنا باستخدام خطوات صغيرة ( 0.0005 ) لـ 70000 عصر. يمكنك تجربة هذه المعلمات ، فهي مصممة تجريبيا.


 const epochs = 70000; const alpha = 0.0005; const trainingCostHistory = trainModel({model: nanoNeuron, epochs, alpha, xTrain, yTrain}); 

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


 console.log('  :', trainingCostHistory[0]); // ie -> 4694.3335043 console.log('  :', trainingCostHistory[epochs - 1]); // ie -> 0.0000024 

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


عملية التدريب


دعونا نلقي نظرة على ما المعلمات لدينا "الخلايا العصبية النانوية" المستفادة. نتوقع أن تشبه celsiusToFahrenheit() w و b المعلمات التي تحمل الاسم نفسه من celsiusToFahrenheit() ( w = 1.8 و b = 32 ) ، لأنها كانت celsiusToFahrenheit() النانوية التي حاولت محاكاةها.


 console.log(' -:', {w: nanoNeuron.w, b: nanoNeuron.b}); // ie -> {w: 1.8, b: 31.99} 

كما ترى ، فإن الخلايا العصبية النانوية قريبة جدًا من وظيفة celsiusToFahrenheit() .


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


 [testPredictions, testCost] = forwardPropagation(nanoNeuron, xTest, yTest); console.log('   :', testCost); // ie -> 0.0000023 

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


 const tempInCelsius = 70; const customPrediction = nanoNeuron.predict(tempInCelsius); console.log(`- "",  ${tempInCelsius}°C   :`, customPrediction); // -> 158.0002 console.log('  :', celsiusToFahrenheit(tempInCelsius)); // -> 158 

قريب جدا! مثل الناس ، لدينا الخلايا العصبية النانوية جيدة ، ولكن ليست مثالية :)


الترميز الناجح!


كيفية تشغيل واختبار الخلايا العصبية النانوية


يمكنك استنساخ المستودع وتشغيل الخلايا العصبية النانو محليًا:


 git clone https://github.com/trekhleb/nano-neuron.git cd nano-neuron 

 node ./NanoNeuron.js 

المفاهيم الضائعة


تم حذف أو تبسيط مفاهيم التعلم الآلي التالية لسهولة التفسير.


فصل التدريب ومجموعات بيانات الاختبار


عادة ما يكون لديك مجموعة واحدة كبيرة من البيانات. اعتمادًا على عدد النسخ في هذه المجموعة ، يمكن إجراء تقسيمها إلى مجموعات تدريب واختبار بنسبة 70/30. يجب خلط البيانات في المجموعة بشكل عشوائي قبل الانقسام. إذا كانت كمية البيانات كبيرة (على سبيل المثال ، ملايين) ، فيمكن إجراء التقسيم إلى مجموعات اختبار وتدريب بنسب قريبة من 90/10 أو 95/5.


السلطة على الانترنت


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


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


تطبيع المدخلات


قبل التدريب ، من المعتاد تطبيع بيانات الإدخال .


تنفيذ المتجهات


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


خطأ الحد الأدنى وظيفة


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


وظيفة التنشيط


عادة ما تمر قيمة الخرج للخلايا العصبية من خلال وظيفة التنشيط. للتنشيط ، يمكن استخدام وظائف مثل Sigmoid و ReLU وغيرها.

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


All Articles