ان البرامج التقليديه تستطيع ايجاد الحلول للمشاكل التي يوجد لها خوارزميه واضحه للحل ، أو التي يكون حلها ثابت لا يتغير أبدا … وتستطيع هذه البرامج حفظ مئات أو ملايين الصور ، لكن هل يمكن لهذه البرامج التعرف على محتويات الصوره التي يحتفظ بها ..
الشبكه العصبيه أتت لحل هذه المشاكل ، حيث تعني بمحاوله تقليد طريقه تفكير الأنسان ، وبالتالى عندما تبدأ برمجه الشبكه العصبيه يجب أن تقوم بتدريبها على مجموعه كبيره من الانماط ، بحيث فيما بعد لو أتى لها نمط مشابه أو قريب منها تقوم الشبكه العصبيه بالتعرف على هذا النمط ..
بشكل عام أغلب مهمات الشكبات العصبيه في نوعين هم الClassification التصنيف أو الAssociation ويمكن أن نقول عنه التعرف recognition ، في النوع الأول الClassification يكون لدينا مدخل ونقوم بتصنيفه الى أحد الأفسام الموجوده ، مثلا صوره حيوان ويتم تصنيفها الى الثديات أو الزواحف أو أي نوع أخر ،،مثال على تلك الأنواع شبكات Perceptron وشبكات الAdline .
في الAssociator يكون المدخل input vector وتخرج الشبكه متجه أخر output vector ، وهناك نوعين من الAssociator الأول هو hetero-associative HA والأخر هو auto-associative AA ، في الأول HA يأخذ المدخل ويخرج مخرج مختلف تماما عن المدخل مثلا الشبكه أخذت ملف صوتي والمخرج يكون عباره عن نصوص text تمثل الأمور التي فهمتها الشبكه من الصوت .. النوع الأخر AA ويكون المخرج بالضبط كما هو المدخل ، ويمكن أستخدامها في حال تم تدريب الشبكه على عده صور ، ثم تم أدخال صوره مشوهه قليلا ، فسوف تتعرف الشبكه على الصوره وترجع النسخه الأصليه ،، الشبكه Hopfield هي من النوع AA .
Hopfield Neural Network
هذا النوع من الشبكات ربما يعد من أسهل الأنواع على الإطلاق ، وتركيبته architecture تكون بأن كل خليه neuron في الشبكه يتصل بالأخر لذلك يطلق عليه Fully Connected Neural Network ، أيضا هذا النوع يعتبر Auto-associative وذلك لأن الشبكه ترجع النمط فور التعرف عليه مباشره ،، في هذا المقال سوف نتناول شبكه Hopfield تتكون من أربع خلايا للتبسيط وحتى تتضح الصوره بشكل كبير ،، ,وهذا النوع Hopfieldيستخدم في الغالب للتعرف على الأنماط Pattern Recognition .
نشاهد الصوره التاليه والتي توضح لي شبكه Hopfield تتكون من أربع خلايا :
كما نلاحظ بالصوره أعلاه ، تتكون الشبكه من 4 خلايا ، كل منها يرتبط بالأخر عن طريق connection (رابط) ، هذا الرابط يحتوي على قيمه والتي تمثل الوزن weight . عدد الروابط هنا هي 12 رابط .. ويمكن تمثيل هذه الروابط باستخدام مصفوفه من بعدين Matrix كما توضح الصوره التاليه :
لاحظ أن قطر الMatrix (كل خليه مع نفسها) يساوي 0 ، لأنه لا يوجد رابط مع كل خليه بالأخرى ، بقيه القيم في الMatrix تكون على حسب الوزن الموجود بين القيمتين ، المثال التالي سوف يوضح العمليه ..
ليكن لدينا الأوزان التاليه ، وهي تتعرف recall على النمط Pattern ال0101 و1010 :
نبدأ بالنمط الأول 0101 كيف يمكن لهذه الشبكه العصبيه أن تتعرف على هذا النمط ، الخطوات بسيطه ، فكل ما في الأمر أن تقوم بحساب التنشيط لكل خليه ، ومن ثم تقوم بمعرفه هل الناتج من الخليه أكبر من داله النتشيط (وفي حالتنا هي Threshold وهي في hop يكون 0 ) ، وفي حال كان أكبر أو يساوي فإن الخليه تقوم بعمل fire (قيمه 1 ) والا العكس (قيمه 0) ..
لحساب تنشيط كل خليه ، نقوم بضرب المدخل (النمط) مع العمود الأول وجمع النتائج (العمليه تسمى dot product) وهكذا نكون عرفنا تنشيط الخليه الأولى ، ونفس الأمر بالنسبه للخليه الثانيه (العمود الثاني) نقوم بضربها مع المدخل وحساب الناتج .. وهكذا للخليه الثالثه والرابعه ،،
نبدأ بالنمط الأول كما ذكرنا 0101 ، ونبدأ بالعمود الأول (خليه 1) في الصوره ، ونقوم بعمليه الضرب وجمع الناتج ، والنتيجه سوف تكون -2 .. هناك طريقه سريعه وهي جمع الرقم الذي يقابل الواحد في المدخل ،
المدخل : 0 1 0 1
الخليه : 0 -1 1 -1
الجموع : -1 + -1 = -2 .
هكذا نكون أخرجنا التنشيط activation للخليه الأولى ، بنفس الأمر لباقي الخلايا ويخرج لدينا الناتج التالي :
N1 = -1 + -1 = -2
N2 = 0 + 1 = 1
N3 = -1 + -1 = -2
N4 = 1 + 0 = 1
المخرج النهائي هو –2, 1, –2, 1 ، الأن نقوم بحساب داله التنشيط activation function (الحد Threshold) ، وهنا أي خليه ناتجها يساوي أو أكبر من صفر سوف تكون نشطه fire بالقيمه (1) ، وغير ذلك بالقيمه (0) .
خليه 1 تنشيطها -2 وبالتالي لن تكون نشطه (0)
خليه 2 تنشيطها 1 وبالتالي تكون نشطه (1)
خليه 3 تنشيطها -2 وبالتالي لن تكون نشطه (0)
خليه 4 تنشيطها 1 وبالتالي تكون نشطه (1)
وبالتالي الناتج يكون 0101 ، وعند مقارتنه مع المدخل الأصلى 0101 سوف نجد أنهم متابطقين وبالتالى تكون الشبكه العصبيه قد تعرفت على النمط المدخل ..
ايجاد الأوزان Deriving the Weight Matrix
لعلك تتسائل كيف أمكن ايجاد تلك الأوزان في المثال السابق ، حيث كما تلاحظ أنه اذا كانت الأوزان صحيحه بالتالي التعرف على النمط أمر في غايه السهوله ،، اذا المشكله كيف يمكن أن نوجد هذه الأوزان … وهو ما يعرف بتدريب الشبكه العصبيه ..
العمليه بشكل مجمل تكون على تدريب الشبكه العصبيه على نمط معين وسوف يكون الناتج هو مصفوفه Matrix تتعرف على هذا النمط contribution matrix ، ونقوم بجمع هذه المصفوفه مع مصفوفه الأوزان ، في حال أردت أن تتعرف على نمط أخر نقوم بجعل الشبكه بتدريب الشبكه على ذلك النمط ونقوم بجمعها مع مصفوفه الأوزان ، وهكذا سوف نضيف الcontribution matrix كل مره لwieght Matrix وهكذا تكون كل مره تعلمت أنماط جديد .. الى أن تنتهي عمليه التدريب .
في المثال السابق كان المدخل 0101 ، لنرى الأن كيف يمكن توليد الأوزان (تدريب الشبكه على هذا المدخل) ، أولا نقوم بعمل Matrix خالي في البدايه ، كما توضح الصوره التاليه :
بعد ذلك نقوم بتطبيق الثلاثه خطوات التاليه :
1) حساب الBipolar للمدخل
2) ضرب الناتج من 1 مع الtransposition لنفس المصفوفه
3) تصفير الأقطار northwest diagonal (التقاء الخليه مع نفسها) تذكر أن في شبكه hobfield لا توجد خليه تتربط مع نفسها .
نبدأ بالخطوات ،،
1) أولاً الBipolar هو وسيله لتمثيل الtrue والfalse ، فبدلا أن تكون قيمه false هي 0 ، تكون false تساوي -1 ، وtrue هي نفسها 1 (سواء في binary أو bipolar) .
لكي نحول من binary الى bipolar يمكن أستخدام القانون التالي :
ولكى نقوم بالعكس ، تحويل من bipolar الى binary نستخدم :
الأن نعود للمدخل 0101 ، نقوم بتحويله :
0 = -1
1 = 1
0 = -1
1 = 1
النتيجه هي -1 1 -1 1 وهذه المصفوفه Vector سوف نستخدمها في المرحله التاليه .
2) ضرب الناتج مع الtransposition لنفس المصفوفه
الناتج السابق ضرب المعكوس له الtransposition :
ينتج لدينا :
3) نقوم الأن بتصفير الأقطار في المنتصف ، وينتج لدينا
(يمكن أن تكون العمليه عن طريق طرح الناتج من (2) مع الIdentity Matrix) .
الصوره السابقه تمثل لي contribution matrix التي تتعرف على النمط 0101 . ونقوم بجمعها مع مصفوفه الأوزان weight matrix . واذا كنا نريد الشبكه تتعرف فقط على هذا النمط بالطبع سوف تصبح الcontribution matrix هي نفسها الweight matrix . واذا أردنا أن تتعرف الشبكه على أنماط أخرى نقوم بنفس الخطوات الثلاثه ، ثم نجمع الcontribution matrix مع الweight matrix ، وهكذا نستمر،
الجزء العملي:
الكود يعتمد على مكتبة Matrix وهي تدعم عمليات المصفوفات ، يمكنك تحميل الكود مرفقة مع مثال شبكة هوبفليد وترجمتها وتشغيلها
مثال على شبكه Hopfield من 4 خلايا ، ونقوم بتدريبها على المدخل1100 ، ثم نقدم لها نفس المدخل وسنجد أنها تعرفت عليه ،، وسنقدم لها مدخل ثاني 1000 سنجد أنها لم تتعرف عليه وقدمت أقرب نمط موجود لديها وهو 1100 ..
// Hopfield Example #include "Utility.h" #include "Hopfield.h" #include <iostream> using namespace std ; int main (int argc , char* argv[]) { try { Hopfield hp(4) ; cout << "\nNow weight Matrix is : \n" << hp.getMatrix() << endl; bool pattern1[] = { true , true , false , false } ; bool pattern2[] = { true , false, false , false } ; cout << "\nTraining Nets With Pattern : " << Utility::print(pattern1) << endl; hp.train(pattern1); //hp.train(pattern2); // now input pattern1 to see if it recogonized bool* result = hp.present(pattern1); cout << "\nPrensent : " << Utility::print(pattern1) << " And Got : " << Utility::print(result) << endl; // now input pattern1 to see if it recogonized bool *r2 = hp.present(pattern2); cout << "\nPrensent : " << Utility::print(pattern2) << " And Got : " << Utility::print(r2) << endl; cout << "\nNow weight Matrix is : \n" << hp.getMatrix() << endl; } catch (const exception& exp) { cout << exp.what(); } return 0 ; }
المخرج كالتالي :
الأن أزل التعليق من السطر 26 من البرنامج ، وهو لكي ندرب الشبكه على المدخل 1000 ، وبعدها سنجد أنها تعرفت عليه .. كما يوضح الشكل التالي :
لاحظ أنك يجب أن تضيف ملفات الرأس كما هي ، وأن تقوم بعمل ترجمه لجميع الملفات وتشغل الملف الرئيسي وهو TestHop.cpp ..
جميع الملفات (Matrix , Utility , Hopfield ) سواء ملف رأس أم cpp موجودين في في الرابط.
نأخذ مثال أخر للتعرف على علامه + و – ، أنظر الشكل التالي :
الأن كل مربع من هذه المربعات يمثل لي خليه كامله ، بالتالى نحتاج الى 9 خلايا لكي نتعرف على العلامه ،، الأن في البدايه يجب أن ندرب الشبكه على العلامتين ، المربع الأبيض يكون false والأسود true
بالتالي الحرف الأول :
-1,1,-1,1,1,1,-1,1,-1
أما الثاني :
-1,-1,-1,1,1,1,-1,-1,-1
الأن نقوم بتدريب الشبكه على هذين المدخلين ، وسوف نستخدم البرنامج للتسهيل طبعا ،، لاحظ البرنامج الأن :
// Hopfield Example #include "Utility.h" #include "Hopfield.h" #include <iostream> using namespace std ; #define num 9 // neuron number int main (int argc , char* argv[]) { try { Hopfield hp(num) ; cout << "\nNow weight Matrix is : \n" << hp.getMatrix() << endl; bool pattern1[] = { false,true,false, true,true,true, false,true,false } ; bool pattern2[] = { false,false,false, true,true,true, false,false,false } ; cout << "\nTraining Nets With Pattern : " << Utility::print(pattern1,num) << endl; hp.train(pattern1,num); hp.train(pattern2,num); // now input pattern1 to see if it recogonized bool* result = hp.present(pattern1,num); cout << "\nPrensent : " << Utility::print(pattern1,num) << " And Got : " << Utility::print(result,num) << endl; // now input pattern1 to see if it recogonized bool *r2 = hp.present(pattern2,num); cout << "\nPrensent : " << Utility::print(pattern2,num) << " And Got : " << Utility::print(r2,num) << endl; cout << "\nNow weight Matrix is : \n" << hp.getMatrix() << endl; } catch (const exception& exp) { cout << exp.what(); } return 0 ; }
وقم مباشره بادخاله للشبكه بدون تدريب ،ماذا تتوقع النتيجه ؟ بالطبع على الحرف الثاني – لأنه أقرب اليه ،، قم بتجربته في البرنامج السابق ولاحظ النتيجه .
شكرا وجزاك الله كل خير
ممكن الرابط اذا سمحت ولك جزيل الشكر
رابط ماذا ؟
وشكراً لك.
تفضل الرابط حمل الملفين وانظر للكود فيهم
https://www.dropbox.com/sh/d89m0473lkn5ewh/AACkVeDVqGxH9ZvDsAZrZNGla?dl=0
شكرا جزيلا على هذا الشرح المفصل.. ولكن اين روابط تحميل الكود الخاص ب
“Utility.h”
“Hopfield.h”
تحياتي
تفضل الرابط حمل الملفين وانظر للكود فيهم
https://www.dropbox.com/sh/d89m0473lkn5ewh/AACkVeDVqGxH9ZvDsAZrZNGla?dl=0
السلام عليكم ..
شرح جميل ومختصر ولكن عدم وجود رابط الكود
مع الشكر
تفضل الرابط حمل الملفين وانظر للكود فيهم
https://www.dropbox.com/sh/d89m0473lkn5ewh/AACkVeDVqGxH9ZvDsAZrZNGla?dl=0
لو تقدر ترشح لنا كتاب أو مرجع نتعلم منه ونستقبل منه باقي الشرح
جزاك الله خيرا
شكرا جزيلا لهذا الشرح… هل يوجد كتاب استطيع اعتماده في دراسة الشبكات
شكرا