Machine Learning: الشبكات العصبية التلافيفية

آخر تحديث: 2026-08-26

تمنح CNNs أجهزة الكمبيوتر "عيونًا" — تعمل نوى التلافيف كمستقبلات بصرية، وتتعرف على الصور طبقة بعد طبقة، من الحواف إلى الأشياء.

1. ما ستتعلمه


2. قصة حقيقية من التجارة الإلكترونية

(1) نقطة الألم: تصنيف المنتجات اليدوي بطيء وغير متسق

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

(2) حل CNN

تتعلم CNNs تلقائيًا الميزات البصرية من صور المنتجات لأداء التصنيف — سرعة على مستوى المللي ثانية، اتساق قوي، وصفر تكلفة عمالة.

PYTHON
import torchvision.models as models

# التعلم بالنقل: استخدم ResNet المدرب مسبقًا
model = models.resnet18(pretrained=True)
model.fc = nn.Linear(model.fc.in_features, num_classes)  # استبدل الطبقة الأخيرة

(3) النتائج: دقة تصنيف 95%، توفير 30 ألف دولار شهريًا

استخدم Bob CNN + التعلم بالنقل لأتمتة تصنيف المنتجات، محققًا دقة تتجاوز 95%. تحسنت سرعة المعالجة من 5 ثوانٍ لكل صورة إلى 0.01 ثانية لكل صورة، مما يوفر 30 ألف دولار من تكاليف العمالة الشهرية.


3. كيف يعمل التلافيف

(1) النوى واستخراج الميزات

100%
graph TB
    INPUT[صورة الإدخال<br/>H x W x C] --> CONV1[طبقة تلافيف 1<br/>حواف وخطوط]
    CONV1 --> POOL1[طبقة تجميع 1<br/>تقليل المكاني]
    POOL1 --> CONV2[طبقة تلافيف 2<br/>قوام وأجزاء]
    CONV2 --> POOL2[طبقة تجميع 2]
    POOL2 --> CONV3[طبقة تلافيف 3<br/>أشياء وأشكال]
    CONV3 --> FLATTEN[تسطيح]
    FLATTEN --> FC[متصل بالكامل]
    FC --> OUTPUT[احتمالات الفئة]

▶ مثال: تنفيذ التلافيف يدويًا

PYTHON
import torch
import torch.nn as nn

# الإدخال: صورة واحدة، قناة واحدة، 5x5
input_img = torch.tensor([[
    [1, 2, 0, 1, 3],
    [0, 1, 2, 3, 1],
    [1, 3, 1, 0, 2],
    [2, 0, 3, 1, 1],
    [0, 1, 2, 0, 1],
]], dtype=torch.float32).unsqueeze(0)  # الشكل: (1, 1, 5, 5)

# Conv2d: قناة إدخال واحدة، قناة إخراج واحدة، نواة 3x3
conv = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0)
print(f"Kernel weights:\n{conv.weight.data.squeeze()}")
print(f"Bias: {conv.bias.data.item():.4f}")

output = conv(input_img)
print(f"\nInput shape: {input_img.shape}")
print(f"Output shape: {output.shape}")
print(f"Output:\n{output.squeeze().detach()}")

Output:

TEXT 📖 للعرض فقط
# Execution successful

(2) معاملات التلافيف

المعامل المعنى التأثير
kernel_size حجم النواة 3x3 (شائع) / 5x5 / 7x7
stride حجم الخطوة 1 (افتراضي) / 2 (اختزال)
padding حشو بالأصفار 0 (يصغر) / 1 (يحافظ على الحجم)
in_channels عدد قنوات الإدخال RGB=3، رمادي=1
out_channels عدد قنوات الإخراج يساوي عدد النوى

▶ مثال: مقارنة تكوينات التلافيف المختلفة

PYTHON
import torch.nn as nn

x = torch.randn(1, 3, 32, 32)  # دفعة واحدة، 3 قنوات، 32x32

configs = {
    "3x3, stride=1, pad=1": nn.Conv2d(3, 16, 3, stride=1, padding=1),
    "3x3, stride=2, pad=1": nn.Conv2d(3, 16, 3, stride=2, padding=1),
    "5x5, stride=1, pad=2": nn.Conv2d(3, 16, 5, stride=1, padding=2),
    "5x5, stride=2, pad=0": nn.Conv2d(3, 16, 5, stride=2, padding=0),
}

for name, layer in configs.items():
    out = layer(x)
    print(f"{name:25s}: {x.shape} → {out.shape}")

Output:

TEXT 📖 للعرض فقط
# Execution successful

4. طبقات التجميع وبنيات CNN

(1) عمليات التجميع

▶ مثال: MaxPool مقابل AvgPool

PYTHON
import torch
import torch.nn as nn

x = torch.tensor([[
    [1, 3, 2, 4],
    [5, 6, 7, 8],
    [9, 2, 1, 3],
    [4, 5, 6, 7],
]], dtype=torch.float32).unsqueeze(0)  # (1, 1, 4, 4)

maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
avgpool = nn.AvgPool2d(kernel_size=2, stride=2)

print(f"Input:\n{x.squeeze()}")
print(f"\nMaxPool (2x2):\n{maxpool(x).squeeze()}")
print(f"\nAvgPool (2x2):\n{avgpool(x).squeeze()}")

Output:

TEXT 📖 للعرض فقط
# Execution successful

(2) تطور البنيات الكلاسيكية

البنية السنة الابتكار العمق المعاملات
LeNet 1998 أول CNN 5 60 ألف
AlexNet 2012 ReLU + Dropout + GPU 8 60 مليون
VGG 2014 نوى صغيرة مكدسة (3x3) 16-19 138 مليون
ResNet 2015 وصلات متبقية (وصلات تخطي) 18-152 11-60 مليون

▶ مثال: بناء CNN بسيط باستخدام PyTorch

PYTHON
import torch
import torch.nn as nn

class SimpleCNN(nn.Module):
    def __init__(self, num_classes=5):
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 32, 3, padding=1),   # 3→32 قناة، 32x32
            nn.ReLU(),
            nn.MaxPool2d(2, 2),               # 32→16x16
            nn.Conv2d(32, 64, 3, padding=1),  # 32→64 قناة، 16x16
            nn.ReLU(),
            nn.MaxPool2d(2, 2),               # 16→8x8
            nn.Conv2d(64, 128, 3, padding=1), # 64→128 قناة، 8x8
            nn.ReLU(),
            nn.MaxPool2d(2, 2),               # 8→4x4
        )
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(128 * 4 * 4, 256),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(256, num_classes),
        )

    def forward(self, x):
        x = self.features(x)
        x = self.classifier(x)
        return x

model = SimpleCNN(num_classes=5)
print(model)
print(f"Parameters: {sum(p.numel() for p in model.parameters()):,}")

Output:

TEXT 📖 للعرض فقط
# Function defined successfully

5. التعلم بالنقل

(1) لماذا يعمل التعلم بالنقل

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

▶ مثال: التعلم بالنقل مع ResNet18

PYTHON
import torch
import torch.nn as nn
import torchvision.models as models
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import numpy as np

# تحميل ResNet18 المدرب مسبقًا
model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)

# تجميد جميع الطبقات (وضع مستخرج الميزات)
for param in model.parameters():
    param.requires_grad = False

# استبدل آخر طبقة متصلة بالكامل
num_classes = 5  # Electronics, Clothing, Food, Books, Home
model.fc = nn.Linear(model.fc.in_features, num_classes)

# فقط طبقة fc الجديدة لها معاملات قابلة للتدريب
trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
total = sum(p.numel() for p in model.parameters())
print(f"Trainable: {trainable:,} / Total: {total:,} ({trainable/total*100:.1f}%)")

# تحويلات البيانات للنموذج المدرب مسبقًا
transform = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

Output:

TEXT 📖 للعرض فقط
# Execution successful

(2) استراتيجيات الضبط الدقيق

الاستراتيجية الطبقات المجمدة حجم بيانات التدريب وقت التدريب الأفضل لـ
مستخرج الميزات الكل (تدريب fc فقط) صغير (<1k) سريع بيانات محدودة جدًا
ضبط دقيق جزئي الطبقات الأخيرة القليلة متوسط (1-10k) متوسط بيانات معتدلة
ضبط دقيق كامل لا شيء كبير (>10k) بطيء بيانات وفيرة

▶ مثال: ضبط دقيق للطبقات الأخيرة القليلة

PYTHON
import torchvision.models as models
import torch.nn as nn

model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)

# تجميد الطبقات المبكرة، أطلق تجميد layer4
for name, param in model.named_parameters():
    if "layer4" in name or "fc" in name:
        param.requires_grad = True
    else:
        param.requires_grad = False

model.fc = nn.Linear(model.fc.in_features, 5)

trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"Fine-tune trainable params: {trainable:,}")

Output:

TEXT 📖 للعرض فقط
# Execution successful

6. تصنيف صور منتج SalesPredict

▶ مثال: خط أنابيب تدريب التعلم بالنقل الكامل

PYTHON
import torch
import torch.nn as nn
import torchvision.models as models
from torch.utils.data import DataLoader, TensorDataset
from sklearn.model_selection import train_test_split
import numpy as np

# محاكاة بيانات الصور (عمليًا، حمّل صورًا حقيقية مع ImageFolder)
rng = np.random.default_rng(42)
n = 2000
X = rng.standard_normal((n, 3, 224, 224)).astype(np.float32)  # 3 قنوات 224x224
y = rng.integers(0, 5, n)  # 5 فئات منتجات

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

train_ds = TensorDataset(torch.FloatTensor(X_train), torch.LongTensor(y_train))
test_ds = TensorDataset(torch.FloatTensor(X_test), torch.LongTensor(y_test))
train_loader = DataLoader(train_ds, batch_size=32, shuffle=True)
test_loader = DataLoader(test_ds, batch_size=64)

