ژرفا — خودآموز یادگیری عمیق و مهندسی هوش مصنوعی (متوسط)

فصل ۱ از ۸

پیشرفت ترم
۰٪

ترم ۳ · دیدن: CNN و انتقالِ یادگیری

تصویر یعنی عدد

فصل ۱پیش‌نمایش رایگان

در این فصل چه یاد می‌گیری#

دو ترم با جدول و بردار کار کردی. این ترم با تصویر کار می‌کند — و اولین چیزی که باید بفهمی این است که برای کامپیوتر هیچ تفاوتی نیست: تصویر هم یک tensor است، فقط با چیدمانِ خاصِ خودش.

در این فصل آن چیدمان را می‌بینی، قراردادِ C×H×W را که در کلِ PyTorch ثابت است یاد می‌گیری، و تصویر را برای دو مقصدِ متفاوت آماده می‌کنی: شبکهٔ خودت و مدلِ آمادهٔ فصلِ ۴.

یک شبکهٔ مربعیِ ریز که هر خانه‌اش یک درجهٔ روشنایی دارد

آخر این فصل می‌توانی:

  • tensor یک تصویر را بخوانی و ابعادش را توضیح بدهی
  • قراردادِ C×H×W و جای batch را بگویی
  • تصویر را درست نرمال کنی
  • تصویرِ خاکستری را برای یک مدلِ آماده آماده کنی

قبل از شروع#

از ترمِ ۱ فصل ۱: tensor، shape، dtype.

از ترمِ ۲ فصل ۳: نرمال‌سازی و اینکه آمار را فقط از دادهٔ آموزش می‌گیری.

دادهٔ این ترم: FashionMNIST — ۷۰ هزار تصویرِ ۲۸×۲۸ خاکستری در ده دستهٔ پوشاک. اولین اجرا چند دقیقه دانلود می‌خواهد، بعدش چند ثانیه.

📓 نوت‌بوک: نوت‌بوک این فصل را در Colab باز کن — همهٔ کدهای این فصل آماده و به‌ترتیب داخلش هست.

💡 نکته: هر فصلِ این ترم روی CPU قابلِ اجراست. GPU سریع‌ترش می‌کند ولی هیچ فصلی بدونش نمی‌شکند — همان قاعدهٔ سختِ این دوره.

۱. یک تصویر، به‌صورتِ عدد#

import torch
import torch.nn as nn

image = Xtr[0]

print("شکل یک تصویر:", tuple(image.shape))
print("نوع:", image.dtype, "| کمینه:", float(image.min()), "| بیشینه:", float(image.max()))
print("برچسب:", int(ytr[0]), "->", CLASSES[int(ytr[0])])
شکل یک تصویر: (1, 28, 28)
نوع: torch.float32 | کمینه: 0.0 | بیشینه: 1.0
برچسب: 9 -> Ankle boot

(1, 28, 28) یعنی یک کانال، بیست‌وهشت سطر، بیست‌وهشت ستون. آن 1 تعدادِ کانالِ رنگ است — تصویرِ خاکستری یک کانال دارد و تصویرِ رنگی سه‌تا.

این ترتیب — C×H×W — قراردادِ ثابتِ PyTorch است و در کلِ ترم تکرار می‌شود. کتابخانه‌های دیگر (مثلاً PIL و matplotlib) ترتیبِ H×W×C را به‌کار می‌برند و همین یکی از رایج‌ترین خطاهای شکل در کارِ با تصویر است.

۲. batch هم یک بُعدِ دیگر#

print("شکل batch:", tuple(Xtr[:8].shape))
print("C×H×W یعنی:", "کانال =", image.shape[0], "| ارتفاع =", image.shape[1], "| عرض =", image.shape[2])
print("سطر میانی (خام ۰..۲۵۵):", (image[0, 14] * 255).round().int().tolist())
شکل batch: (8, 1, 28, 28)
C×H×W یعنی: کانال = 1 | ارتفاع = 28 | عرض = 28
سطر میانی (خام ۰..۲۵۵): [0, 0, 1, 4, 6, 7, 2, 0, 0, 0, 0, 0, 237, 226, 217, 223, 222, 219, 222, 221, 216, 223, 229, 215, 218, 255, 77, 0]

