كيفية عرض المرشّحات وخرائط المزايا في شبكات الطيّ العصبونية

Visualize filters
Visualize filters

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

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

عرض طبقات الطيّ

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

اختيار نموذج مُدرّب مُسبقًا من شبكات الهندسة البصرية VGG

في البداية يجب اختيار النموذج الذي سنقوم بعرض مرشّحاته وخرائط مزاياه. وعوضًا عن القيام بملائمة نموذج من البداية يمكن استخدام نموذج تصنيف صور مناسب ومعدّ بشكل مسبق، توفّر مكتبة كيراس  العديد من الأمثلة لنماذج تعمل بشكل جيد في تصنيف الصور  تم تطويرها من قبل مجموعات بحث مختلفة لتحدي التعرف البصري على ايمج نت ImageNet أو ما يطلق عليها اسم ILSVRC ومن هذه النماذج سنختار النموذج “مجموعة الهندسة البصرية VGG-16 ” الذي أعطى أفضل النتائج في منافسة عام 2014 وهو نموذج عميق مكون من 16 طبقة مدرّبة يمكن استخدامه في عرض المرشّحات وخرائط المزايا كونه يملك بنية موحدة بسيطة مكونة من طبقات طيّ وتجميع مرتبة بشكل تسلسلي وهو ذو أداء جيد جدًا و هذا يعني أن المرشّحات وخرائط المزايا الناتجة ستستخلص  مزايا مفيدة. لمزيد من المعلومات عن هذا النموذج يمكن الرجوع إلى الورقة المسماة “ شبكات الطيّ العميقة جدًأ للتعرف على الصور على نطاق واسع” التي صدرت في عام 2015.
يمكن تحميل وتلخيص نموذج في جي جي   VGG-16 من خلال بضعة أسطر من الشيفرة البرمجية على الشكل التالي:

from keras.applications.vgg16 import VGG16
model = VGG16()
model.summary()

بتشغيل الشيفرة البرمجية السابقة على ورقة جوبيتر Jupyter Notebook في جوجل كولاب google colab سيتم تحميل أوزان النموذج إلى الذاكرة ومن ثم طباعة ملخّص النموذج كما في الشكل (1).

الشكل (1): نموذج مجموعة الهندسة البصرية VGG-16

عند تحميل النموذج لأول مرة سيتم تحميل الأوزان من الانترنت و تخزينها في مسار العمل home directory. حجم هذه الأوزان هو 500 ميجا بايت تقريبًا، لذلك من الممكن أن تأخذ بضعة لحظات ليتم تحميلها حسب سرعة الاتصال لديك. نلاحظ في الشكل (1) أن الطبقات مسماة بشكل جيد ومنظمة ضمن كتل وذات فهرس بأرقام صحيحة ضمن كل كتلة. 
بعد أن أصبح لدينا نموذجًا مدرّبامسبقًأ يمكننا الآن استخدامه كأساس للعرض visualization.

كيفية عرض المرشّحات

ربما أبسط طريقة للعرض هي من خلال رسم المرشّحات المدرّبة بشكل مباشر. و في علم مصطلحات الشبكة العصبونية المرشّحات المدرّبة هي ببساطة الأوزان، و لكن بسبب البنية ثنائية الأبعاد للمرشّحات سيكون لقيم الأوزان علاقة مكانية مع بعضها البعض ورسم كل مرشّح كصورة ثنائية البعد سيكون له معنى أو يمكن أن يكون كذلك.
الخطوة الأولى هي مراجعة المرشّحات في النموذج لمعرفة ما علينا القيام به. في الشكل (1) تم طباعة خلاصة عن النموذج مع شكل الخرج لكل طبقة (شكل خرائط المزايا الناتجة) لكن دون طباعة  شكل المرشّحات (الأوزان) في الشبكة وإنما فقط العدد الكلي للأوزان بالطبقة. يمكن الوصول إلى كل الطبقات في النموذج من خلال الخاصية model.layers
و كل طبقة لها خاصية تدعى layer.name حيث طبقات الطيّ تسمى بالشكل  block#_conv# و # هو عبارة عن رقم صحيح بالتالي يمكن فحص اسم كل طبقة وتخطي أي طبقة لا تحتوي على المحارف “conv”

for layer in model.layers:
	if 'conv' not in layer.name:
		continue

كل طبقة طيّ لها مجموعتين من الأوزان الأولى هي كتلة من المرشّحات والثانية هي كتلة من قيم الانحيازات. يمكن من خلال استخدام التابع  layer.get_weights() الحصول على هذه الأوزان ومن ثم تلخيص شكلها.

filters, biases = layer.get_weights()
print(layer.name, filters.shape)

بتجميع الشيفرة السابقة معًأ:

from keras.applications.vgg16 import VGG16
from matplotlib import pyplot
model = VGG16()
for layer in model.layers:
  if 'conv' not in layer.name:
    continue
  filters, biases = layer.get_weights()
  print(layer.name, filters.shape)

ونتيجة التنفيذ ستكون طباعة قائمة من تفاصيل الطبقات بما في ذلك اسم الطبقة وشكل المرشحات فيها كما هو مبين في الشكل (2).

الشكل(2): طباعة أسماء الطبقات مع الفهارس وشكل المرشحات فيها

نلاحظ أن جميع طبقات الطيّ تستخدم المرشحات ذات الأبعاد 3×3 والتي تعتبر صغيرة وربما سهلة التفسير. وبما أن بنية شبكات الطيّ العصبونية تفترض بأن يكون عمق المرشّح مطابق لعمق الدخل  (عدد القنوات) بالتالي من أجل صورة دخل ذات ثلاث قنوات (أحمر, أخضر, أزرق) ستكون المرشّحات بعمق ثلاثة و يمكن أن يتم العرض إمّا من خلال رسم ثلاث صور (صورة لكل قناة) أو ضغط القنوات الثلاثة معًا في صورة ملونة وحيدة أو النظر فقط  إلى القناة الأولى والافتراض أن بقية القنوات ستكون مشابهة. المشكلة تكمن في وجود 63  مرشح آخر يجب عرضهم وذلك لأن عدد المرشحات هو ٦٤!
يمكن استرجاع المرشّحات من الطبقة الأولى كما يلي:

filters, biases = model.layers[1].get_weights()

قيم الأوزان عبارة عن قيم موجبة وسالبة صغيرة  تتمحور حول الصفر. يمكن تقييس قيمها لتكون ضمن المجال [0,1] وبالتالي يسهل عرضها.

f_min, f_max = filters.min(), filters.max()
filters = (filters - f_min) / (f_max - f_min)

يمكن الآن عدّ أول ستة مرشّحات من ال64 مرشح في الكتلة ومن ثم رسم القنوات الثلاثة لكل مرشّح منها. سنستخدم مكتبةُ الرَّسمِ الرِّياضيِّ في بايثون (ماتبلوت) matplotlib لرسم كل مرشّح في سطر جديد وكل قناة مرشّح (عمق) في عمود جديد.

n_filters, ix = 6, 1
for i in range(n_filters):
	f = filters[:, :, :, i]
	for j in range(3):
		ax = pyplot.subplot(n_filters, 3, ix)
		ax.set_xticks([])
		ax.set_yticks([])
		pyplot.imshow(f[:, :, j], cmap='gray')
		ix += 1
pyplot.show()

بتجميع ما سبق تصبح الشيفرة البرمجية الكاملة لرسم أول ستة مرشّحات من طبقة الطيّ الخفية في نموذج في جي جي  على الشكل التالي:

from keras.applications.vgg16 import VGG16
from matplotlib import pyplot
model = VGG16()
filters, biases = model.layers[1].get_weights()
f_min, f_max = filters.min(), filters.max()
filters = (filters - f_min) / (f_max - f_min)
n_filters, ix = 6, 1
for i in range(n_filters):
	f = filters[:, :, :, i]
	for j in range(3):
		ax = pyplot.subplot(n_filters, 3, ix)
		ax.set_xticks([])
		ax.set_yticks([])
		pyplot.imshow(f[:, :, j], cmap='gray')
		ix += 1
pyplot.show()

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

الشكل(3): رسم أول ستة مرشّحات من نموذج الهندسة البصرية مع تفصيل كل قناة

