الصورة كموتر
درس 1 من 7
1الصورة كموتر
الصورة الكبيرةالصورة بالنسبة للنموذج ليست صورة، بل ثلاث مصفوفات أرقام فوق بعضها: أحمر وأخضر وأزرق. قبل أي شبكة، يجب أن تعرف ترتيب أبعادها، ومدى قيمها، وكيف تطبّعها، لأن خطأً صغيرًا هنا يجعل أفضل نموذج في العالم يرى ضجيجًا.
ماذا تشاهد في الرسم: الصورة تمرّ بأربع محطات: تُقرأ بالقنوات في الآخر، ثم تُقصّ إلى 224، ثم يقسمها ToTensor على 255 ويعيد ترتيبها إلى (C, H, W)، ثم تُطبَّع بأرقام ImageNet. المحطة المميّزة هي التطبيع، لأن خطأها لا يرفع أي رسالة.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
الصورة الرقمية شبكة مربعات صغيرة، وكل مربع ثلاثة أرقام: كم فيه من الأحمر والأخضر والأزرق. لكي يفهمها النموذج، نحولها إلى علبة أرقام بثلاث طبقات، ونصغّر الأرقام لتكون بين صفر وواحد تقريبًا، حتى لا يطغى رقم على غيره.
الصورة موتر بشكل (C, H, W) في PyTorch، وC = 3 للألوان، وقيم البكسل 0..255 تُقسم على 255 ثم تُطبَّع بمتوسط وانحراف كل قناة. الدفعة تضيف بعدًا رابعًا (N, C, H, W)، وانتبه لترتيب HWC في مكتبات مثل PIL.
قبل أن تبدأ
🧊الموتر
تقرأ الشكل كجملة وتعرف الفرق بين view و permute من مسار التعلّم العميق.
📊المصفوفات مع NumPy
تعرف المتوسط والانحراف عبر محور معيّن، مثل axis=(0, 2, 3) في هذا الدرس.
الفكرة الجوهرية
الصورة عند النموذج أرقام فقط. في هذا الدرس ترى هذه الأرقام قناةً قناة، ثم ترتّب أبعادها كما يريد PyTorch، ثم تطبّعها، ثم تجمع كل ذلك في خط معالجة واحد.
1القنوات: ثلاث شبكات أرقام
كل بكسل في صورة ملوّنة ثلاثة أرقام من 0 إلى 255: أحمر وأخضر وأزرق. كل لون شبكة بحجم الصورة، وتسمّى قناة.
انظر إلى الرسم: الصورة ثلاث طبقات فوق بعضها. الصورة الرمادية طبقة واحدة، وبعض الصور فيها قناة رابعة للشفافية يجب حذفها قبل النموذج.
scikit-learn يأتي بصور أرقام مكتوبة بخط اليد، 8 في 8 بكسل بقيم من 0 إلى 16. ارسمها بالحروف لترى أن الرقم مجرد شكل في مصفوفة.
from sklearn.datasets import load_digits
digits = load_digits()
img = digits.images[0]
print("label:", digits.target[0], "shape:", img.shape)
for row in img.astype(int):
print("".join(" .:-=+*#%@"[min(v * 10 // 17, 9)] for v in row))
هذا صفر. النموذج سيرى نفس المصفوفة بالضبط، 64 رقمًا، ولا شيء آخر.
BGR لا RGB، فيرى النموذج السماء برتقالية والوجوه زرقاء، وتنخفض دقته دون أي رسالة خطأ.2ترتيب الأبعاد: (C, H, W)
مكتبات الصور تعطيك الشكل (H, W, C)، أي القنوات في الآخر. أما PyTorch فيريد القنوات أولًا: (C, H, W).
انظر إلى الرسم: نفس الأبعاد الثلاثة بترتيب جديد. الأرقام نفسها، والذي تغيّر هو من يأتي أولًا.
import numpy as np
image = np.zeros((4, 6, 3), dtype=np.uint8)
image[:, :3] = [200, 30, 30]
image[:, 3:] = [30, 30, 200]
print("shape (H, W, C):", image.shape, image.dtype)
print("top-left pixel:", image[0, 0])
print("red channel row 0:", image[0, :, 0])
chw = image.transpose(2, 0, 1)
print("shape (C, H, W):", chw.shape)
النصف الأيسر أحمر [200, 30, 30] والأيمن أزرق. المكتبات التي تقرأ الصور (Pillow وOpenCV وmatplotlib) تعطيك الترتيب (H, W, C)، أي القنوات في الآخر، بينما PyTorch يتوقّع (C, H, W). transpose(2, 0, 1) هو الجسر بينهما، وستكتبه أو تكتب ما يعادله في كل مشروع رؤية.
عند التدريب يأتي بُعد رابع في المقدّمة هو عدد الصور، فيصبح الشكل (N, C, H, W). اطبع الشكل دائمًا بعد تحميل أول صورة.
3التطبيع لكل قناة
الشبكات تتعلّم أسرع وأثبت حين تكون المدخلات قرب الصفر وانتشارها قرب الواحد. لذلك نطبّع على خطوتين.
انظر إلى الرسم: نقسم على 255 فتصبح القيم بين 0 و1، ثم نطرح متوسط كل قناة ونقسم على انحرافها.
دفعة من 16 صورة عشوائية بحجم 32 في 32. axis=(0, 2, 3) يعني: احسب عبر الصور والارتفاع والعرض، وأبقِ القنوات منفصلة.
import numpy as np
rng = np.random.default_rng(0)
batch = rng.integers(0, 256, size=(16, 3, 32, 32)).astype(np.float32)
scaled = batch / 255.0
mean = scaled.mean(axis=(0, 2, 3), keepdims=True)
std = scaled.std(axis=(0, 2, 3), keepdims=True)
normalised = (scaled - mean) / std
print("raw range:", batch.min(), batch.max())
print("scaled range:", scaled.min(), round(float(scaled.max()), 3))
print("per-channel mean after:", normalised.mean(axis=(0, 2, 3)).round(3) + 0.0)
print("per-channel std after: ", normalised.std(axis=(0, 2, 3)).round(3))
بعد التطبيع، متوسط كل قناة صفر وانحرافها واحد. هذا بالضبط ما يفعله transforms.Normalize في torchvision، مع فرق أنه يأخذ المتوسط والانحراف جاهزين كأرقام بدل حسابهما من الدفعة.
4أرقام ImageNet وخط المعالجة الكامل
مع نموذج مدرّب مسبقًا لا تحسب المتوسط والانحراف من بياناتك. استخدم أرقام بياناته الأصلية بالضبط: mean=[0.485, 0.456, 0.406] و std=[0.229, 0.224, 0.225] لنماذج ImageNet.
النماذج تتوقّع حجمًا ثابتًا، غالبًا 224 في 224. فنغيّر الحجم ونقصّ أولًا، ثم نطبّع.
هذا ما ستكتبه في مشروع حقيقي. يحتاج torchvision وصورة على جهازك، فهو للقراءة هنا.
from PIL import Image
from torchvision import transforms
preprocess = 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]),
])
image = Image.open("cat.jpg").convert("RGB")
x = preprocess(image).unsqueeze(0)
print(x.shape) # torch.Size([1, 3, 224, 224])
convert("RGB") يحذف قناة الشفافية ويحوّل الرمادي إلى ثلاث قنوات. ToTensor يقسم على 255 ويحوّل (H, W, C) إلى (C, H, W) في خطوة واحدة. وunsqueeze(0) يضيف بعد الدفعة، لأن النموذج يتوقّع دفعة حتى لو كانت صورة واحدة.
كيف يعمل، خطوة بخطوة: كيف تتحوّل صورة إلى مدخل لنموذج
افتح الصورة بـ Pillow مع convert("RGB")، فتُحذف قناة الشفافية ويتحوّل الرمادي إلى ثلاث قنوات.
غيّر حجمها إلى 256 ثم قصّ المركز إلى 224، الحجم الذي يتوقّعه النموذج.
ToTensor يقسم على 255 ويحوّل (H, W, C) إلى (C, H, W) في خطوة واحدة.
Normalize يطرح متوسط كل قناة ويقسم على انحرافها، ثم unsqueeze(0) يضيف بُعد الدفعة.
مثال محلول
كل بكسل في صورة ملوّنة ثلاثة أرقام من 0 إلى 255. صورة 224 في 224 تعني 150528 رقمًا. ابدأ بصورة صغيرة جدًّا تصنعها بنفسك حتى ترى كل رقم.
x.min() وx.max() وx.mean() لأول دفعة دائمًا.
جرّب بلا كود
خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| كل المكتبات تقرأ الألوان بنفس الترتيب. | OpenCV يقرأ القنوات بترتيب BGR لا RGB، فيرى النموذج سماءً برتقالية وتنخفض دقته بلا رسالة خطأ. |
| لتحويل (480, 640, 3) إلى (3, 480, 640) يكفي view. | view يغيّر الشكل دون أن ينقل البيانات فيخلط البكسلات. إعادة ترتيب الأبعاد تحتاج permute أو ToTensor. |
| مع بياناتي الخاصة أحسب متوسطًا وانحرافًا جديدين دائمًا. | مع نموذج مدرّب مسبقًا ابدأ بأرقام بياناته الأصلية، لأن طبقاته الأولى تعلّمت على مدخلات طُبّعت بها. |
جرّب بنفسك
قرأت صورة فكان شكلها (480, 640, 3). ماذا تفعل قبل إعطائها لنموذج PyTorch؟
القنوات في الآخر فتحتاج إعادة ترتيب بـpermute أو ToTensor، لا view الذي يخلط البكسلات. ثم الحجم والتطبيع اللذان دُرّب عليهما النموذج، ثم بعد الدفعة.
تستخدم نموذجًا مدرّبًا على ImageNet. أي أرقام تطبيع تستخدم لصورك الطبية؟
الطبقات الأولى في النموذج تعلّمت أوزانها على مدخلات مطبّعة بأرقام ImageNet، فتغييرها يغيّر ما «تراه» تلك الطبقات. عمليًا يعمل الخياران غالبًا عند ضبط كل النموذج، لكن البداية الآمنة هي الأرقام الأصلية.
بطاقات مراجعة سريعة
(N, C, H, W): عدد الصور، ثم القنوات، ثم الارتفاع، ثم العرض. المكتبات الأخرى تضع القنوات في الآخر، فتحتاج تحويلًا.تحقق من فهمك
عندك صور رمادية بقناة واحدة ونموذج مدرّب مسبقًا يتوقّع ثلاث قنوات. ما الحل البسيط؟
كرّر القناة الوحيدة ثلاث مرات، بـconvert("RGB") في Pillow أو x.repeat(3, 1, 1) على الموتر. الصورة تبقى رمادية في الشكل، لكن الشكل صار (3, H, W) كما يتوقّع النموذج، وكل قناة تُطبّع بأرقامها. البديل تعديل الطبقة الأولى لتقبل قناة واحدة، وهو أعقد ويفقد جزءًا من الأوزان المدرّبة.
صورة ملوّنة 224 في 224. كم رقمًا يراه النموذج؟
224 × 224 × 3 = 150528 رقمًا، ثلاثة لكل بكسل: أحمر وأخضر وأزرق.
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
توثيق رسمي2
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.