البحث في الموقع
المحتوى عن 'tensorflow'.
-
تُستخدم الشبكات العصبية كوسيلةٍ للتعلم العميق، فهي واحدةٌ من المجالات الفرعية العديدة لطُرق تطبيق الذكاء الصناعي. وقد اقْتُرحت لأول مرةٍ منذ حوالي 70 عامًا في محاولةٍ لمحاكاة طريقة عمل دماغ الإنسان، إلا أنها أبسط بكثيرٍ من الخلايا العصبية الحقيقة، إذ أن كلّ خليةٍ اصطناعيةٍ مرتبطةٌ بعِدة طبقاتٍ، ولكلّ واحدةٍ منها وزنٌ مُعينٌ يُعبر عن أهمية هذه الطبقة، وذلك لتحديد كيفية استجابة الخلية العصبية عند نشْر البيانات عبرها، وبينما كانت الشبكات العصبية سابقًا محدودةً في عدد الخلايا العصبية التي تستطيع محاكاتها في ذلك الوقت -وهو الأمر الذي انعكس بدوره على تعقيد عملية التعلم التي يمكننا تحقيقها-، إلا أنه في السنوات الأخيرة، ونظرًا للتقدم الكبير في تطوّر الأجهزة، استطعنا أخيرًا بناء شبكاتٍ عصبيةٍ عميقةٍ جدًا، وتدريبها على مجموعات بياناتٍ هائلةٍ وضخمة كذلك، مما أدّى إلى تحقيق قفزاتٍ نوعية في تطور الذكاء الاصطناعي وتحديدًا تعلم الآلة. سمحت تلك القفزات النوعية للآلات بمُقاربة قدرات البشر، بل وتجاوزتها في أداء بعض المهام المحدودة. ومن بين هذه المهام، قدرتها على التعرف على الكائنات، فعلى الرغم من أن الآلات كانت غير قادرة تاريخيًا على منافسة قوة الرؤية البشرية، إلا أنّ التطورات الحديثة في التعلم العميق جعلت من الممكن بناء شبكاتٍ عصبيةٍ باستطاعتها التعرف على الكائنات والوجوه والنصوص، بل وحتى العواطف! سنُطبق في هذا المقال قِسمًا فرعيًا صغيرًا من طُرق التعرف على الكائنات، وتحديدًا التعرف على الأرقام المكتوبة بخط اليد، وذلك باستخدام مكتبة TensorFlow، وهي مكتبة بايثون مفتوحة المصدر التي طُوّرت في مختبرات غوغل Google Brain لأبحاث التعلم العميق، كما أنها من أشهر المكتبات الحالية في التعلم العميق، وسنأخذ صورًا مكتوبٌ عليها الأرقام بخط اليد من الرقم 0 وحتى الرقم 9، وسنبني شبكةً عصبيةً وندربها لكي تتعرف على التصنيف المناسب لكل رقمٍ معروضٍ في الصورة وتتنبأ به، ثم تَنسْبه لصنفٍ من أصناف الأرقام الموجودة. سنفترض إلمامك بمصطلحات ومفاهيم تعلم الآلة، مثل التدريب والاختبار والميزات والأصناف والتحسين والتقييم. لهذا لن تحتاج لخبرةٍ سابقةٍ في مجال التعلم العميق التطبيقي أو بمكتبة TensorFlow، ولمتابعة وفَهم هذا المقال جيدًا ننصحك أولًا بالاطلاع على: المفاهيم الأساسية لتعلم الآلة. المتطلبات الرئيسية لإكمال هذا المقال ستحتاج بيئةً برمجيةً للغة بايثون الإصدار 3.8 سواءً كان محليًا أو بعيدًا. ويجب أن تتضمن هذه البيئة البرمجية مدير الحِزم pip لتثبيت الحِزم، ومُنشئ البيئات الافتراضية venv لإنشاء بيئاتٍ افتراضيةٍ. 1. إعداد المشروع ستحتاج أولًا لتثبيت بعض التبعيات، وذلك لإنشاء مساحة عملٍ للاحتفاظ بملفاتنا قبل أن نتمكن من تطوير برنامج التعرف على الصور، وسنستخدم بيئة بايثون 3.8 الافتراضية لإدارة التبعيات الخاصة بمشروعنا. سَنُنشئ مجلدًا جديدًا خاصًا بمشروعنا وسندخل إليه هكذا: mkdir tensorflow-demo cd tensorflow-demo سننفذّ الأوامر التالية لإنشاء البيئة الافتراضية: python -m venv tensorflow-demo ومن ثم الامر التالي في Linux لتنشيط البيئة الافتراضية: source tensorflow-demo/bin/activate أما في Windows، فيكون أمر التنشيط: "tensorflow-demo/Scripts/activate.bat" بعد ذلك، سنُثبتّ المكتبات التي سنستخدمها. سنستخدم إصداراتٍ محددةٍ من هذه المكتبات، من خلال إنشاء ملف requirements.txt في مجلد المشروع، وسيُحدِّد هذا الملف المتطلبات والإصدارات التي سنحتاج إليها. نفتح الملف requirements.txt في محرر النصوص، ونُضيف الأسطر التالية، وذلك لتحديد المكتبات التي نريدها وإصداراتها: keras==2.6.0 numpy==1.19.5 Pillow==8.4.0 scikit-learn==1.0 scipy==1.7.1 sklearn==0.0 tensorflow==2.6.0 سنحفظ التغييرات التي طرأت على الملف وسنخرج من محرر النصوص، ثم سنُثَبت هذه المكتبات بالأمر التالي: (tensorflow-demo) $ pip install -r requirements.txt بعد تثبيتنا لهذه التبعيات، سنُصبح جاهزين لبدء العمل على مشروعنا. 2. استيراد مجموعة بيانات MNIST تُسمى مجموعة البيانات التي سنستخدمها، بمجموعة بيانات MNIST، وهي مجموعةٌ كلاسيكيةٌ في مجتمع مُطوري تعلم الآلة، وتتكون من صورٍ لأرقامٍ مكتوبةٍ بخط اليد، بحجم 28×28 بكسل. ونستعرض فيما يلي بعض الأمثلة للأرقام المُتضمنة فيها: لاحظ أنه ينبغي أن نستخدم ملفًا واحدًا لجميع أعمالنا في هذا المقال، ولنُنشئ برنامج بايثون يتعامل مع مجموعة البيانات هذه، سننشئ ملفًا جديدًا باسم main.py، وسنفتح هذا الملف بأي محرر شيفرات لدينا -مثل VS code- وسنُضيف هذه الأسطر البرمجية لاستيراد المكتبات اللازمة: import tensorflow as tf import numpy as np from sklearn.preprocessing import OneHotEncoder #مكتبة معالجة الصور from PIL import Image #التوافقية مع إصدار سابق tf.compat.v1.disable_v2_behavior() وسنضيف أيضًا هذه الأسطر من الشيفرات البرمجية لملفك لاستيراد مجموعة بيانات MNIST وذلك باختيار صور التدريب المتاحة من Tensorflow ومن ثم نُنزلها ونقسمها إلى جزئين: الأول للتدريب والثاني للاختبار: #اختيار بيانات التدريب mnist = tf.keras.datasets.mnist #تنزيل بيانات التدريب والاختبار (x_train, y_train), (x_test, y_test) = mnist.load_data() #طباعة عدد بيانات التدريب والاختبار print (len(x_train)) print (len(x_test)) #تحجيم البيانات بين 0 و 1 x_train, x_test = x_train / 255.0, x_test / 255.0 #الترميز الأحادي النشط y_train = [[i] for i in y_train] y_test = [[i] for i in y_test] enc = OneHotEncoder(sparse=True) enc.fit(y_train) y_train = enc.transform(y_train) y_test = enc.transform(y_test) تقوم الدالة 'mnist.load_data' بتنزيل البيانات وتقسيمها إلى مجموعتين واحدة للتدريب (60000 صورة) والمجموعة الثانية للاختبار (10000 صورة). وعند قراءة البيانات سنستخدم الترميز الأحادي النشط One-Hot Encoding لتمثيل التصنيفات للصور. حيث يَستَخدم الترميز الأحادي النشط One-Hot Encoding متجهًا vector مُكونٌ من قيمٍ ثنائيةٍ لتمثيل القيم الرقمية أو الصنفية. ونظرًا لأن أصنافنا مخصصةٌ لتمثيل الأرقام من 0 إلى 9، فإن المتجه سيحتوي على 10 قيمٍ، واحدةٌ لكلّ رقمٍ ممكنٍ. وتُسنَد إحدى هذه القيم بوضع القيمة 1، وذلك لتمثيل الرقم في هذا المؤشر للمتجه، كما ستُسنَد القيم الباقية بالقيمة 0. فمثلًا، سيُمثلُ الرقم 3 من خلال المتجه هكذا: [0 ،0 ،0 ،1 ،0 ،0 ،0 ،0 ،0 ،0]. وسنلاحظ وجود القيمة 1 في الفهرس 3، لذلك فإن المتجه سيُمثِلُ الرقم 3. ولتمثيل الصور الفعلية والتي تكون بحجم 28x28 بكسل، يتوجب علينا تسويتها في المتجه 1D بحجم 784 بكسل، وهو ناتج ضرب 28×28. وسنخزن هذه البكسلات والتي ستُشكل الصورة لاحقًا، وذلك في قيمٍ تتراوح بين 0 و255، حيث ستحدّد هذه القيم تدرج اللون الرمادي للبكسل، وستُعرَض صورنا باللونين الأبيض والأسود فقط. لذلك سيُمثلُ البكسل الأسود بالقيمة 255، والبكسل الأبيض بالقيمة 0، وذلك مع التدرجات المختلفة للون الرمادي بينهم. والآن بعد استيرادنا للبيانات، حان الوقت للتفكير في كيفية بناء الشبكة العصبية. 3. تحديد بنية الشبكة العصبية يُشير مصطلح بنية الشبكة العصبية لعناصرٍ متنوعةٍ، مثل عدد الطبقات في الشبكة وعدد الوِحدات في كلّ طبقةٍ، كما يشير إلى كيفية توصيل هذه الوِحدات بين الطبقات المختلفة. ونظرًا لأن الشبكات العصبية مستوحاةٌ من كيفية عمل الدماغ البشري، فسنستخدم مصطلح الوِحدة ليُمثّل ما يُمكن تسميته بيولوجيًا بالخلايا العصبية. تأخذ الوِحدات بعض القيم من الوِحدات السابقة مثل مُدخلاتٍ لها، حيث تتشابه مع الخلايا العصبية التي تُمرر إشاراتها حول الدماغ، ثمّ تُجري عمليةً حسابيةً، وتُمرر القيمة الجديدة مثل مُخرجاتٍ إلى وِحداتٍ أخرى، وهكذا. تُوضع هذه الوِحدات على شكل طبقاتٍ متراكبةٍ فوق بعضها البعض مشكّلةً الشبكة العصبية، بحيث يمكن للشبكة أن تتألف كحدٍ أدنى من طبقتين، طبقةٌ لإدخال القيم، وطبقةٌ أخرى لإخراج القيم. يُستخدم مصطلح الطبقة المخفية لجميع الطبقات الموجودة بين طبقات المُدخلات وطبقات المُخرجات الخارجية، أي أن تلك الطبقات تكون مخفيةً عن العالم الحقيقي. تحقق البُنى المختلفة للشبكة نتائجًا مختلفةً عن بعضها البعض، ويمكن اتخاذ الأداء مثل معيارٍ للحكم على هذه البُنى المختلفة، كما يمكن اتخاذ عناصر أخرى معيارًا للحكم، مثل الوسطاء والبيانات ومدة التدريب. سنضيف هذه الأسطر البرمجية التالية لملفك، وذلك لتخزين عدد الوِحدات المُخصصة لكلّ طبقةٍ ووضعها في متغيّراتٍ عامةٍ. وهذه الطريقة ستسمح لنا بتغيير بِنية الشبكة بمكانٍ واحدٍ، وفي نهاية هذا المقال يمكنك اختبار مدى تأثير الأعداد المختلفة من الطبقات والوِحدات على نتائج نموذجنا: n_input = 784 # input layer (28x28 pixels) n_hidden1 = 512 # 1st hidden layer n_hidden2 = 256 # 2nd hidden layer n_hidden3 = 128 # 3rd hidden layer n_output = 10 # output layer (0-9 digits) يُوضح الرسم البياني التالي تصورًا للبِنية التي صمّمناها، مع توصيل كلّ طبقةٍ بالطبقات المحيطة بها توصيلًا كاملًا: ويرتبط مصطلح الشبكة العصبية العميقة Deep Neural Network بعدد الطبقات المخفية، وعادةً ما تُشير كلمة السطحية في مصطلح الشبكة العصبية السطحية إلى وجود طبقةٍ مخفيةٍ واحدةٍ، بينما تُشير كلمة العميقة إلى وجود طبقاتٍ مخفيةٍ متعددةٍ. ونظريًا إذا أُعطِيت الشبكة العصبية السطحية ما يكفي من بياناتٍ للتدريب، فيجب أن تَقدِر على تمثيل أي وظيفةٍ يمكن للشبكة العصبية العميقة أن تؤدّيها. ولكن من ناحية الفعالية الحسابية، فغالبًا ما يكون نتائج استخدام شبكةٍ عصبيةٍ عميقةٍ ذات حجمٍ صغيرٍ أفضل من النتائج التي تُعطيها الشبكة العصبية السطحية ذات العدد الكبير من الوِحدات المخفية، وذلك عند تأديتهم لنفس المَهمة. كما أن الشبكات العصبية السطحية غالبًا ما تواجه مشكلة فَرط التخصيص Overfitting، إذ يكون هدف الشبكة الأساسي هو حفظ بيانات التدريب التي شاهدتها، ولكنها لن تستطيع تعميم المعرفة التي اكتسبتها على البيانات الجديدة، وهذا هو السبب في كون استخدام الشبكات العصبية العميقة أكثر شيوعًا، إذ أنها تسمح للطبقات المتعددة الموجودة بين البيانات المُدخلة الأولية والبيانات المُصنفة الناتجة، بتعلم الميزات على مستوياتٍ متنوعةٍ، مما يُعزز قدرة الشبكة على التعلم وتعميم الفكرة. ومن العناصر الأخرى للشبكة العصبية التي يجب تعريفها هنا هي الوسطاء الفائقة Hyperparameters، فعلى عكس الوسطاء العادية التي تُحدث قيمها أثناء عملية التدريب، سنُسند قيم الوسطاء الفائقة في البداية وسنثبتها طوال العملية. أسنِد المتغيّرات بالقيم التالية في ملفك: learning_rate = 1e-4 n_iterations = 1000 batch_size = 128 dropout = 0.5 يمثل معدل التعلم Learning Rate مدى تعديل الوسطاء في كلّ خطوةٍ من عملية التعلّم، إذ تُعَد هذه التعديلات مكونًا رئيسيًا للتدريب، فبعد كلّ عملية مرور ٍعبر الشبكة، سنضبط أوزان الطبقات قليلًا لأهمية ذلك في محاولةٍ لتقليل الخسارة، حيث يمكن لمعدل التعلم المرتفع أن يتحقق بسرعة، ولكن يمكن كذلك أن تتجاوز القيم المثلى عند تحديثها في كلّ مرة. يشير مصطلح عدد التكرارات Number Of Iterations إلى عدد مرات مرورنا على خطوة التدريب، ويشير حجم الدفعة Batch Size لعدد أمثلة التدريب التي نستخدمها في كل خطوة، كما ويمثل المتغير dropout الموضع الذي نحذف عنده بعضًا من الوِحدات عشوائيًا. وسنستخدم المتغير dropout في الطبقة النهائية المخفية لإعطاء كلّ وِحدة من الوحدات احتمالًا بنسبة 50٪ للتخلص منها في كلّ خطوة تدريبٍ، وهذا سيساعد على منع ظهور مشكلة فرط التخصيص Overfitting. حددنا الآن بِنية شبكتنا العصبية والوسطاء الفائقة التي ستُؤثر على عملية التعلّم، والخطوة التالية هي بناء الشبكة مثل مخططٍ بيانيٍ من خلال مكتبة TensorFlow. 4. بناء مخطط بياني من خلال مكتبة TensorFlow لبناء شبكتنا، لابد لنا من إعداد الشبكة مثل مخططٍ بيانيٍ حسابي من خلال مكتبة TensorFlow لتنفيذه. والمفهوم الأساسي لمكتبة TensorFlow هو tensor، وهو بنية بياناتٍ مشابهةٍ لبِنية المصفوفة Array، أو القائمة List. وهذا المتغير سيهيَأ ويُعالَج عند مروره عبر المخطط البياني للشبكة عبر عملية التعلّم. وسنبدأ بتحديد ثلاثة متغيراتٍ tensors من نوع placeholders، وهو نوع tensor تُسندُ قيمته لاحقًا. والآن سنضيف الشيفرة البرمجية التالية إلى الملف الذي نعمل عليه: X = tf.compat.v1.placeholder("float", [None, n_input]) Y = tf.compat.v1.placeholder("float", [None, n_output]) keep_prob = tf.compat.v1.placeholder(tf.float32) إنّ الوسيط الوحيد الذي يتوجب علينا تحديده عند التعريف هو حجم البيانات التي سنُسندها لاحقًا، وبالنسبة للمتغير X سنستخدم شكل [None، 784]، إذ ستمثل القيمة None كميةً غير محددةٍ، وسنُسند كميةً غير محددةٍ من الصور ذات حجم 784 بكسل. بحيث يصبح شكل المتغير Y هو [None، 10]، وستمثل None عددًا غير محددٍ من التصنيفات الناتجة، مع وجود 10 أصنافٍ محتملةٍ. وسنستخدم في المتغير keep_prob tensor من نوع placeholders للتحكم في معدل dropout، وسنجعله من نوع placeholders وذلك لجعله متغيرًا من نوعٍ قابلٍ للتعديل، بدلًا من كونه متغيرًا من نوعٍ غير قابلٍ للتعديل immutable variable، وذلك لأننا نريد استخدام نفس tensor التدريب عند إسناد dropout بالقيمة 0.5، ونفس tensor الاختبار عند إسناد dropout بالقيمة 1.0. والوسطاء التي ستُحدث قيمها الشبكة العصبية في عملية التدريب هي القيم الخاصة بوزن كلّ طبقةٍ، والتي تُعبر عن الأهمية وقيم التحيز bias values، لذلك سنحتاج لإسنادهم بقيمٍ إبتدائيةٍ بدلًا من قيمٍ فارغةٍ. وهذه القيم هي الأساس الذي ستبدأ الشبكة رحلة التعلم انطلاقًا منها، إذ ستُستخدم في تفعيل دوال الشبكة العصبية، والتي تُمثِلُ قوة الاتصالات بين الوِحدات. ونظرًا لاستمرار تحسين القيم أثناء عملية التدريب، يمكننا ضبطها حاليًا بالقيمة 0. لاحظ أن القيمة الأولية في الواقع لها تأثيرٌ كبيرٌ على الدقة النهائية للنموذج. وسنستخدم التوزيع الاحتمالي الطبيعي المنقطع Truncated normal distribution لتوليد قيمٍ عشوائيةٍ لأوزان الطبقات، بحيث يكونون قريبين من الصفر حتى يتمكنوا من التعديل إما باتجاهٍ إيجابيٍ أو سلبيٍ، كما يكونون مختلفين قليلًا، وذلك ليُنتِجوا أخطاءً مختلفةً، وبهذه الطريقة سنضمن بأن يتعلم النموذج شيئًا مفيدًا. والآن سنضيف هذه الأسطر البرمجية التالية لملفنا الذي نعمل عليه: weights = { 'w1': tf.Variable(tf.random.truncated_normal([n_input, n_hidden1], stddev=0.1)), 'w2': tf.Variable(tf.random.truncated_normal([n_hidden1, n_hidden2], stddev=0.1)), 'w3': tf.Variable(tf.random.truncated_normal([n_hidden2, n_hidden3], stddev=0.1)), 'out': tf.Variable(tf.random.truncated_normal([n_hidden3, n_output], stddev=0.1)), } بالنسبة للتحيز Bais، سنستخدم قيمةً ثابتةً صغيرةً لضمان تنشيط جميع tensors المراحل الأولية، وبالتالي المساهمة في الانتشار. وستُخزن الأوزان وجميع tensors التحيزات في objects قواميس Dictionary لسهولة الوصول إليها. أضف هذه الشيفرة البرمجية للملف الذي نعمل عليه وذلك لتعريف التحيز وقِيَمه: biases = { 'b1': tf.Variable(tf.constant(0.1, shape=[n_hidden1])), 'b2': tf.Variable(tf.constant(0.1, shape=[n_hidden2])), 'b3': tf.Variable(tf.constant(0.1, shape=[n_hidden3])), 'out': tf.Variable(tf.constant(0.1, shape=[n_output])) } والآن جهّز طبقات الشبكة العصبية من خلال تعريف العمليات التي ستتعامل مع tensors المرحلة الحالية. وأضف هذه الشيفرة البرمجية للملف الذي نعمل عليه: layer_1 = tf.add(tf.matmul(X, weights['w1']), biases['b1']) layer_2 = tf.add(tf.matmul(layer_1, weights['w2']), biases['b2']) layer_3 = tf.add(tf.matmul(layer_2, weights['w3']), biases['b3']) layer_drop = tf.nn.dropout(layer_3, keep_prob) output_layer = tf.matmul(layer_3, weights['out']) + biases['out'] ستنفذ كلّ طبقةٍ مخفيةٍ عملية ضربٍ للمصفوفة على نتائج الطبقة التي سبقتها وعلى أوزان الطبقة الحالية، وسيُضاف التحيز لهذه القيم. في الطبقة المخفية الأخيرة، سنُطبِّق عملية التسرب dropout بالقيمة 0.5 للمتغير Keep_prob الخاص بنا. الخطوة الأخيرة في بناء المخطط البياني، هي تحديد دالة الخسارة التي نريد تحسينها. والاختيار الشائع لدالة الخسارة في المكتبة البرمجية TensorFlow هو الانتروبي المشترك Joint Antropy، والمعروف كذلك باسم فقدان السجل log-loss، وهو الذي يُحدد الفرق بين التوزيعين الاحتماليين لكلً من التنبؤات والتصنيف. ويمكن أن تكون قيمة الانتروبي المشترك 0، وذلك في أفضل الأحوال عند التصنيف المثالي، وذلك مع انعدام الخسارة تمامًا. سنحتاج كذلك إلى اختيار خوارزمية التحسين المناسبة، والتي سنستخدمها لتقليل الناتج من دالة الخسارة. وتُسمى هذه العملية بعملية تحسين الانحدار التدريجي، وهي طريقةٌ شائعةٌ للعثور على الحد الأدنى للدالة، من خلال اتخاذ خطواتٍ تكراريةٍ على طول التدرج في الاتجاه السلبي التنازلي. وهناك العديد من الخيارات لخوارزميات تحسين الانحدار التدريجي المُطبقة في المكتبة البرمجية TensorFlow، إلا أننا سنستخدم في هذا المقال خوارزمية المُحسِّن أدم Adam optimizer، الذي يعمتد على عملية تحسين الانحدار التدريجي باستخدام الزخم أو كمية الحركة Momentum، وذلك بتسريع عملية التنعيم من خلال حساب متوسط ٍمُرجَّحٍ بكثرة للتدرجات، واستخدام ذلك في التعديلات مما يؤدي لتقاربٍ أسرع. وسنضيف هذه الشيفرة للملف الذي نعمل عليه: cross_entropy = tf.reduce_mean( tf.nn.softmax_cross_entropy_with_logits( labels=Y, logits=output_layer )) train_step = tf.compat.v1.train.AdamOptimizer(1e-4).minimize(cross_entropy) عرّفنا حتى الآن الشبكة وبنيناها باستخدام المكتبة البرمجية TensorFlow، والخطوة التالية هي إرسال البيانات عبر المخطط البياني لتدريبها، ومن ثَمّ اختبارها للتحقق فيما إن كانت تعلمت شيئًا بالفعل أم لا. 5. التدريب والاختبار تتضمن عملية التدريب تغذية المخطط البياني للشبكة بمجموعة بيانات التدريب، وتحسين نتيجة دالة الخسارة، إذ أن في كلّ مرةٍ تمر فيها الشبكة عبر مجموعةٍ إضافيةٍ من صور التدريب، فستُحدثُ الوسطاء لتقليل الخسارة، وذلك بهدف تحسين دقة التنبؤ للأرقامٍ؛ أما عملية الاختبار، فتتضمن تشغيل مجموعة بيانات الاختبار الخاصة بنا عبر المخطط البياني المدرّب، كما ستتتبع عدد الصور التي صح التنبؤ بها، حتى نحسب الدقة جيدًا. قبل البدء في عملية التدريب، سوف نحدد دالة تقييم الدقة لكي نتمكن من طباعتها على مجموعاتٍ صغيرةٍ من البيانات أثناء التدريب. هذه البيانات المطبوعة ستسمح لنا بالتحقق من انخفاض الخسارة وزيادة الدقة، وذلك بدءًا من المرور الأول عبر المخطط البياني، وحتى المرور الأخير؛ كما ستسمح لنا بتتبّع ما إذا نفذنا عمليات مرور ٍكافيةً عبر المخطط البياني للوصول لنتيجةٍ مناسبةٍ ومثاليةٍ أم لا: correct_pred = tf.equal(tf.argmax(output_layer, 1), tf.argmax(Y, 1)) accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32)) سنستخدم الدالة arg_max في المتغيّر right_pred للموازنة بين الصور التي صَحَ توقُّعها، وذلك بالنظر لقيمة التنبؤات output_layer والتصنيفات Y، وسنستخدم الدالة equal لإعادة هذه النتائج مثل قائمةٍ مؤلفةٍ من قيمٍ بوليانيةٍ. ويمكننا بعد ذلك تحويل هذه القائمة للنوع float، وذلك لحساب المتوسط للحصول على درجة الدقة الإجمالية. الآن نحن جاهزون لتهيئة الجلسة لتشغيل المخطط البياني، إذ سنرسل للشبكة أمثلة التدريب الخاصة بنا، وبمجرد انتهاء التدريب، سنرسل أمثلة اختبارٍ جديدةٍ عبر المخطط البياني نفسه لتحديد دقة النموذج. أضف هذه الشيفرة للملف الذي نعمل عليه: init = tf.compat.v1.global_variables_initializer() sess = tf.compat.v1.Session() sess.run(init) إن جوهر عملية التدريب في التعلم العميق هو تحسين ناتج دالة الخسارة. ونحن هنا سنهدف إلى تقليل الفرق بين التصنيفات المُتوقعة للصور والتصنيفات الحقيقية لها. وستتضمن هذه العملية أربع خطواتٍ تتكرر لعددٍ محددٍ من مرات المرور عبر المخطط البياني، وهي: دفع القيم إلى الأمام عبر الشبكة. حساب الخسارة. دفع القيم للخلف عبر الشبكة. تحديث الوسطاء. ففي كلّ خطوة تدريب، سنعدِّل الوسطاء قليلًا في محاولةٍ لتقليل نتائج دالة الخسارة. وفي الخطوة التالية مع تَقدُّم عملية التعلّم، يجب أن نشاهد انخفاضًا في الخسارة، حيث سنوقِف التدريب في النهاية، وسنستخدم الشبكة مثل نموذجٍ لاختبار بياناتنا الجديدة. سنضيف هذه الشيفرة البرمجية للملف الذي نعمل عليه: # التدريب على دفعات صغيرة for i in range(n_iterations): startbatch = (i*batch_size) % len(x_train) endbatch = ((i+1)*batch_size) % len(x_train) batch_x = np.array(x_train[startbatch:endbatch]) batch_x = batch_x.reshape(batch_size, -1) batch_y = y_train[startbatch:endbatch].toarray() if batch_x.shape != (128, 784): continue sess.run(train_step, feed_dict={ X: batch_x, Y: (batch_y), keep_prob: dropout }) # طباعة الخسارة والدقة لكل دفعة صغيرة if i % 100 == 0: minibatch_loss, minibatch_accuracy = sess.run( [cross_entropy, accuracy], feed_dict={X: batch_x, Y: batch_y, keep_prob: 1.0} ) print( "Iteration", str(i), "\t| Loss =", str(minibatch_loss), "\t| Accuracy =", str(minibatch_accuracy) ) بعد 100 عملية مرورٍ لكلّ خطوة تدريبٍ والتي أرسلنا فيها مجموعةً صغيرةً من الصور عبر الشبكة، سنطبع نتائج دالة الخسارة والدقة لتلك الدفعة. وينبغي ألّا نتوقع هنا انخفاض معدل الخسارة وزيادة الدقة، لأن القيم لكل دفعةٍ صغيرةٍ. إذ أن النتائج ليست للنموذج بأكمله. فنحن نستخدم مجموعاتٍ صغيرةٍ من الصور بدلًا من إرسال كلّ صورةٍ بمفردها، وذلك لتسريع عملية التدريب والسماح للشبكة برؤية عددٍ من الأمثلة المختلفة قبل تحديث الوسطاء. وبمجرد اكتمال التدريب، يمكننا تشغيل الجلسة على الصور المخصصة للاختبار. وهذه المرة سنستخدم القيمة 1.0 مثل مُعدلِ تَسرّب dropout للمتغيّر Keep_prob، وذلك للتأكد من أن جميع الوِحدات نشطةٌ في عملية الاختبار. أضف هذه الشيفرة البرمجية للملف الذي نعمل عليه: إعداد صور الاختبار كمتجهات أحادية طول كل منها 28*28 # x_test = x_test.reshape(-1,784) test_accuracy = sess.run(accuracy, feed_dict={X: x_test, Y: y_test.toarray(), keep_prob: 1.0}) print("\nAccuracy on test set:", test_accuracy) والآن سنشغّل برنامجنا، لنعرف مدى دقة شبكتنا العصبية في التعرف على الأرقام المكتوبة بخط اليد. وسنحفظ التغييرات في الملف main.py الذي نعمل عليه. نَفِّذ الأمر التالي في الوِحدة الطرفية لتنفيذ الشيفرة البرمجية: (tensorflow-demo) $ python main.py سترى نتيجةً مشابهةً لما يلي، ويمكن أن تختلف قليلًا نتائج الخسارة والدقة الفردية: Iteration 0 | Loss = 3.67079 | Accuracy = 0.140625 Iteration 100 | Loss = 0.492122 | Accuracy = 0.84375 Iteration 200 | Loss = 0.421595 | Accuracy = 0.882812 Iteration 300 | Loss = 0.307726 | Accuracy = 0.921875 Iteration 400 | Loss = 0.392948 | Accuracy = 0.882812 Iteration 500 | Loss = 0.371461 | Accuracy = 0.90625 Iteration 600 | Loss = 0.378425 | Accuracy = 0.882812 Iteration 700 | Loss = 0.338605 | Accuracy = 0.914062 Iteration 800 | Loss = 0.379697 | Accuracy = 0.875 Iteration 900 | Loss = 0.444303 | Accuracy = 0.90625 Accuracy on test set: 0.9206 ولمحاولة تحسين دقة نموذجنا، أو لمعرفة المزيد حول تأثير ضبط الوسطاء الفائقة hyperparameters، يمكننا تغييرها لاختبار تأثيرها المنعكس على معدّل التعلم وعتبة التسرب Dropout Threshold، وكذا حجم الدفعة من الصور في كمية الأمثلة وعدد مرات المرور عبر المخطط، كما يمكننا كذلك تغيير عدد الوِحدات في طبقاتنا المخفية وتغيير عدد الطبقات المخفية نفسها، وذلك لنرى كيف ستؤثر بنية الشبكة العصبية على النموذج سواءً بزيادة دقته أو بتخفيضها. وللتأكد من أن الشبكة تتعرف جيدًا على الصور المكتوبة بخط اليد، فسنختبرها على صورةٍ خاصةٍ بنا، فإذا كنت تعمل على جهازك المحلي وترغب في استخدام صورٍ من جهازك، يمكنك استخدام أي محرر رسوماتٍ لإنشاء صورة بأبعاد 28x28 بكسل لأي رقمٍ تريده. مثلًا: نزل الصورة وانقلها إلى مجلد المشروع (تأكد أنها باسم test_image.png أو غير اسمها في الشيفرة) ثم أضف في نهاية الملف main.py هذا السطر البرمجي التالي لتحميل صورة الاختبار للرقم المكتوب بخط اليد: img = np.array(Image.open("test_image.png").convert('L')).ravel() إن الدالة open من مكتبة الصور Image تحمّل صورة الاختبار مثل مصفوفةٍ رباعية الأبعاد 4D، حيث تحتوي على قنوات الألوان الثلاث الرئيسية RGB بالإضافة إلى الشفافية، ولكن هذا ليس نفس التمثيل الذي استخدمناه سابقًا عند القراءة من مجموعة البيانات باستخدام المكتبة البرمجية TensorFlow، لذلك سنحتاج للقيام ببعض المهام الإضافية ليتناسب تنسيق هذه الصور مع التنسيق الذي سبق واعتمدناه في الخوارزمية. سنستخدم الدالة convert مع الوسيط L لتقليل تمثيل 4D RGBA إلى قناة لونٍ رماديةٍ واحدةٍ، وسنُخزنها على هيئة مصفوفة numpy. وسنستدعي ravel لتسوية المصفوفة. الآن بعد أن صححّنا بنية معلومات الصورة، يمكننا تشغيل الجلسة بنفس الطريقة السابقة، ولكن هذه المرة سنُرسل صورةً واحدةً فقط للاختبار. وسنضيف الشيفرة التالية للملف لاختبار الصورة وطباعة التصنيف الناتج، هكذا: prediction = sess.run(tf.argmax(output_layer, 1), feed_dict={X: [img]}) print ("Prediction for test image:", np.squeeze(prediction)) وتُستدعى الدالة np.squeeze على المتغير prediction ليُعِيد عددًا صحيحًا وفريدًا إلى المصفوفة. وسيتضح من الناتج أن الشبكة العصبية قد تعرفت على الصورة كرقم 4، هكذا: Prediction for test image: 4 يمكنك الآن تجربة عملية اختبار الشبكة باستخدام صورٍ أكثر تعقيدًا مثل الأرقام المتشابهة مع الأرقام الأخرى، أو أرقامٍ مكتوبةٍ بخطٍ سيئٍ أو حتى خاطئةٍ، وذلك لمعرفة وقياس مدى نجاحها. الخلاصة في هذا المقال، نجحنا في تدريب شبكةٍ عصبيةٍ لتصنيف مجموعة بياناتٍ MNIST بدقةٍ تصل إلى 92٪، واختبارها على صورةٍ خاصةٍ بنا، مع العلم بأنه قد تحققت نسبة أعلى في الأبحاث العلمية الحديثة وكانت حوالي 99٪ لنفس الفكرة، وذلك باستخدام بُنىً مختلفةً لشبكةٍ عصبيةٍ ذات تعقيدٍ أكبر، بحيث تتضمن طبقات تلافيفية. وتستخدم تلك الشبكات بِنيةً ثنائية الأبعاد للصورة لتمثيل المحتويات تمثيلًا أفضل من تمثيل نموذجنا السابق، إذ أن نموذجنا يُسوّي كلّ البكسلات في متجهٍ واحدٍ مكوّنٍ من 784 وِحدة. ويمكنك قراءة المزيد على الموقع الرسمي للمكتبة TensorFlow، والاطلاع على الأوراق البحثية التي تُفصِّل أدق النتائج على موقع MNIST. والآن بعد أن تعرفنا على كيفية بناء شبكةٍ عصبيةٍ وتدريبها، يمكنك تجربة هذا التطبيق واستخدامه على بياناتك الخاصة، أو اختبارها على مجموعات بياناتٍ شائعةٍ مختلفةٍ عن تلك التي استخدمناها مثل: مجموعة البيانات من غوغل أو مجموعة البيانات من CIFAR-10، وذلك للتعرف على صورٍ أكثر عموميةٍ وشموليةٍ. ترجمة -وبتصرف- للفصل How To Build a Neural Network to Recognize Handwritten Digits with TensorFlow من كتاب Python Machine Learning Projects لكاتبته Ellie Birbeck يُمكن تنزيل الكود كاملًا من Recognize-Handwritten-Numbers-MNIST-master. اقرأ أيضًا إعداد شبكة عصبية صنعية وتدريبها للتعرف على الوجوه النسخة الكاملة من كتاب مدخل إلى الذكاء الاصطناعي وتعلم الآلة النسخة العربية الكاملة من كتاب البرمجة بلغة بايثون
-
الذكاء الصنعي وخوارزميات تعلم الآلة AI/ML تتفق جميع التقنيات والخوارزميات التي تندرج تحت مسمى الذكاء الصنعي Artificial Intelligence وتعلم الآلة Machine Learning باختلاف أطيافها على البدء بتحليل البيانات الخام والبحث فيها (بطرق خوارزمية ممنهجة) لاستكشاف ما تحتويه من أنماط وعلاقات في داخلها وبين كياناتها. إن معرفة مثل تلك الأنماط والعلاقات ستساعدنا على بناء نماذج قادرة على استقراء الجوهر العام المشترك الذي يجمع ويصنف تلك الكتل من البيانات على الرغم من الاختلافات في التفاصيل الهامشية والتي قد تكون كبيرة ظاهريا ومربكة في عين من لا يتمتع بالخبرة في مجال الدراسة. لقد أثبتت مثل هذه النظم فعاليتها في حوسبة العديد من المهام التي كان يعتقد حتى وقت قريب أنها عصية على عالم البرمجيات، ساعد على ذلك الطفرة التي شهدتها عتاديات الحواسيب في العقد الأخير والتقدم الهائل في إمكانيات الحوسبة المتوازية لوحدات المعالجة الرسومية GPU، وكذلك توافر حلول الحوسبة السحابية لشريحة أكبر من فرق التطوير البرمجية التي كان يصعب عليها في الماضي الحصول على حواسيب فائقة بسهولة. إننا نشهد في الفترة الحالية انتقالا وتحولا جذريا في مفاهيم علم البرمجة مقارنة بما سبق وبما تعلمناه أو استخدمناه خلال القرن الماضي (كالبرمجة الوظيفية ومخططات سير العمل، أو حتى البرمجة الغرضية التوجه بكائناتها وطرائقها)، فالمبرمج هو من كان يضع منطق العمل وخوارزميته ليحدد أسلوب معالجة المدخلات وتوليد المخرجات، وقد امتازت فترة ثمانينيات وتسعينيات القرن الماضي بوفرة القدرة الحاسوبية مقارنة بكمية البيانات المتوافرة للمعالجة أصلا، لكن ما نشهده الآن في القرن الحادي والعشرين قد قلب هذه المعادلة رأسا على عقب، فقد أصبح لدينا فائض كبير من البيانات التي تجمع من كل حدب وصوب على مدار الساعة بدءا من جوالاتنا (التي ما عادت وسيلة للاتصال فقط) وصولا إلى الأقمار الاصطناعية في مداراتها حول الأرض. إن هذا المستوى العالي من الأتمتة في حياتنا ومجتمعاتنا نتج عنه كم هائل من البيانات التي تجاوزت بمراحل القدرة على تحليلها واستخلاص المعلومات منها بالطرق التقليدية، وهو ما أعاد فتح الأبواب مجددا لتقنيات الذكاء الصنعي التي كان لها مجد سابق منتصف القرن الماضي لكنه زال بعد أن عجزت القدرات العتادية في ذلك الحين عن مواكبة شطحات المتنورين من رواد هذا الحقل من العلوم، لكننا اليوم وبتضافر جهود الباحثين في مجالات شتى مثل علم البيانات والإحصاء والحواسيب بلا شك، أصبحنا قادرين على تنفيذ ما كانوا يتحدثون عنه ضمن طيف واسع من التطبيقات ربما بات يتجاوز أقصى طموحاتهم. الشبكات العصبية Neural Networks في جزء من لوحة رافائييل الجصيّة "مدرسة أثينا" تم رسم أفلاطون وأرسطو بشكل يعبّر عن نظريّة كل منهما في المعرفة، فأرسطو يومئ نحو الأرض فيما يشير أفلاطون بإصبعه نحو السماء، حيث كان ينظر أرسطو إلى الطبيعة بحثا عن إجابات في حين أن أفلاطون يبحث عن المثالي. وها نحن ننتقل في عالم البرمجة من فلسفة أفلاطون التي كنا نتّبعها في أدوات بناء تطبيقاتنا من لغات برمجة وما تحويه من متغيرات وتوابع وعبارات شرطية وحلقات وسواها، إلى فلسفة أرسطو حيث نبحث في كيفية عمل أدمغتنا ونحاول محاكاتها في بنيتها وطريقة عملها، وهكذا تماما ولد مجال الشبكات العصبية ضمن علوم الذكاء الصنعي. حيث ابتدأت المحاكاة على مستوى الخلية العصبية (العصبون)، فالعصبونات هي خلايا تتألف من جسم مركزي يتضمن نواة الخلية ويمتد منه استطالة وحيدة تكوّن ليف عصبي طويل يقوم مقام السلك الناقل للإشارة الخارجة من الخلية عند نهايته تفرعات كثيرة تنتهي بعقد مشبكية صغيرة، أما في الطرف الآخر من جسم الخلية العصبية فتبرز تفرّعات تخرج في كافة الاتجاهات والتي عن طريقها ترد إلى جسم الخلية البيانات الداخلة، ولابد للإشارات لكي تمر من عصبون إلى آخر أن تجتاز الفجوة الضيقة ما بين عقدة المشبك والجسم أو التفرّع للعصبون التالي. تتلقى الخلية العصبية عدة تنبيهات من الخلايا المجاورة تؤدي إلى شحنها، فإذا وصلت تلك الشحنة إلى عتبة معينة ينبثق كمون كهربائي عند قاعدة المحور وينتشر دفعة واحدة على طوله. لا تستجيب العصبونات لمختلف التنبيهات بشكل متشابه، فلكل منبه درجة أهمية تزيد أو تنقص، كما أن خرج العصبون لا يمتاز بالتدرج، فإما أن تكون هناك نبضة عصبية تنتشر عبر المحور إلى الخلايا المجاورة أو لن يكون هنالك شيء على الإطلاق. طبعا هذا الوصف لبنية العصبون وطريقة عمله فيه تبسيط شديد لحقيقة الأمر، لكن هذا المستوى من الشرح يفي بالغرض. على الرغم من أننا عندما نحاكي عمل العصبون (بفرض أننا نعلم طريقة عمله تماما) لن نحصل على عصبون حقيقي، لكننا سنحصل على معالجة حقيقية للمعلومات كما لو كان العصبون هو من قام بها، وهذا هو بيت القصيد. إن التمثيل الرياضي للعصبون يفترض أن لدينا n إشارة دخل سنرمز إليها بالمقادير X1, X2, …, Xn يرتبط كل منها بوزن أو تثقيل للتعبير عن دور المشابك العصبية كون العصبونات لا تستجيب بشكل متشابه لمختلف التنبيهات كما اتفقنا سابقا. سنرمز إلى تلك الأوزان بالمقادير W1, W2, …, Wn والتي قد تكون قيما موجبة أو حتى سالبة تكبر أو تصغر بحسب طبيعة ودور إشارة الدخل المرتبطة بها سواء كانت محفّزة أم مثبّطة وإلى أي قدر هي كذلك. وهكذا يمكننا التعبير عن مجمل الدخل الآتي إلى العصبون المفرد بالشكل الرياضي التالي: من جهة أخرى، لتمثيل إشارة خرج العصبون نحتاج إلى دالة رياضية تستطيع توصيف عمل قانون الكل أو لا شيء تبعا لعتبة معيّنة، وهناك عدّة خيارات رياضية شائعة قد يتم تفضيل إحداها على الأخرى بحسب طبيعة البيانات التي نتعامل معها نذكر منها على سبيل المثال لا الحصر: Sigmoid (للقيم الثنائية 0/1 أو نعم/لا أو حتى ذكر/أنثى)، TanH (للفئات أو التصنيفات المتقطعة مثل الأعراق: عربي، أوروبي، أفريقي، آسيوي، هندي، الخ.)، وكذلك ReLU (للقيم المتصلة كالعمر مثلا). يوضح الشكل التالي الصيغة الرياضية والتمثيل البياني الذي يظهر العلاقة فيما بين الدخل والخرج لكل منها: بعد أن قمنا بتوصيف العصبون بشكل رياضي مبسّط، علينا الانتقال للحديث عن بنية الشبكات التي تنتظم بها تلك العصبونات وطرق ارتباطها بعضها ببعض، سنتناول بالشرح شكلا واحدا من أشكال بناء الشبكات العصبية، لكن ذلك لا يعني عدم وجود معماريات أخرى لبناء تلك الشبكات. سنفترض أن العصبونات تنتظم في طبقات ولكل طبقة عدد من العصبونات بحيث أن خرج أي عصبون من هذه الطبقة يتم إيصاله إلى كل عصبونات الطبقة التالية. يمكن تمييز الطبقة الأولى على أنـها طبقة الإدخال والتي تتلقى بياناتها من الوسط الخارجي للشبكة العصبية، كذلك نعرّف طبقة الإخراج على أنـها الطبقة الأخيرة والتي ترسل ناتج معالجة البيانات ثانية إلى الوسط الخارجي، في حين يسمّى كل ما عدى ذلك من طبقات بين هاتين الطبقتين بالطبقات الخفية. كما نلاحظ فإن عدد العصبونات في كل من طبقتي الإدخال والإخراج محدد بحسب طبيعة الوظيفة المناطة بالشبكة العصبية (مثلا عدد العنصورات Pixels الإجمالي في الصورة لكل قناة لونية RGB في الدخل، وعدد الفئات المراد تصنيفها في الخرج)، أمّا عدد الطبقات الخفية وعدد العصبونات في كل منها فلا توجد قواعد ضابطة وواضحة لذلك. مكتبة TensorFlow من Google مكتبة TensorFlow هي منصة متكاملة لتدريب وبناء تطبيقات الذكاء الصنعي وتعلم الآلة بالاعتماد على تقنية الشبكات العصبية طورتها شركة Google باستخدام لغة Python ونشرتها تحت ترخيص البرمجيات الحرة والمفتوحة المصدر، وهي تعد في الوقت الراهن واحدة من أكثر المكتبات شهرة واستخداما في هذا المجال (رغم أنها ليست الوحيدة قطعا)، وذلك نظرا لغزارة وتنوع المصادر والأدوات المتوافرة لها والتي تتيح للباحثين القدرة على بناء واستخدام تطبيقات الذكاء الصنعي في أعمالهم. للمزيد حول TensorFlow يمكنكم الإطلاع على الموقع الرسمي لها على الرابط التالي: https://www.tensorflow.org دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن مكنز TensorFlow Hub للنماذج إحدى أهم التحديات في عالم الذكاء الصنعي بشكل خاص، وعلوم البيانات بشكل عام، هي القدرة على إعادة استخدام ما سبق وما توصل إليه فريق تطوير آخر سابقًا، لذا قدمت Google هذا المكنز لوضع طريقة معيارية في مشاركة نماذج الشبكات العصبية بحيث تتضمن كافة المعلومات المطلوبة لإعادة استخدامها سواء كانت بنية الشبكة العصبية ذاتها (من حيث عدد الطبقات، ونوعها، وعدد العصبونات في كل منها، ونوع الروابط فيما بينها، الخ.)، إضافة إلى قيم الوسطاء والأوزان المختلفة في تلك الشبكة العصبية بعد إتمام عملية تدريبها. يمكن أخذ هذه النماذج وإعادة استخدامها في مهام مختلفة أو حتى إعادة تدريبها بسهولة مستخدمين تقنية تدعى نقل التعلم والتي سنتحدث عنها لاحقا في هذا الدرس. لمزيد من المعلومات حول هذا المكنز يمكنكم زيارة الموقع الرسمي له على الرابط التالي: https://www.tensorflow.org/hub. نموذج MobileNet V2 للرؤية الحاسوبية تم تصميم هذه العائلة من نماذج الشبكات العصبية المخصصة لمهام الرؤية الحاسوبية عامة الأغراض مثل التصنيف وتحديد الأجزاء والعناصر في الصورة وسواها من الوظائف مع مراعاة المصادر المحدودة التي قد تكون متوافرة على الأجهزة المحمولة. إن القدرة على تشغيل تطبيقات التعلم العميق على أجهزة الجوال الشخصية ستحسن من تجربة المستخدم نظرا لأنها ستكون متاحة في أي زمان ومكان بغض النظر عن الحاجة إلى الاتصال بمصادر خارجية على الإنترنت، وهو ما سيترافق مع فوائد إضافية لجهة الأمان والخصوصية والاقتصاد في استهلاك الطاقة. لمزيد من المعلومات يمكنك الإطلاع على الرابط المدرج ضمن قسم المراجع1. تقنية نقل التعلم Transfer Learning إن النماذج الحديثة للتعرف على الصور تحتوي على الملايين من الوسطاء (من أوزان للروابط ما بين الآلاف من العصبونات المرصوفة في العشرات من الطبقات الخفية) والتي يتطلب تدريبها من الصفر كما كبيرا من بيانات التدريب من جهة، والكثير من الطاقة الحاسوبية من جهة أخرى (تقدّر بالمئات من ساعات الحساب على وحدات المعالجة الرسومية GPU أو حتى أكثر بكثير). إن تقنية نقل التعلم تعتمد على حيلة ذكية لاختصار كم المصادر الكبير الذي نحتاجه لتطوير نموذج رؤية حاسوبية جديد تخصص مهاراته في التعرف على نمط مختلف من الصور (مثلا صور الأشعة السينية لتشخيص وجود أورام سرطانية محتملة عوض التعرف على الأنواع المختلفة من الأزهار البرية). تقوم الفكرة على استبدال الطبقة الأخيرة فقط من شبكة عصبية سبق وأن تم تدريبها بشكل جيد على تصنيف الصور ولو لغايات مختلفة، مستفيدين بذلك من كم المهارات التي اكتسبتها بنية الطبقات الخفية في ذلك النموذج، ابتداء من التعرف على أنماط النسج والأشكال وترابط الأجزاء وعلاقات الألوان وغيرها مما هو مشترك بالعموم بين كافة نظم الرؤية الحاسوبية، والتي يمكن إعادة استخدامها ومشاركتها بين النماذج المختلفة. وحدها الطبقة الأخيرة فقط الخاصة بالأصناف تتغير بتغير الغاية والهدف من النموذج الذي يجري تطويره وتخصيصه، لذا هي وحدها التي سيتم تدريبها فعليا عند استخدام تقنية نقل التعلم هذه. لمزيد من المعلومات حول هذه التقنية في التعليم يمكنكم الإطلاع على رابط ورقة البحث العلمي المدرجة ضمن قسم المراجع أدناه2. تجهيز بيئة العمل سنستخدم منصة Docker المخصصة لتطوير ونشر وإدارة التطبيقات باستخدام فكرة الحاويات وذلك لتسهيل بناء بيئة العمل لدينا من أجل تنفيذ التطبيق العملي في هذه الجلسة، حيث أن الحاويات هي عبارة عن حزم تنفيذية خفيفة وقائمة بذاتها لتطبيق ما، تحوي كل المكتبات وملفات الإمداد والاعتماديات والأجزاء الأخرى الضرورية ليعمل التطبيق ضمن بيئة معزولة، هذا عدى عن أنها خفيفة لأنها لا تتطلب حملا إضافيا كالأجهزة الافتراضية كونها تعمل ضمن نواة النظام المضيف مباشرة دون الحاجة إلى نظام ضيف، وبذلك نزيل عن كاهلنا في هذه المرحلة أي تعقيدات تختص بالتنصيب والربط والإعداد لمختلف مكونات بيئة التطوير الخاصة بمكتبة TensorFlow وهي مهمة ليست باليسيرة على المبتدئ، لذا عليك القيام بتثبيت Docker على حاسوبك الشخصي من الموقع الرسمي https://www.docker.com/ قبل الانتقال إلى الخطوة التالية. اطلع على مقال «التعامل مع حاويات Docker» في قسم دوكر في أكاديمية حسوب. تطبيق عملي يقوم بتحديد جنس الشخص من صورة وجهه بداية نقوم بتنصيب TensorFlow على Docker ضمن حاوية تحت تسمية hsoub-ft، قد تتطلب هذه الخطوة بعض الوقت نظرا لكون حجم صورة الحاوية التي سيتم سحبها وتنزيلها عبر الإنترنت يتجاوز 1GB: docker pull tensorflow/tensorflow docker run --name hsoub-tf -it -d tensorflow/tensorflow:latest بعد ذلك نقوم بالدخول إلى سطر الأوامر ضمن الحاوية ونقوم بتنصيب الإصدار 2.0 على الأقل من مكتبة TensorFlow وكذلك الإصدار 0.6 على الأقل من نموذج تصنيف الصور3 الذي سنستخدمه والمستضاف في مكنز TensorFlow Hub، و بعد إتمام هذه الخطوات نخرج باستخدام الأمر exit في سطر الأوامر للعودة إلى الجهاز المضيف: docker exec -it hsoub-tf bash pip install "tensorflow~=2.0" pip install "tensorflow-hub[make_image_classifier]~=0.6" exit الخطوة التالية هي تحضير بيانات التدريب وذلك من خلال الحصول على الصور التي سيتم تدريب الشبكة عليها، في مثالنا هذا استخدمنا مجموعة جزئية تتكون من حوالي 2000 صورة مقسمة إلى فئتين ذكور وإناث وهي مقتطعة من مجموعة بيانات أكبر تدعى UTKFace4 المتاحة للاستخدامات غير التجارية والتي تتضمن بالأساس ما يزيد عن 20 ألف صورة وجه. تم اختيار الصور التي سوف نستخدمها في عملية التدريب بحيث تكون متوازنة من حيث الجنس (أي أن عدد الصور الخاصة بالذكور يساوي تقريبا عددها للإناث) والعرقيات (أي تقارب عدد الأشخاص من ذوي الأصول الأوروبية والأفريقية والهندية الخ.) وذلك لضمان عدم التحيز، إضافة إلى أن الصور تخص أشخاصا تتراوح أعمارهم ما بين 20 إلى 40 سنة. للمتابعة عليك تحميل الملف المضغوط المرفق مع هذا المحتوى، ثم قم بفك ضغطه على حاسوبك وستحصل على مجلد باسم training داخله ثلاث مجلدات هي images و output وكذلك test. ستلاحظ ضمن مجلد images أن هنالك مجلد فرعي لك تصنيف تريد من شبكتك العصبية أن تتعرف عليه (في حالتنا هذه هناك مجلدان فقط بتسمية Male و Female) داخل كل منهما مجموعة الصور التي تنتمي إلى ذلك التصنيف. من جهة أخرى فإن مجلد output هو فارغ حاليا لكنه المكان الذي سيتم فيه حفظ الشبكة العصبية بعد إتمام عملية تدريبها (أي حيث سنخزن النموذج الناتج)، أخيرا ستجد في المجلد الثالث test شيفرة برمجية بسيطة لاختبار النموذج الناتج وبعض الصور التي لم يسبق له أن رآها من قبل (أي أنها لم تكن موجودة أصلا ضمن صور وبيانات التدريب). نحن بحاجة إلى نقل كل هذه المجلدات وما فيها من ملفات إلى داخل الحاوية hsoub-tf وذلك باستخدام الأمر التالي على الجهاز المضيف: docker cp .\training hsoub-tf:/training الآن نستطيع الانتقال مجددا إلى سطر الأوامر ضمن الحاوية باستخدام الأمر التالي: docker exec -it hsoub-tf bash وبعد ذلك يمكننا بدء عملية التدريب باستخدام الأمر التالي: make_image_classifier \ --image_dir training/images dir \ --tfhub_module https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4 \ --image_size 224 \ --saved_model_dir training/output/model \ --labels_output_file training/output/class_labels.txt \ --tflite_output_file training/output/mobile_model.tflite إن وسطاء الأمر التنفيذي السابق تحدد المسار الذي يحتوي على مجلدات الصور التي سيتم استخدامها في عملية التدريب (أي مسار المجلد ضمن الحاوية وليس على الجهاز المضيف)، وكذلك مصدر النموذج الأصلي الذي ستطبق عليه تقنية نقل التعلم باستبدال طبقته الأخيرة، بعد ذلك نحدد الأبعاد المطلوبة للصور ليتم تحجيمها تلقائيا لتلائم هذه الأبعاد (فهذا محدد ومرتبط بطبقة الإدخال في نموذج الشبكة العصبية المستخدمة)، في حالتنا نحن نستخدم نموذج MobileNet V2 والذي يفترض أبعاد الصورة هي 224 عنصورة/بيكسل للطول والعرض، بعد ذلك نحدد المكان الذي سيتم فيه حفظ النموذج المدرّب الناتج، وكذلك أين سيتم حفظ التسميات المرافقة لعصبونات الخرج من شبكتنا العصبية بالترتيب، وأخيرا أين سيتم تصدير هذا النموذج بصيغة tflite المحزومة والموضبة لتطبيقات الجوال. في نهاية عملية التدريب (والتي قد تطول تبعا لعدد الصور من جهة، ولسرعة الحاسوب الذي تتم عليه عملية التدريب من جهة أخرى)، سنجد أننا حصلنا على نموذج شبكة عصبية يستطيع تمييز جنس الشخص من صورته بدقة تتعدى 80% وذلك بمجهود بسيط جدا دون الحاجة إلى عمليات ضبط ومعايرة فائقة التخصص لوسطاء بناء وتدريب الشبكة العصبية، ودون الحاجة كذلك إلى ساعات وساعات من التدريب ولا إلى آلاف وآلاف من الصورة للتدرب عليها! إنها بحق نتيجة مرضية لأوائل مغامراتك مع الشبكات العصبية، لكنها مجرد البداية. ها قد حان الوقت لتجربة النموذج الذي قمنا بتدريبه على صور لم يسبق له أن رآها من قبل، للقيام بذلك سوف نستخدم برنامج معد مسبقا لهذه الغاية5 وهو مكتوب بلغة Python وموجود داخل المجلد training/test صحبة بضعة صور كأمثلة للتجريب (ويمكن أن تستخدم صورك الخاصة في هذه المرحلة)، حيث ستتم عملية الاختبار لكل صورة من خلال الأمر التالي (وفيه نشير إلى مسار الشبكة العصبية التي سيتم تحميلها واستخدامها، والملف النصي الذي يتضمن اسم التصنيف الخاص بكل عصبون خرج ضمن هذه الشبكة بالترتيب، وأخيرا مسار الصورة المراد تصنيفها): python training/test/label_image.py \ --input_mean 0 --input_std 255 \ --model_file training/output/mobile_model.tflite \ --label_file training/output/class_labels.txt \ --image training/test/Ahmed_Zewail.jpg بعد إتمام تدريبنا واختبارنا للشبكة العصبية حان الوقت للخروج من بيئة التدريب هذه باستخدام الأمر exit للعودة إلى سطر الأوامر على الجهاز المضيف، ومن ثم سنرغب طبعا باستخراج النموذج الذي قمنا بتعليمه خلال هذه الجلسة من داخل حاوية Docker وهو ما نستطيع القيام به باستخدام الأمر التالي: docker cp hsoub-tf:/training/output .\training نقاط تستحق التأمل قد يرى البعض في تقنيات الذكاء الصنعي حلا لجميع المشكلات، لكنها في حقيقة الأمر لا تأتي خالية من المخاطر التي قد ترقى إلى حد اعتبارها نقاط ضعف أو عيوب يجب أن تؤخذ بعين الاعتبار، نذكر منها: باعتبار أن النماذج في الشبكات العصبية تبنى انطلاقا من بيانات التدريب، لذا فإنها غير قادرة على حل أي مشاكل كانت موجودة أصلا في تلك البيانات كالأخطاء أو الانحياز أو عدم التكامل والشمول لمختلف الحالات المراد التعامل معها. يصعب في الشبكات العصبية تفسير المنطق الذي استخدمه النموذج لإعطاء إجابته، فالتعامل معه أقرب ما يكون للصندوق الأسود الذي لا نعلم كمستخدمين آلية عمله الدقيقة في الداخل، بل نؤمن بأن ما نحصل عليه من إجابات هو أفضل المتاح، ولهذه الفكرة تداعياتها الفلسفية والاجتماعية التي تصعّب من استخدام هكذا أدوات في الحالات التي تتطلب تقديم تبرير (مثلا عند تطبيق عقوبة أو حرمان من مكافأة). تطوير نماذج الشبكات العصبية يتطلب قدرا كبيرا من بيانات التدريب المشروحة والمجهزة بشكل جيد وملائم، وهو ما قد يعني الكثير من الجهد لتوفير مثل هكذا مصادر للتدريب. عملية تدريب الشبكات العصبية هي عملية متطلّبة من ناحية قدرات المعالجة الحسابية المتوفّرة للعتاد المستخدم، وذلك على عكس عملية استخدامها في التطبيقات عقب إتمام التدريب، لذا قد يجد المطور في الحوسبة السحابية فرصا متاحة بميزانيات في المتناول. إن بناء النماذج باستخدام خوارزميات تعلم الآلة يتطلب مطورين أذكياء وموهوبين، فعلى الرغم من أن تطبيق المثال الذي قمنا بعرضه يبدو سهلا ويسيرا، إلا أن نظرة أكثر تعمقا ستكشف لك الكثير من التفاصيل التي بحاجة إلى معايرة وضبط، منها على سبيل المثال لا الحصر: معمارية الشبكة، وطريقة توصيف تابع تفعيل العصبونات فيها، وعدد طبقاتها الخفية، وعدد العصبونات في كل منها، وطريقة ربطها بعضها ببعض، وكيفية حساب الخطأ ما بين النتيجة المحسوبة والمطلوبة، ومعدل سرعة التعلم، وعدد مرات تكرار عرض الأمثلة على الشبكة العصبية أثناء التدريب، وغيرها الكثير. إن انتقاء التوليفة الأكثر ملائمة لجملة معايير الضبط هذه يؤثر بشكل حاسم على جودة ودقة النموذج الناتج. مراجع أجنبية للاستزادة MobileNetV2: The Next Generation of On-Device Computer Vision Networks DeCAF: A Deep Convolutional Activation Feature for Generic Visual Recognition Making your own TensorFlow model for image classification UTKFace: Large Scale Face Dataset TensorFlow Lite Python image classification demo اقرأ أيضًا تعلم الذكاء الاصطناعي الذكاء الاصطناعي: دليلك الشامل المقال التالي: إعداد شبكة عصبية صنعية وتدريبها للتعرف على الوجوه الذكاء الاصطناعي: مراحل البدء والتطور والأسس التي نشأ عليها
-
- 2
-
- تعرف على الوجوه
- شبكة عصبية
-
(و 2 أكثر)
موسوم في: