اذهب إلى المحتوى

إعداد شبكة عصبية صنعية وتدريبها للتعرف على الوجوه


خالد الشمعة

بنية الشبكات العصبية الصنعية

تتكون الشبكات العصبية الصنعية من عناصر أولية بسيطة من حيث طريقتها في معالجة البيانات تدعى العصبونات، ويمكن تمثيل أي من تلك العصبونات رياضيا -وفق مفاهيم البرمجة غرضية التوجه- على شكل كائن برمجي Object يتضمن كل نسخة (Instance) منه على مصفوفة من أوزان الدخل يساوي حجمها عدد إشارات الدخل الواردة لهذا العصبون والتي قد تتراوح ما بين العشرات والآلاف تبعا لبنية الشبكة العصبية وهيكليتها. إن معالجة العصبون الواحد للإشارات الواردة بسيطة من الناحية الرياضية، حيث يتم ضرب كل إشارة دخل بقيمة الوزن المقابل لها ومن ثم تجمع كافة النواتج لنحصل على مقدار كلي يمثل درجة استثارة العصبون أو شحنته الإجمالية، ومن ثم يرسل هذا الرقم إلى تابع التفعيل، وهو ببساطة علاقة رياضية تحاكي إلى حد ما سلوك العصبونات الحقيقية فيما يخص قانون الكل أو لاشيء مع بعض التصرف لاعتبارات تتعلق بخوارزميات التعليم المستخدمة (إمكانية حساب المشتق الرياضي كما في حالة تابع Sigmoid) أو لاعتبارات براغماتية عملية (سهولة البرمجة وسرعة التنفيذ كما في حالة التابع ReLU) أو حتى لاعتبارات تتعلق بطبيعة البيانات المعالجة (كشيوع استخدام التابع TanH عند التعامل مع بيانات الفئات والأصناف). في نهاية المطاف تستخدم قيمة الاستثارة الإجمالية للعصبون كدخل لتابع التفعيل x هذا، وبتطبيق العلاقة الرياضية الخاصة بتابع التفعيل المحدد للعصبون نحسب قيمة y المقابلة والتي تمثل الآن خرج هذا العصبون.

neuron.png

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

nn-network (1).png

الفرق ما بين تدريب واستخدام الشبكات العصبية الصنعية

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

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

كيفية حفظ وتصدير الشبكات العصبية الصنعية

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

عادة ما تقوم مكتبة TensorFlow بحفظ نموذج الشبكة العصبية الصنعية بكافة وسطائها وقيمها ضمن مجلد خاص بذلك خلال عملية التدريب والذي يمكن قراءته واستعادة بنية شبكته العصبية باستخدام لغة Python (ستجد ضمنه ملف بامتداد ‎*.pb إضافة إلى مجلدين فرعيين هما variables وassets)، لكن هذه الصيغة من الحفظ ملائمة فقط لبيئة التطوير ولا تصلح للتطبيق العملي. عوضا عن ذلك أتاحت Google مجموعة من الصيغ المعيارية المناسبة للتطبيقات المختلفة من أهمها صيغة ‎*.tfjs الموجهة للمبرمجين بلغة JavaScript ذائعة الصيت وواسعة الانتشار في عالم الويب سواء باستخدامها على طرف المستعرض أو حتى على طرف المخدم من خلال تقنية Node.js، كذلك لدينا صيغة ‎*.tflite والمصممة أصلا لتعمل بموارد محدودة من سرعة معالجة ومساحة ذاكرة وذلك بهدف استخدامها على أجهزة الجوال أو إنترنت الأشياء.

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

مكتبة Face-API

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

https://justadudewhohacks.github.io/face-api.js/docs/

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

تم بناء نموذج التعرف على العمر والجنس باستخدام شبكة عصبية صنعية متعددة المهام توظف فيها طبقة استخلاص سمات الوجه لتقدير العمر وكذلك لتصنيف الجنس، يبلغ حجم حزمة النموذج بالإجمال قرابة 420kb، وقد تم تدريبها واختبارها باستخدام قواعد بيانات متعددة لصور الوجوه الموسومة بالعمر والجنس الحقيقيين (منها على سبيل المثال موسوعة Wikipedia وقاعدة IMDB للأفلام والممثلين)، وتبلغ دقتها 95% في تحديد الجنس، وهامش خطئها في تحديد العمر يقارب 4 سنوات ونصف.

استخدام الشبكات العصبية في نافذة متصفحك

لنقم بداية بإنشاء مجلد جديد وليكن اسمه face-api للمشروع الذي سنعمل عليه اليوم ضمن مخدم الويب المحلي الذي لديك لتجربة تطبيقات الويب التي تعمل عليها (أي ضمن المجلد C:\xampp\htdocs على سبيل المثال في حال كنت تستخدم مخدم XAMPP)، سنضيف داخل ذلك المجلد الرئيسي مجلدين فرعيين باسم js وكذلك models، ومن ثم نقوم بنسخ الملفات التي نحتاجها من مكتبة Face-API الأصلية على الشكل التالي:

نُنزِّل الصيغة المصغرة/المضغوطة من المكتبة ذاتها (أي الملف "face-api.min.js") ونسخها إلى داخل المجلد الفرعي js في مشروعنا، يمكن الحصول على ذلك الملف من العنوان التالي: https://github.com/justadudewhohacks/face-api.js/tree/master/dist نُنَزِّل نماذج الشبكات العصبية الصنعية التي سنستخدمها، حيث يوجد ملفين لكل نموذج شبكة عصبية أحدهما ينتهي إسمه بكلمة "shard1" تحفظ فيه قيم أوزان الشبكة، أما الآخر فهو ملف بصيغة json يصف بنية الشبكة حتى يتم قراءة وتحميل قيم الأوزان السابقة بشكل سليم. في مثالنا الحالي سنحتاج إلى استخدام شبكتين عصبيتين هما "age_gender_model" و "tiny_face_detector_model"، أي أننا بحاجة إلى تنزيل أربع ملفات ومن ثم نسخها إلى داخل مجلد models في مشروعنا. يمكنك الحصول على تلك الملفات من العنوان التالي:

https://github.com/justadudewhohacks/face-api.js/tree/master/weights

بعد ذلك سنُنشِئ ملفين جديدين أحدهما سندعوه index.html سنضعه في المجلد الرئيسي للمشروع، أما الآخر فسندعوه main.js ونضعه ضمن المجلد الفرعي js المخصص لشيفرات لغة JavaScript البرمجية. سنقوم بداية بتنقيح محتوى صفحة HTML والتي سنجعلها بأبسط شكل ممكن بغرض التركيز على العناصر الأساسية التي نهتم بها:

<html>
  <head>
    <title>Face-API Example</title>
  </head>
  <body>

  </body>
</html>

ضمن قسم body سنقوم بإضافة عنصر div فيه عنصر video لعرض الفيديو الذي تلتقطه كاميرا حاسوبك ندعوه webcam، ويتم ضبطها لتعمل تلقائيا ضمن النمط الصامت بمجرد تحميل الصفحة:

<div class="container">
    <video id="webcam" height="360" width="360" autoplay muted></video>
</div>

ثم نضيف حقل إدخال input مخصص للعمر ندعوه age:

Age (years): <input id="age" size="3"><br />

بعد ذلك نضيف مجموعة أزرار اختيار من نوع radio ندعوها gender فيها اختيارين اثنين هما male وfemale:

<input id="male" type="radio" name="gender" value="male">Male<br />
<input id="female" type="radio" name="gender" value="female">Female<br />

أخيرا وبعد اكتمال تحميل وعرض كافة عناصر الصفحة، نقوم بتضمين ملفات جافاسكريبت في نهاية محتويات الصفحة حتى نكون متأكدين من وصولها برمجيا لكافة العناصر ضمن تلك الصفحة:

<script src="js/face-api.min.js"></script>
<script src="js/main.js"></script>

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

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

لذلك سنبدأ بكتابة محتوى الملف main.js من الشيفرات البرمجية مع شرح مختصر لكل قسم منها، فالسطر الأول يقوم بتعيين اسم الثابت video للإشارة إلى العنصر المدعوة webcam ضمن صفحة HTML السابقة:

const video = document.getElementById("webcam");

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

Promise.all([
  faceapi.nets.tinyFaceDetector.loadFromUri("models"),
  faceapi.nets.ageGenderNet.loadFromUri("models")
]).then(startVideo);

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

function startVideo() {
  navigator.getUserMedia(
    { video: {} },
    stream => (video.srcObject = stream),
    err => console.error(err)
  );
}

ومن ثم نضيف حدث يقوم بالإنصات لما يتم عرضه ضمن عنصر video بحيث يستدعي بشكل غير متزامن async (أي دون الحاجة لانتظار الإجابة حتى يتابع عرض الفيديو) وذلك كل ثانية (حيث تم ضبط الفترة الزمنية setInterval لتكون قيمتها 1000 ميلي ثانية). يقوم هذا الاستدعاء الدوري المتكرر بتعيين قيمة الكائن detection بواسطة مكتبة faceapi حيث تحدد جميع الوجوه الموجودة ضمن كائن video بالاستعانة بنموذج TinyFaceDetector مستخدمين الإعدادات الافتراضية، ومن ثم يمرر الناتج (أي الوجوه التي تم التعرف عليها في الصورة)، إلى الشبكة العصبية الأخرى التي تتعرف على العمر والجنس:

video.addEventListener("playing", () => {
   setInterval(async () => {
    const detections = await faceapi
      .detectAllFaces(video, new faceapi.TinyFaceDetectorOptions())
      .withAgeAndGender();

إن العبارة الشرطية التالية تتأكد إن كان الكائن detections موجودا أصلا (تذكر أن تعيين قيمة هذا الكائن تتم من خلال استدعاء غير متزامن وبالتالي يمكن أن تكون القيمة غير موجودة في البداية ريثما تصل إجابة ذلك الاستدعاء). ليس هذا فحسب، بل يجب أن يتضمن على الأقل وجه واحد على الأقل. فإن تحقق هذين الشرطين يتم قراءة الجنس المتوقع للوجه الأول detections[0].gender وتعيينه لعنصر الإدخال المقابل له، وكذلك قراءة العمر المتوقع لذات الوجه الأول detections[0].age وتقريبه إلى أقرب عدد صحيح باستخدام التابع Math.round ومن ثم إسناده كقيمة لعنصر الإدخال المدعو age ضمن صفحة HTML السابقة:

if (detections && Object.keys(detections).length > 0) {
      document.getElementById(detections[0].gender).checked = true;
      document.getElementById("age").value = Math.round(detections[0].age);
    }
  }, 1000);
});

هذا كل شيء! تستطيع الآن تجربة هذا التطبيق البسيط من خلال عرض الصفحة على نافذة المستعرض مستخدمين عنوانها على مخدم الويب المحلي وليكن على سبيل المثال: http://localhost/face-api

screenshot.png

نقاط تستحق التأمل

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

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

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

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

مراجع للاستزادة

  1. مكتبة TensorFlow
  2. مكتبة face-api.js
  3. Model optimization

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...