آن سطر همان تصویر است. دوازده خانهٔ اول همه زیر ۱۰ هستند — زمینهٔ سیاه، که چند خانه‌اش دقیقاً صفر نیست بلکه ۱ و ۴ و ۶ است. بعد یک رشتهٔ طولانی از عددهای بالای ۲۰۰ (بدنهٔ روشنِ چکمه)، و در انتها ۷۷ و صفر.

همان چند خانهٔ «تقریباً سیاه» خودش یک درس است: زمینهٔ یک تصویرِ واقعی به‌ندرت عددِ گردِ صفر است. پس هیچ‌وقت با == 0 دنبالِ زمینه نگرد؛ آستانه بگذار.

هیچ چیزِ اسرارآمیزی در تصویر نیست. یک جدولِ عدد است، و شبکه‌ای که در ترمِ ۱ ساختی می‌تواند همین را بگیرد — که در فصلِ ۲ می‌بینیم چرا این کارِ درستی نیست.

پس شکلِ کاملِ ورودی N×C×H×W است: batch، کانال، ارتفاع، عرض. این چهار حرف را حفظ کن؛ هر خطای شکلی که در این ترم می‌گیری، با نوشتنِ همین چهارتا حل می‌شود.

۳. نرمال‌سازی#

mean, std = Xtr.mean(), Xtr.std()
normed = (Xtr - mean) / std

print("میانگین کل:", round(float(mean), 4), "| انحراف معیار:", round(float(std), 4))
print("بعد از استانداردسازی -> میانگین:", round(float(normed.mean()), 4), "| انحراف:", round(float(normed.std()), 4))
میانگین کل: 0.2855 | انحراف معیار: 0.3541
بعد از استانداردسازی -> میانگین: -0.0 | انحراف: 1.0

پیکسل‌ها از قبل در بازهٔ ۰ تا ۱ بودند (تقسیم بر ۲۵۵)، ولی میانگینشان ۰٫۲۸ است — چون بیشترِ تصویر زمینهٔ سیاه است. استانداردسازی مرکز را به صفر می‌برد.

⚠️ مواظب باش: میانگین و انحراف را از دادهٔ آموزش بگیر و همان را روی اعتبارسنجی و آزمون هم به‌کار ببر — نه اینکه هر مجموعه آمارِ خودش را داشته باشد. این دقیقاً همان نشتیِ سرنخ ترمِ ۳ فصلِ ۴ است، و در کارِ با تصویر چون آمار «بی‌ضرر» به‌نظر می‌رسد، بیشتر پیش می‌آید.

برای تصویرِ رنگی، آمار را برای هر کانال جدا حساب می‌کنی — چون کانالِ آبی و قرمز توزیعِ متفاوتی دارند. و اگر از یک مدلِ آماده استفاده می‌کنی، باید دقیقاً همان آماری را به‌کار ببری که آن مدل با آن آموزش دیده (فصلِ ۴).

۴. آماده کردن برای یک مدلِ آماده#

gray = Xtr[:2]
rgb = gray.repeat(1, 3, 1, 1)
big = torch.nn.functional.interpolate(rgb, size=(224, 224), mode="bilinear", align_corners=False)

print("خاکستری:", tuple(gray.shape), "-> سه‌کاناله:", tuple(rgb.shape), "-> بزرگ‌شده:", tuple(big.shape))
خاکستری: (2, 1, 28, 28) -> سه‌کاناله: (2, 3, 28, 28) -> بزرگ‌شده: (2, 3, 224, 224)

دو تبدیل، و هر دو در فصلِ ۴ لازم می‌شوند:

  • repeat(1, 3, 1, 1) همان کانالِ خاکستری را سه بار تکرار می‌کند. مدل‌های آمادهٔ بینایی روی تصویرِ رنگی آموزش دیده‌اند و سه کانال می‌خواهند. این کپیِ ساده اطلاعاتِ تازه‌ای اضافه نمی‌کند — فقط شکل را با انتظارِ مدل جور می‌کند.
  • interpolate به ۲۲۴×۲۲۴ چون همان مدل‌ها روی این اندازه آموزش دیده‌اند.

