Kodax

Convolutional Neural Networks — التعلم العميق

الشبكات الالتفافية (CNN)

لماذا لا تكفي الطبقات الكثيفة للصور؟

- صورة ملونة 224×224 = 150,528 مدخلاً. طبقة Dense من 1000 عصبون = 150 مليون وزن في طبقة واحدة!

- التسطيح يدمّر البنية المكانية: البكسلات المتجاورة مرتبطة، وتسطيحها يخفي ذلك.

- قطة في الزاوية وقطة في الوسط يجب أن تُعرفا بنفس الطريقة.

الالتفاف (Convolution)

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

import numpy as np

image = np.array([
    [0, 0, 0, 9, 9, 9],
    [0, 0, 0, 9, 9, 9],
    [0, 0, 0, 9, 9, 9],
    [0, 0, 0, 9, 9, 9],
])
kernel = np.array([[-1, 0, 1]] * 3)       # مرشح يكتشف الحواف الرأسية

h, w = image.shape[0] - 2, image.shape[1] - 2
out = np.zeros((h, w))
for i in range(h):
    for j in range(w):
        out[i, j] = (image[i:i + 3, j:j + 3] * kernel).sum()
print(out)   # قيم كبيرة فقط حيث تنتقل الصورة من داكن إلى فاتح

في CNN لا نصمم المرشحات: الشبكة تتعلم قيمها. الطبقات الأولى تتعلم مرشحات حواف وألوان، والأعمق أنماطاً أعقد.

لماذا هو فعّال؟

- مشاركة الأوزان: نفس المرشح (9 أوزان) يُطبق على كل الصورة.

- الاتصال المحلي: كل مخرج يعتمد على منطقة صغيرة.

- ثبات الإزاحة: النمط يُكتشف أينما ظهر.

طبقة Conv2D(32, (3,3)) على صورة RGB = 32 × (3×3×3 + 1) = 896 وزناً فقط.

المصطلحات

| المصطلح | المعنى |

|---|---|

| عدد المرشحات | عدد خرائط الميزات الناتجة (32، 64...) |

| kernel_size | حجم المرشح (3×3 الأشيع) |

| strides | قفزة المرشح؛ 2 تصغّر المخرج للنصف |

| padding="same" | حشو بالأصفار ليبقى الحجم كما هو؛ "valid" بلا حشو |

| Pooling | تصغير الخريطة: MaxPooling2D(2) يأخذ الأكبر من كل 2×2 |

البنية النموذجية

صورة ← [Conv ← ReLU ← Conv ← ReLU ← Pool] × عدة مرات ← GlobalAveragePooling ← Dense ← Softmax
       (الأبعاد المكانية تصغر، وعدد المرشحات يكبر: 32 ← 64 ← 128)

GlobalAveragePooling2D (متوسط كل خريطة) بديل حديث لـ Flatten يقلل المعاملات كثيراً ويخفف الحفظ.

تمرين

عدّل المرشح في المثال إلى كاشف حواف أفقية واختبره على صورة نصفها العلوي داكن. ثم احسب يدوياً عدد معاملات Conv2D(64, (3,3)) بعد طبقة فيها 32 مرشحاً.

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

# ===== تحميل CIFAR-10 =====
(X_train, y_train), (X_test, y_test) = keras.datasets.cifar10.load_data()

# التطبيع
X_train = X_train / 255.0
X_test = X_test / 255.0

print(f"Shape: {X_train.shape}")  # (50000, 32, 32, 3)

# ===== بناء CNN =====
model = keras.Sequential([
    # Block 1
    layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),
    layers.MaxPooling2D((2, 2)),
    
    # Block 2
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    
    # Block 3
    layers.Conv2D(64, (3, 3), activation='relu'),
    
    # Classification Head
    layers.Flatten(),
    layers.Dense(64, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(10, activation='softmax')
])

model.summary()

# ===== التدريب =====
model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

history = model.fit(
    X_train, y_train,
    epochs=10,
    batch_size=64,
    validation_split=0.1
)

# ===== التقييم =====
test_loss, test_acc = model.evaluate(X_test, y_test)
print(f"Test Accuracy: {test_acc:.2%}")
اختبر فهمك