على الرغم من أننا استطعنا عرض مرشّحات طبقة الطيّ الأولى بشكل واضح إلا أننا عرضنا ستة فقط من أصل 64 وكان كل منها بثلاث قنوات وحتى في حال أردنا عرض بقية المرشّحات سيبقى الأمر ممكنًا!
لكن ماذا لو أردنا عرض مرشّحات الطبقة الثانية! 64 مرشّح وكل منها ب64 قناة مطابقة لخرائط المزايا؟ عندها لرؤية جميع هذه المرشّحات مع قنواتها سيتطلب ذلك رسم (64 × 64) 4096 صورة وسيكون من الصعب رؤية أي تفاصيل فيها!

كيفية عرض خرائط المزايا

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

الشكل(4): صورة الطائر روبن الملتقطة من قبل كريس هيلد المستخدمة كدخل للنموذج

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

from keras.applications.vgg16 import VGG16
from matplotlib import pyplot
model = VGG16()
for i in range(len(model.layers)):
	layer = model.layers[i]
	if 'conv' not in layer.name:
		continue
	print(i, layer.name, layer.output.shape)

بتشغيل الشيفرة السابقة سنرى نفس أشكال الخرج الذي رأيناه في خلاصة النموذج لكن هذه المرة فقط لطبقات الطيّ.

الشكل(5):طباعة أسماء الطبقات مع الفهارس وشكل خرائط المزايا فيها

يمكن الاستفادة من المعلومات الناتجة في بناء نموذج جديد يحوي مجموعة جزئية من الطبقات الموجودة في نموذج في جي جي  الكامل. سيكون للنموذج الجديد نفس طبقة دخل النموذج الأساسي لكن الخرج سيكون خرج طبقة طيّ معطاة والذي نعلم أنه سيكون تفعيل هذه الطبقة (خريطة المزايا). بعد تحميل نموذج في جي جي  يمكن أن نُعرّف نموذج جديد سيكون الخرج فيه خريطة المزايا من طبقة الطيّ الأولى ذات الفهرس 1 كما يلي:

model = Model(inputs=model.inputs, outputs=model.layers[1].output)

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

img = load_img('bird.jpg', target_size=(224, 224))

بعد ذلك نقوم بتحويل الصورة من تمثيل بيل PIL إلى مصفوفة بايثون العددية Numpy لبيانات البيكسل و توسيعها من مصفوفة ثلاثية الأبعاد إلى مصفوفة رباعية البعد 4D (العينات، الأسطر، الأعمدة، القنوات) ولدينا هنا عينة واحدة.

img = img_to_array(img)
img = expand_dims(img, axis=0)

ثم القيام بتقييس قيم البيكسل لتصبح ملائمة لنموذج في جي جي

img = preprocess_input(img)

الآن أصبحنا جاهزين للحصول على خريطة المزايا، يمكن القيام بذلك بسهولة من خلال استدعاء التابع model.predict() وتمرير الصورة التي قمنا بتجهيزها.

feature_maps = model.predict(img)

نحن نعلم أن النتيجة ستكون خريطة مزايا بأبعاد 224x224x64. يمكن طباعة جميع الصور ثنائية الأبعاد الـ 64 كصور مربعة 8×8.

square = 8
ix = 1
for _ in range(square):
	for _ in range(square):
		ax = pyplot.subplot(square, square, ix)
		ax.set_xticks([])
		ax.set_yticks([])
		pyplot.imshow(feature_maps[0, :, :, ix-1], cmap='gray')
		ix += 1
pyplot.show()

بتجميع جميع الخطوات معًأ ستعطي الشيفرة البرمجية التالية خريطة المزايا لطبقة الطيّ الأولى من نموذج في جي جي  لصورة الدخل ا (الطائر) على الشكل التالي:

from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.models import Model
from matplotlib import pyplot
from numpy import expand_dims
model = VGG16()
model = Model(inputs=model.inputs, outputs=model.layers[1].output)
model.summary()
img = load_img('bird.jpg', target_size=(224, 224))
img = img_to_array(img)
img = expand_dims(img, axis=0)
img = preprocess_input(img)
feature_maps = model.predict(img)
square = 8
ix = 1
for _ in range(square):
	for _ in range(square):
		ax = pyplot.subplot(square, square, ix)
		ax.set_xticks([])
		ax.set_yticks([])
		pyplot.imshow(feature_maps[0, :, :, ix-1], cmap='gray')
		ix += 1