📏 اندازه بگیر: بزرگ کردنِ ۲۸ به ۲۲۴ هیچ جزئیاتی اضافه نمی‌کند — همان اطلاعات را روی شبکهٔ درشت‌تری پخش می‌کند. پس انتظار نداشته باش مدلِ آماده معجزه کند؛ در فصلِ ۴ دقیقاً می‌سنجیم که با این محدودیت چقدر خوب کار می‌کند، و جوابش شاید غافلگیرت کند.

چک کن: بعد از هر تبدیلِ تصویر، شکل را چاپ کن. اگر عددِ دوم ۳ نشد، مدل‌های آماده خطای کانال می‌دهند؛ اگر دو عددِ آخر ۲۲۴ نشد، خطای اندازه. دو ثانیه وقت می‌گیرد و بیشترِ خطاهای این ترم را حذف می‌کند.

۵. جدولِ خطاهای شکل#

پیامِ خطا معنی راهِ حل
expected input[…] to have 3 channels but got 1 تصویرِ خاکستری به مدلِ رنگی repeat(1, 3, 1, 1)
Expected 4-dimensional input بُعدِ batch جا مانده unsqueeze(0)
Given groups=1, weight of size […] تعدادِ کانالِ ورودی با لایه نمی‌خواند in_channels را چک کن
mat1 and mat2 shapes cannot be multiplied بعد از Flatten، اندازه با Linear نمی‌خواند خروجیِ لایهٔ آخرِ کانولوشن را حساب کن (فصلِ ۳)

🔧 اگر کار نکرد: تصویر وارونه یا عجیب نمایش داده می‌شود — احتمالاً H×W×C را به matplotlib نداده‌ای؛ image.permute(1, 2, 0) لازم است. دانلود گیر کرده — سلولِ راه‌اندازی را دوباره اجرا کن؛ فایل‌های ناقص با اجرای دوباره تکمیل می‌شوند. همه‌چیز کند است — این ترم زیرمجموعهٔ ۴۰۰۰تایی می‌گیرد، نه کلِ ۶۰ هزار؛ اگر کدت را عوض کرده‌ای، همان را برگردان.

🤖 از دستیارت بپرس: «چرا PyTorch از C×H×W استفاده می‌کند در حالی که کتابخانه‌های تصویری معمولاً H×W×C دارند؟» جوابش به نحوهٔ چیده شدنِ داده در حافظه و سرعتِ کانولوشن برمی‌گردد — و فهمیدنش کمکت می‌کند یادت بماند کدام کدام است. بعد بپرس permute و reshape چه فرقی دارند؛ این دو را اشتباه گرفتن، تصویرت را بی‌صدا خراب می‌کند.

واژه‌های تازهٔ این فصل#

کلمه تلفظ به حروف فارسی یعنی چه
channel چنل یکی از لایه‌های رنگیِ تصویر
C×H×W ترتیبِ ابعادِ تصویر در PyTorch
interpolation اینترپولیشن تغییرِ اندازهٔ تصویر با محاسبهٔ پیکسل‌های میانی
permute پرمیوت جابه‌جا کردنِ ترتیبِ ابعاد

تمرین‌ها

اول خودت فکر کن یا امتحان کن — بعد اینجا را باز کن.

در فصل بعد#

تصویر را به شکلِ tensor داری. حالا سؤالِ اصلی: چرا لایهٔ Linear که دو ترم به‌کار بردی، برای تصویر ابزارِ اشتباهی است؟ فصلِ بعد جوابش را با شمردنِ پارامترها می‌دهد و بعد convolution را از پایه می‌سازد — با کرنلی که خودت مقدارش را می‌گذاری و می‌بینی دقیقاً چه چیزی پیدا می‌کند.

به آخر این فصل رسیدی!

اگر ساختی و جواب داد، این دکمه مال توست.