هذا المقال يتطلب مستوى متوسط. يفترض إنك تعرف أساسيات الشبكات العصبية وتقدر تقرأ كود Python، لكنك ما اشتغلتش قبل كده على النماذج التوليدية.
لو فاهم إزاي نموذج الانتشار بيحوّل ضوضاء عشوائية لصورة، هتقدر تضبط عدد الخطوات وتكسب سرعة 20 إلى 50 ضعف بنفس الجودة تقريبًا. ده الفرق بين صورة في ثانية وصورة في نص دقيقة.
نماذج الانتشار: من الضوضاء إلى الصورة
المشكلة باختصار: منين بتيجي الصورة أصلًا
Midjourney وStable Diffusion وDALL·E كلهم بيشتغلوا بنفس الفكرة الأساسية: نماذج الانتشار (Diffusion Models). السؤال اللي بيحيّر أغلب الناس: النموذج بيرسم الصورة منين؟ الإجابة اللي بتحصل فعلاً إنه مبيرسمش من ورقة بيضا. بيبدأ من ضوضاء عشوائية بالكامل، وبيشيلها على مراحل لحد ما تظهر صورة.
المثال الأول: ثلج التلفزيون القديم
افتكر التلفزيون القديم لما القناة تقطع. الشاشة بتمتلئ "ثلج" أبيض وأسود عشوائي. تخيّل إن فيه حد شاطر بياخد الثلج ده ويبدأ يمسح منه شوية شوية، وكل مسحة بيقرّب الصورة لمنظر حقيقي: سما، جبل، شمس. بعد مية مسحة، الثلج اختفى وطلعت صورة كاملة.
ده بالظبط اللي بيعمله نموذج الانتشار. بيبدأ من "ثلج" (ضوضاء)، وبيتدرّب على إنه يشيل جزء صغير من الضوضاء في كل خطوة. النموذج مش بيرسم، هو بيعمل إزالة ضوضاء (denoising) متكررة.
الشرح العلمي: عمليتان متعاكستان
نموذج الانتشار مبني على عمليتين. الأولى ثابتة ومعروفة، والتانية هي اللي بنتعلمها.
الانتشار الأمامي (Forward): نبدأ من صورة حقيقية x0 ونضيف عليها ضوضاء غاوسية على خطوات صغيرة، من x1 لحد xT (عادة T = 1000). عند آخر خطوة، الصورة بتبقى ضوضاء نقية تقريبًا. العملية دي حتمية الشكل ومفيهاش تعلّم، مجرد إضافة ضوضاء بجدول معروف. ودي سلسلة ماركوف: كل خطوة بتعتمد على اللي قبلها بس.
الانتشار العكسي (Reverse): هنا الشغل الحقيقي. بندرّب شبكة عصبية تتنبأ بالضوضاء اللي اتضافت في كل خطوة، وتشيلها. لو النموذج عرف يشيل الضوضاء بدقة، نقدر نبدأ من ضوضاء عشوائية جديدة وناخد خطوات عكسية لحد ما نوصل لصورة جديدة تمامًا مكانتش موجودة قبل كده.
الافتراض المهم هنا: إن الخطوات صغيرة كفاية لدرجة إن كل خطوة عكسية تقدر تُقرّب بتوزيع غاوسي. ده اللي بيخلي المسألة قابلة للتعلم من الأساس (Ho et al., 2020).
مثال تنفيذي: الانتشار الأمامي والعكسي بالكود
الكود ده بيوضّح الجزء الرياضي بدون أي مكتبات تقيلة. الانتشار الأمامي شغّال بالكامل. العكسي محتاج شبكة مدرّبة تتنبأ بالضوضاء، فسبناها كمدخل.
import numpy as np
T = 1000
betas = np.linspace(1e-4, 0.02, T) # جدول الضوضاء الخطي (Ho et al., 2020)
alphas = 1.0 - betas
alpha_bar = np.cumprod(alphas) # الناتج التراكمي ᾱ_t
def add_noise(x0, t):
"""الانتشار الأمامي: نوصل لأي خطوة t في معادلة واحدة."""
eps = np.random.randn(*x0.shape) # ضوضاء غاوسية قياسية
xt = np.sqrt(alpha_bar[t]) * x0 + np.sqrt(1 - alpha_bar[t]) * eps
return xt, eps
x0 = np.random.rand(64, 64) # صورة مبسّطة 64×64
x_noisy, _ = add_noise(x0, t=900) # قرب النهاية = ضوضاء شبه كاملة
print(round(x_noisy.std(), 2)) # ~1.0: بقى توزيع غاوسي قياسي تقريبًا
def denoise_step(xt, t, eps_theta):
"""خطوة عكسية واحدة من x_t إلى x_{t-1}. eps_theta = تنبؤ الشبكة بالضوضاء."""
a, ab = alphas[t], alpha_bar[t]
mean = (xt - (1 - a) / np.sqrt(1 - ab) * eps_theta) / np.sqrt(a)
z = np.random.randn(*xt.shape) if t > 0 else 0
return mean + np.sqrt(betas[t]) * z