# ResNet18 المدرب مسبقًا مع رأس مخصص
model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
for param in model.parameters():
    param.requires_grad = False
model.fc = nn.Linear(model.fc.in_features, 5)

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.fc.parameters(), lr=0.001)

# التدريب
for epoch in range(10):
    model.train()
    correct, total = 0, 0
    for X_batch, y_batch in train_loader:
        y_pred = model(X_batch)
        loss = criterion(y_pred, y_batch)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        correct += (y_pred.argmax(1) == y_batch).sum().item()
        total += y_batch.size(0)

    if epoch % 2 == 0:
        print(f"Epoch {epoch}: loss={loss.item():.4f}, acc={correct/total:.3f}")

# تقييم
model.eval()
correct, total = 0, 0
with torch.no_grad():
    for X_batch, y_batch in test_loader:
        y_pred = model(X_batch)
        correct += (y_pred.argmax(1) == y_batch).sum().item()
        total += y_batch.size(0)

print(f"\nTest Accuracy: {correct/total:.3f}")

Output:

TEXT 📖 للعرض فقط
# Execution successful

❓ أسئلة شائعة

س لماذا CNNs أنسب للصور من MLPs؟
ج ثلاثة أسباب — 1) مشاركة المعاملات (نفس النواة تمسح الصورة بأكملها، مما يقلل المعاملات)؛ 2) الترابط المحلي (كل خلية عصبية ترى منطقة محلية فقط)؛ 3) ثبات الترجمة (يتم التعرف على الأشياء بغض النظر عن الموضع). تعمل MLPs على تسطيح الصور وتفقد البنية المكانية.
س كم البيانات التي يتطلبها التعلم بالنقل؟
ج وضع مستخرج الميزات (تدريب طبقة fc فقط) يحتاج فقط بضع مئات من الصور؛ ضبط الطبقات الأخيرة القليلة يتطلب 1-10 آلاف صورة؛ التدريب من الصفر يحتاج 10 آلاف+ صورة. كلما قلّت البيانات، يجب تجميد المزيد من الطبقات.
س لماذا نواة 3x3 هي الأكثر استخدامًا؟
ج تلافيفتان 3x3 مكدستان لهما نفس حقل الاستقبال كنواة 5x5 واحدة، لكن مع معاملات أقل (18 مقابل 25) ولاخطية أقوى (تفعيلتان ReLU). أظهر VGG أن تكديس النوى الصغيرة يتفوق على الكبيرة.
س ما هي الوصلات المتبقية في ResNet؟
ج y = F(x) + x — تتعلم الشبكة الباقي (الزيادة) بدلاً من التعيين الكامل. الفوائد: تحل مشكلة تلاشي التدرج في الشبكات العميقة وتتيح تدريب شبكات من 100+ طبقة.
س لماذا نحتاج Normalize في المعالجة المسبقة للصور؟
ج تم تطبيع النماذج المدربة مسبقًا باستخدام متوسط ImageNet والانحراف المعياري. يجب أن تستخدم البيانات الجديدة نفس التطبيع؛ وإلا، لن تتطابق توزيعات الميزات وسيتأثر أداء التعلم بالنقل.
س كيف تتعامل مع عدم توازن الفئات؟
ج ثلاث طرق — 1) دالة خسارة موزونة (nn.CrossEntropyLoss(weight=class_weights))؛ 2) الإفراط في عينات فئة الأقلية؛ 3) زيادة البيانات (قلبات/تدوير/اقتصاص عشوائي).

📖 ملخص

📝 تمارين

  1. أساسي (الصعوبة ⭐): ابنِ CNN من طبقتين باستخدام nn.Conv2d + nn.MaxPool2d بإدخال 3x32x32 ومخرج 16x8x8. اطبع الشكل بعد كل طبقة. تلميح: Conv2d(3,8,3,pad=1) → Pool → Conv2d(8,16,3,pad=1) → Pool.
  2. متوسط (الصعوبة ⭐⭐): استخدم التعلم بالنقل (ResNet18) لتصنيف CIFAR-10 (10 فئات). تجميد جميع الطبقات باستثناء fc ودرب لـ 5 حقب. تلميح: torchvision.datasets.CIFAR10 + transforms.
  3. تحدٍّ (الصعوبة ⭐⭐⭐): قارن مستخرج الميزات مقابل الضبط الدقيق الجزئي مقابل الضبط الدقيق الكامل على CIFAR-10 من حيث الدقة ووقت التدريب. ارسم منحنيات الدقة مقابل الحقبة للاستراتيجيات الثلاث. تلميح: تجميد أعداد مختلفة من الطبقات وسجل دقة الاختبار في كل حقبة.

← الدرس السابق: مقدمة في التعلم العميق | الدرس التالي: تقييم النموذج والضبط →

Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%