الصور كشبكات منظّمة
الصورة الرمادي مش أكتر من matrix في بُعدين من الأرقام. كل عنصر فيها — وهو الـ pixel — شايل قيمة شدّة ضوء بتتراوح بين 0 (أسود) و255 (أبيض). رقم MNIST مقاسه 28×28 هو matrix فيها 784 رقم. أما صورة 1080p ففيها 1920×1080 = 2,073,600 pixel.
والصور الملوّنة بتزوّد بُعد تالت هو الـ channels (القنوات). الصورة RGB العادية فيها تلات channels — الأحمر والأخضر والأزرق — متراصّين في tensor شكله H×W×3. فصورة RGB مقاسها 224×224 هي tensor في تلات أبعاد فيه 224×224×3 = 150,528 رقم. وبعض المجالات بتستخدم channels أكتر؛ زي الأشعة المقطعية الطبية بعشرات الشرايح، والتصوير الفضائي الطيفي اللي بيعدّي المرئي.
إيه اللي بيخلّي الصور مميزة ويستاهل الاهتمام ده؟ قيم الـ pixels مش مستقلة. الـ pixels اللي جنب بعض بتميل تبقى شبه بعض (المحلية المكانية)، ونفس الـ pattern — زي حافة أو زاوية أو ملمس — ممكن يظهر في أي حتة في الصورة (الثبات مع الإزاحة). والـ fully connected layer اللي بتعامل كل pixel لوحده بتتجاهل الخاصيتين ودول وتكلفتها فلكية: layer واحدة بتوصّل 150,528 input بـ 1000 output محتاجة 150 مليون parameter. والـ convolutional neural networks (الشبكات العصبية التلافيفية) بتستغل بنية الصورة عشان تبقى أكفأ وأفعل بكتير.
عملية الـ convolution
العملية الأساسية هي الـ convolution (الالتواء) (أو بالدقة الـ cross-correlation في أغلب تطبيقات الـ deep learning). matrix صغيرة اسمها الـ filter (المرشّح) أو الـ kernel (النواة) بتتزحلق على الصورة الداخلة. وفي كل مكان، بتحسب الضرب عنصر بعنصر بينها وبين الحتة اللي فوقها من الصورة، وبعدين تجمع النواتج في قيمة output واحدة. والناتج في كل مكان بيكوّن الـ output feature map (خريطة المزايا).
نفس الـ filter بيتطبّق في كل مكان. والـ weight sharing (مشاركة الأوزان) دي هي مصدر الكفاءة الأساسي: filter 3×3 فيه 9 parameters بس بيتعلّموا مهما كان حجم الصورة، وبيتعلّم يكشف نفس الـ pattern المحلي في كل مكان. قارن ده بالـ fully connected layer اللي فيها كل output ليه مجموعة weights خاصة بيه لكل pixel داخل.
رياضيًا، الـ convolution الحقيقي بيقلب الـ filter قبل ما يزحلقه (لفّة 180°). وأغلب libraries الـ deep learning بتنفّذ الـ cross-correlation اللي بيعدّي القلب ده، وبتسمّيه "convolution". ولأن weights الـ filter بتتعلّم، الفرق مالوش أثر عملي: الشبكة بتتعلّم الـ weights اللي محتاجاها سواء مقلوبة ولا لأ.
الـ filters بتكشف إيه: الحواف والتنعيم والتوضيح
قبل الـ convolutional networks، مهندسين الـ computer vision كانوا بيصمّموا الـ filters بإيديهم. عملية الـ convolution واحدة — القيم اللي جوه الـ filter بس هي اللي بتختلف. وفهم الـ filters المعمولة بالإيد بيبني إحساس باللي الـ filters المتعلّمة بتكتشفه لوحدها.
الـ Sobel filter (مرشّح سوبل) بيكشف الحواف الأفقية أو الرأسية. الـ kernel الأفقي بتاع Sobel هو [−1, 0, 1; −2, 0, 2; −1, 0, 1]: بيطرح العمود الشمال من اليمين فبيكبّر المناطق اللي شدّة الضوء فيها بتتغيّر بسرعة من الشمال لليمين. ولو طبّقته على صورة وش بيطلّع حواف العينين والمناخير والبُق كخطوط منوّرة.
الـ Gaussian blur filter بياخد متوسط الـ pixels اللي جنب بعض بـ weights جاوسية، فبينعّم الصورة. بيقلّل الـ noise والتفاصيل اللي ترددها عالي. وقيم الـ filter شكلها منحنى الجرس: الـ pixel اللي في النص بياخد أعلى weight وبيقل ناحية الأطراف. وفي الـ convolutional networks، الـ layers الأولى كتير بتتعلّم filters شبه filters جابور بتجمع كشف الحواف مع الحساسية للاتجاه، شبه خلايا القشرة البصرية في الثدييات.
الـ sharpening filter (مرشّح التوضيح) بيشتغل بالعكس: بيكبّر الفرق بين كل pixel وجيرانه فبيبرز الحواف. kernel التوضيح المعتاد ليه نص موجب كبير وحواليه سالب: [0, −1, 0; −1, 5, −1; 0, −1, 0].
في أول layer من convolutional network متدرّبة، الـ filters شبه functions جابور — كاشفات حواف وألوان ليها اتجاه. والـ layers الأعمق بتجمّعها في ملامس، وبعدين أجزاء، وبعدين مفاهيم عالية المستوى. والتركيب الهرمي ده — من حواف لملامس لأجزاء لأجسام — بيطلع لوحده من الـ gradient descent (النزول التدرجي)، زي المسار البطني في القشرة البصرية.
الـ stride: التحكم في حجم القفزة
افتراضيًا، الـ filter بيتزحلق pixel واحد كل مرة (stride 1). وزيادة الـ stride (الخطوة) لـ s بتخلّي الـ filter ينط s pixel بين الأماكن. stride 2 على input 6×6 مع filter 3×3 (من غير padding) بيطلّع output 2×2 بدل 4×4 — يعني الدقة المكانية بتتنصّ.
والـ stride طريقة من طرق الـ spatial downsampling (التقليص المكاني). الـ strided convolution بيعمل نفس شغل الـ convolution العادي وبعده اختيار كل output رقم s — بس في لفّة واحدة. والـ convolutions اللي الـ stride بتاعها 2 مشهورة في الـ architectures الحديثة كبديل لـ layers الـ pooling، فبتدّي downsampling بيتعلّم بدل عملية ثابتة.
الـ padding: الحفاظ على الحجم المكاني
من غير padding، كل convolution بيقلّص الأبعاد المكانية. لـ filter مقاسه k×k، الـ output بيبقى (H−k+1)×(W−k+1). ورص layers كتير من غير padding بيقلّص الـ feature map بسرعة لحد ما تختفي.
الـ zero padding (الحشو بأصفار) بيزوّد إطار أصفار حوالين الـ input قبل ما الـ filter يتطبّق. والـ same padding (الحشو المتماثل) بيزوّد أصفار كفاية عشان الـ output يبقى بنفس الحجم المكاني للـ input (مع stride 1). ولـ filter k×k، ده محتاج padding قده p = (k−1)/2 من كل ناحية. والـ valid padding (الحشو الصحيح) معناه مفيش padding خالص — الـ filter بيتطبّق بس في الأماكن اللي بيتداخل فيها كله مع الـ input.
الـ pooling: التلخيص المكاني
بعد الـ convolutional layer، الـ feature maps كتير بتتقلّص بعملية الـ pooling (التجميع). الـ pooling بيقلّل الدقة المكانية وهو محتفظ بأقوى المزايا اللي اتكشفت، فبيخلّي التمثيل أخصر وبيدّي قدر من الثبات مع الإزاحة.
الـ max pooling (تجميع الحد الأقصى) بيقسم الـ feature map لشبابيك مش متداخلة (عادةً 2×2) ويحتفظ بأكبر قيمة في كل واحد. الفكرة: لو feature اتكشفت في أي حتة في المنطقة 2×2 دي، بنحتفظ بأقوى كشف. والـ max pooling هو الأشهر لأنه بيختار أقوى استجابة ويتجاهل الـ activations الضعيفة.
الـ average pooling (تجميع المتوسط) بياخد متوسط كل شباك بدل أكبر قيمة. بيحتفظ بالمعلومات المتفرّشة مش بالقمم. والـ average pooling بيتستخدم في آخر architectures حديثة كتير (الـ global average pooling) عشان يطوي الـ feature map كلها لرقم واحد لكل channel قبل layer الـ classification الأخيرة.
قبل الـ dense layer الأخيرة، الـ architectures القديمة (AlexNet وVGG) كانت بتعمل flattening للـ feature maps لـ vector طويل فبتوصل لملايين الـ parameters. والـ architectures الحديثة بتستخدم الـ global average pooling (التجميع الكروي للمتوسط) بدل كده: بتقلّص كل channel للمتوسط المكاني بتاعها فبتطلّع vector طوله بيساوي عدد الـ channels. feature map مقاسها 7×7×512 بتبقى vector بـ 512 بُعد مع الـ global pooling، بس 25,088 بُعد مع الـ flattening.
الـ receptive field والمزايا الهرمية
الـ receptive field (المجال الاستقبالي) بتاع الـ neuron هو المنطقة من الصورة الداخلة اللي تقدر تأثّر على الـ activation بتاعه. convolutional layer واحدة 3×3 الـ receptive field بتاعها 3×3. وlayerين 3×3 فوق بعض الـ field الفعلي بتاعهم 5×5. وتلات layers بيدّوا 7×7. وفي العموم، رص L layer من filters k×k بيدّي field فعلي [L(k−1)+1]×[L(k−1)+1].
وده مفتاح التعلّم الهرمي للمزايا. الـ layers الأولى الـ receptive fields بتاعتها صغيرة وبتكتشف patterns محلية: حواف وزوايا وبقع لون. والـ layers اللي في النص بتجمّعها في تراكيب أكبر: ملامس وأجزاء. والـ layers العميقة بتدمج على مستوى الصورة كلها عشان تتعرّف على الأجسام الكاملة. وكل layer بتشوف سياق أوسع من اللي تحتها.
والـ pooling بيسرّع نمو الـ receptive field الفعلي. بعد max pooling 2×2، كل مكان convolution بعد كده بيغطّي ضعف المدى المكاني الأصلي. والشبكة اللي بتبدّل بين layers convolution وpooling بتشوف الصورة كلها في layers قليلة نسبيًا.
ليه الـ convolution بيشتغل مع الصور
تلات inductive biases (تحيزات استقرائية) بيخلّوا الـ convolution مناسب بشكل فريد للبيانات المرئية:
الـ local connectivity (الترابط المحلي). كل neuron في الـ output بيتوصّل بحتة صغيرة بس من الـ input مش بالصورة كلها. وده مبرّر لأن الـ patterns اللي ليها معنى — حواف وملامس — محلية: pixel عند المكان (10, 10) مبيقولكش حاجة عن pixel بعيد عند (200, 200) لما بتكشف حافة محلية.
الـ weight sharing. نفس الـ filter بيتطبّق في كل مكان. كاشف الحواف اللي اتعلّم في حتة من الصورة المفروض يشتغل في أي حتة تانية. والافتراض ده — إن إحصائيات الصورة تقريبًا ثابتة على المكان — صح على نطاق واسع وبيقلّل الـ parameters بمعامل بيساوي عدد الأماكن.
الـ translation invariance (الثبات مع الإزاحة). لو قطة ظهرت فوق على الشمال في صورة وتحت على اليمين في صورة تانية، الـ convolutional layers بتطلّع نفس الـ activations بس متزاحة في المكان. ومعنى كده إن الشبكة مش محتاجة تتعلّم من جديد تكشف القطط في كل مكان ممكن — تبسيط كبير قصاد الـ fully connected networks.
الـ convolutional layers equivariant (متكافئة) مع الإزاحة: إزاحة الـ input بتزيح الـ feature map بنفس المقدار. والـ pooling بيدّي invariance (ثبات): الـ output مبيتغيّرش مع الإزاحات الصغيرة. ورؤوس الـ classification محتاجة الثبات (label "قطة" مينفعش يتغيّر مع المكان)، فالـ convolutional networks بتجمع بين الـ convolution المتكافئ والـ pooling الثابت عشان تاخد أحسن ما في الاتنين. وخد بالك إن الـ convolutions مش ثابتة مع اللف أو تغيير الحجم — ده بيتعالج بالـ data augmentation أو architectures متخصصة.
- الصور tensors شكلها H×W×C. الرمادي C=1؛ والـ RGB C=3. قيم الـ pixels بتشفّر الشدّة أو اللون، والـ pixels اللي جنب بعض مترابطة مكانيًا — خاصية الـ convolutional networks بتستغلها.
- الـ convolution بيزحلق filter صغير على الـ input ويحسب نواتج الضرب عنصر بعنصر ويجمعها في كل مكان. والـ weight sharing بيدّي الـ filter اللي مقاسه k×k عدد k² parameter بس مهما كان حجم الصورة.
- الـ filters المعمولة بالإيد (Sobel والـ Gaussian والتوضيح) بتكشف اللي الـ convolution يقدر يرصده. والـ convolutional networks بتتعلّم الـ filters لوحدها، فبتكتشف حواف في الـ layers الأولى ومزايا معقّدة في الأعمق.
- الـ stride بيتحكم الـ filter بينط كام pixel كل خطوة. والـ stride الأكبر بيصغّر حجم الـ output. والـ padding (same قصاد valid) بيتحكم إذا كان الحجم المكاني هيتحفظ ولا هيتقلّص.
- الـ max pooling بياخد أكبر قيمة في كل شباك مكاني؛ والـ average pooling بياخد المتوسط. والاتنين بيقلّصوا الـ feature map. والـ global average pooling بيطوي الخريطة المكانية كلها لرقم واحد لكل channel.
- الـ receptive field بتاع الـ neuron هو منطقة الـ input اللي بيشوفها. رص L layer من filters k×k بيدّي field فعلي [L(k−1)+1]². والـ pooling بيسرّع نمو الـ receptive field.
- الـ convolution بيشتغل بفضل تلات inductive biases: الـ local connectivity (الـ patterns محلية)، والـ weight sharing (نفس الـ pattern في كل حتة)، والـ translation equivariance (إزاحة الـ input بتزيح الـ output). والـ pooling بيزوّد الثبات.