pyplot.show()

بتشغيل الشيفرة السابقة سيتم أولًا تلخيص النموذج الجديد المُصغّر من نموذج في جي جي   والذي لا يزال يستخدم نفس الأوزان (المرشّحات) الموجودة في طبقة الطيّ الأولى من النموذج الأساسي ويقوم بأخذ الصورة ليعطي خريطة المزايا.

الشكل(6):طباعة خلاصة النموذج الجديد المصغر من نموذج في جي جي

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

الشكل(7):عرض خرائط المزايا المستخرجة من طبقة الطيّ الأولى في نموذج في جي جي  VGG16

تعتبر النتيجة التي حصلنا عليها جيدة وتتوافق بشكل عام مع توقّعاتنا. بالإمكان تعديل الشيفرة البرمجية لرسم خرائط مزايا من خرج طبقات طيّ محددة أخرى. ويمكن أيضًأ تنفيذ ما سبق بأسلوب آخر وذلك من خلال تجميع خرائط المزايا للخرج من كل كتلة من النموذج في مرور واحد ومن ثم إنشاء صورة لكل منها. وبما أن هناك خمس كتل رئيسية في الصورة تنتهي كل منها بطبقة تجميع Pooling layer فإن  فهارس أخر طبقة طيّ في كل كتلة ستكون  [2, 5, 9, 13, 17]. بالتالي يمكننا أيضًأ تعريف نموذج جديد يمتلك أكثر من خرج (خرج خريطة مزايا واحدة لكل آخر طبقة طيّ في كل كتلة كما يلي,:

ixs = [2, 5, 9, 13, 17]
outputs = [model.layers[i+1].output for i in ixs]
model = Model(inputs=model.inputs, outputs=outputs)
model.summary()

سينتج عن التنبؤ بهذا النموذج الجديد قائمة من خرائط المزايا. نحن نعلم بأن عدد خرائط المزايا (مثل: العمق أو عدد القنوات) في الطبقات الأعمق يزيد كثيرًأ عن 64 ليصل مثلًا إلى  256 أو 512. ومع ذلك يمكننا تحديد عدد خرائط المزايا المراد عرضها بالعدد 64 للحفاظ على التناسق.

square = 8
for fmap in feature_maps:
	ix = 1
	for _ in range(square):
		for _ in range(square):
			ax = pyplot.subplot(square, square, ix)
			ax.set_xticks([])
			ax.set_yticks([])
			pyplot.imshow(fmap[0, :, :, ix-1], cmap='gray')
			ix += 1
	pyplot.show()

ومن خلال ربط جميع التغييرات مع بعضها البعض يمكن إنشاء خمس رسمات فرعية لكل كتلة من الكتل الخمسة الموجودة في نموذج في جي جي  لصورة الطائر لدينا. الشيفرة البرمجية الكاملة لذلك هي كما يلي:

from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.models import Model
from matplotlib import pyplot
from numpy import expand_dims
model = VGG16()
ixs = [2, 5, 9, 13, 17]
outputs = [model.layers[i].output for i in ixs]
model = Model(inputs=model.inputs, outputs=outputs)
img = load_img('bird.jpg', target_size=(224, 224))
img = img_to_array(img)
img = expand_dims(img, axis=0)
img = preprocess_input(img)
feature_maps = model.predict(img)
square = 8
for fmap in feature_maps:
	ix = 1
	for _ in range(square):
		for _ in range(square):
			ax = pyplot.subplot(square, square, ix)
			ax.set_xticks([])
			ax.set_yticks([])
			pyplot.imshow(fmap[0, :, :, ix-1], cmap='gray')
			ix += 1
	pyplot.show()

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

الشكل(8): خرائط المزايا لخمسة من الكتل الأساسية الموجودة في نموذج في جي جي

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

الخاتمة

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

المراجع

[1]-How to Visualize Filters and Feature Maps in Convolutional Neural Networks
[2]- Convolutional Neural Network: Feature Map and Filter Visualization
[3]- Karen Simonyan, Andrew Zisserman, Visual Geometry Group, Department of Engineering Science, University of Oxford, “Very Deep Convolutional Networks for Large-Scale Image Recognition”, 2015

0 Shares:
اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

You May Also Like