الدرس 8 من 8

الـ Transfer Learning

إزاي تعمل موديل صور ممتاز بمية صورة بس.

الفكرة

لو بتتعلم تسوق عربية نقل وانت أصلاً بتسوق ملاكي، مش هتبدأ من الصفر: انت عارف الدريكسيون والفرامل والإشارات، ومحتاج تتعلم الفرق بس. الـ Transfer Learning نفس الكلام: موديل اتدرب على ملايين الصور (ImageNet) واتعلم يشوف حواف وأشكال وأجزاء، وانت بتعلّمه بس آخر خطوة الخاصة بمشكلتك.

Transfer Learningمئات الصور، دقايق تدريب على GPU واحد، ودقة عالية.
من الصفرملايين الصور، أيام أو أسابيع تدريب، وأجهزة غالية.

حمّل موديل جاهز وجهّزه

هنعمل موديل يفرق بين ٣ أكلات مصرية: كشري، وطعمية، وملوخية. هناخد ResNet18 المتدرب، نجمّد كل طبقاته، ونبدل آخر طبقة بطبقة جديدة فيها ٣ مخرجات:

resnet_setup.py
import torch
from torch import nn
from torchvision.models import resnet18, ResNet18_Weights

model = resnet18(weights=ResNet18_Weights.DEFAULT)   # downloads pretrained weights

for param in model.parameters():          # freeze everything it already learned
    param.requires_grad = False

print("original last layer:", model.fc)
model.fc = nn.Linear(model.fc.in_features, 3)   # new head: koshari / falafel / molokhia

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

من أكتر من ١١ مليون وزن، هنتدرب على ١٥٣٩ بس. عشان كده التدريب سريع ومحتاج صور قليلة.

جهّز الصور في فولدرات

folder structure
food_data/
    train/
        koshari/      img001.jpg, img002.jpg, ...
        falafel/      ...
        molokhia/     ...
    val/
        koshari/      ...
        falafel/      ...
        molokhia/     ...
# folder names become the class names automatically

التدريب

train_food.py
import torch
from torch import nn
from torchvision import datasets, transforms
from torchvision.models import resnet18, ResNet18_Weights
from torch.utils.data import DataLoader

device = "cuda" if torch.cuda.is_available() else "cpu"
weights = ResNet18_Weights.DEFAULT

train_tf = transforms.Compose([
    transforms.RandomResizedCrop(224),     # data augmentation:
    transforms.RandomHorizontalFlip(),     # new variations every epoch
    weights.transforms(),                  # resize + normalize like ImageNet
])
train_ds = datasets.ImageFolder("food_data/train", transform=train_tf)
val_ds = datasets.ImageFolder("food_data/val", transform=weights.transforms())
train_dl = DataLoader(train_ds, batch_size=32, shuffle=True)
val_dl = DataLoader(val_ds, batch_size=32)

model = resnet18(weights=weights)
for p in model.parameters():
    p.requires_grad = False
model.fc = nn.Linear(model.fc.in_features, len(train_ds.classes))
model = model.to(device)

opt = torch.optim.Adam(model.fc.parameters(), lr=1e-3)   # only the new head
loss_fn = nn.CrossEntropyLoss()

for epoch in range(5):
    model.train()
    for xb, yb in train_dl:
        xb, yb = xb.to(device), yb.to(device)
        opt.zero_grad()
        loss_fn(model(xb), yb).backward()
        opt.step()

    model.eval()
    correct = 0
    with torch.no_grad():
        for xb, yb in val_dl:
            preds = model(xb.to(device)).argmax(1).cpu()
            correct += (preds == yb).sum().item()
    print(f"epoch {epoch}: val accuracy = {correct / len(val_ds):.1%}")
data augmentation بنعمل نسخ معدلة من الصور (قص، قلب، إضاءة) فالموديل يشوف تنوع أكتر من غير صور جديدة.
freezing إنك توقف تعلم الطبقات القديمة عشان متبوظش اللي اتعلمته.
fine-tuning بعد ما الـ head الجديدة تتعلم، ممكن تفك آخر كام طبقة وتدربهم بـ learning rate صغير جداً.
💡 منين تجيب موديلات جاهزة؟torchvision.models فيها أشهر موديلات الصور. ومكتبة timm فيها مئات. وHugging Face فيه آلاف الموديلات لكل حاجة: صور، ونصوص، وصوت، وهتعيش فيه في المرحلة الجاية.
🚀 مشروعكصوّر ٥٠ صورة لكل نوع من ٣ حاجات حواليك (أنواع نبات، ماركات عربيات، أكلات)، وطبّق الكود ده في Colab. في أقل من ساعة هيبقى عندك موديل صور حقيقي عملته بنفسك، وده مشروع ممتاز للـ portfolio.
الدرس اللي فات