انتقل إلى المحتوى الرئيسي

الوحدة 6 — نماذج الانتشار: التشويش ثمّ تعلّم إزالته

في 2020 أظهرت ورقة DDPM لـHo وJain وAbbeel أنّ فكرة قديمة نسبيًّا (منذ 2015 مع Sohl-Dickstein) يمكن أن تُنافس GAN على جودة الصور. ثمّ في 2022 أنتجت Stable Diffusion وDALL-E 2 وImagen صورًا مذهلة من جمل نصّيّة، وأعادت رسم المشهد. المفاجأة أنّ فكرة النموذج بسيطة عجيبة: نشوّش صورةً تدريجيًّا حتّى نحوّلها إلى ضجيج خالص، ثمّ نعلّم شبكة أن تعكس هذه العمليّة.

الفكرة: مسار أمامي معلوم ومسار خلفي متعلَّم

في الطرف الأمامي، عمليّة بسيطة بلا تعلّم: نأخذ صورة x0x_0 حقيقيّة، ونضيف إليها ضجيجًا طبيعيًّا بجرعات صغيرة في كلّ خطوة، على مدى TT خطوة (عادةً T=1000T = 1000). في نهاية المسار، xTx_T لا يمكن تمييزها عن ضجيج طبيعيّ محض.

q(xtxt1)=N ⁣(xt;1βtxt1,βtI)q(x_t \mid x_{t-1}) = \mathcal{N}\!\left(x_t; \sqrt{1 - \beta_t}\, x_{t-1}, \beta_t I\right)

الخصيصة الجميلة التي تُبرّر كلّ الرياضيّات التالية: يمكن أخذ عيّنة مباشرة من xtx_t بمعلومية x0x_0 عبر صيغة مغلقة (بفضل تركيب توزيعات طبيعيّة):

xt=αˉtx0+1αˉtϵ,ϵN(0,I)x_t = \sqrt{\bar\alpha_t}\, x_0 + \sqrt{1 - \bar\alpha_t}\, \epsilon, \qquad \epsilon \sim \mathcal{N}(0, I)

حيث αˉt=s=1t(1βs)\bar\alpha_t = \prod_{s=1}^{t}(1 - \beta_s). لسنا مضطرّين لتشغيل المسار خطوةً خطوة أثناء التدريب.

في الطرف الخلفي، الشبكة ϵθ(xt,t)\epsilon_{\theta}(x_t, t) تُدرَّب لتُنبِّئ الضجيج المضاف بمعلومية الصورة المشوَّشة xtx_t والخطوة الزمنيّة tt. الخسارة أبسط ما يمكن تخيّله:

L=Ex0,ϵ,t[ϵϵθ(xt,t)2]\mathcal{L} = \mathbb{E}_{x_0, \epsilon, t}\left[\|\epsilon - \epsilon_{\theta}(x_t, t)\|^2\right]

هذا هو DDPM كلّه: خطأ تربيعيّ على الضجيج المتوقّع. مقارنة بلعبة GAN المعقّدة، البساطة صادمة.

حلقة التدريب في PyTorch

import torch

T = 1000
betas = torch.linspace(1e-4, 0.02, T) # جدول $\beta_t$ الخطّي
alphas = 1.0 - betas
alphas_cum = torch.cumprod(alphas, dim=0) # $\bar\alpha_t$

def entrainement_pas(unet, x_0, optimiseur):
B = x_0.size(0)
t = torch.randint(0, T, (B,)) # خطوة زمنيّة عشوائيّة لكلّ صورة
epsilon = torch.randn_like(x_0)
a_bar_t = alphas_cum[t].view(-1, 1, 1, 1)
x_t = torch.sqrt(a_bar_t) * x_0 + torch.sqrt(1 - a_bar_t) * epsilon

epsilon_pred = unet(x_t, t)
perte = torch.mean((epsilon - epsilon_pred) ** 2)

optimiseur.zero_grad()
perte.backward()
optimiseur.step()
return perte.item()

ثلاث ملاحظات جوهرية. الأولى: كلّ صورة في الدفعة تُشوَّش بمعلوم مختلف tt، فتتعلّم الشبكة إزالة التشويش في كلّ المستويات. الثانية: الشبكة تعرف tt لأنّها تُحقَن كتضمين إلى U-Net (كما نُدخل موضع الرمز إلى المحوّل). الثالث: لا يوجد مميّز، ولا لعبة، ولا انهيار أنماط. التدريب مستقرّ بشكل مذهل.

بنية الشبكة: U-Net مشروط بالزمن

الشبكة القياسية هي U-Net: بنية قوس نزول-صعود مع اتّصالات جانبيّة بين طبقات النزول ومطابقاتها في الصعود. النزول يلتقط الأنماط الكبيرة، والصعود يعيد بناء التفاصيل، والاتّصالات الجانبيّة تحمل المعلومة الدقيقة.

الخطوة الزمنيّة tt تُدخَل عبر تضمين جيبيّ (على غرار المحوّل)، ثمّ يُضخّ إلى كلّ كتلة U-Net عبر جمع أو عبر AdaIN. هذا التكييف حاسم: بدونه، الشبكة لا تعرف كم من الضجيج عليها إزالته، وتفشل تمامًا.

في نماذج حديثة (Stable Diffusion) نضيف كذلك طبقات انتباه ذاتيّ داخل U-Net، لكي تلتقط الشبكة اعتماديّات بعيدة داخل الصورة (كأنّ عين في يسار الصورة تُطابق عينًا في يمينها). وسنضيف الانتباه المتقاطع مع النصّ في الوحدة التالية.

أخذ العيّنة: DDPM بطيء لكنّه دقيق

لتوليد صورة جديدة، نبدأ من xTN(0,I)x_T \sim \mathcal{N}(0, I) ونطبّق TT خطوة عكسيّة:

xt1=1αt(xtβt1αˉtϵθ(xt,t))+σtzx_{t-1} = \frac{1}{\sqrt{\alpha_t}}\left(x_t - \frac{\beta_t}{\sqrt{1-\bar\alpha_t}}\, \epsilon_{\theta}(x_t, t)\right) + \sigma_t z

مع zN(0,I)z \sim \mathcal{N}(0, I) (أو صفر في آخر خطوة). العمليّة تتطلّب ألف نداء على U-Net لصورة واحدة. هذا بطء حقيقيّ: ما يستغرقه GAN مللي ثواني يستغرقه DDPM دقائق أو ثوانٍ عديدة على بطاقة رسوميّات جيّدة.

DDIM: التسريع دون إعادة تدريب

DDIM (Denoising Diffusion Implicit Models) لـSong وMeng وErmon (2020) لاحظت أنّ الشبكة نفسها المُدرَّبة على DDPM يمكن استعمالها بمسار أخذ عيّنة أقصر بكثير، وحاسم منطقيًّا. الفكرة: بدل عكس الخطوات واحدة واحدة، نقفز على شبكة فرعيّة (مثلًا كلّ عشرين خطوة)، ونستعمل تحديثًا حتميًّا يقارب المسار الأصليّ.

def echantillon_ddim(unet, forme, T=1000, pas=50):
x = torch.randn(forme)
indices = torch.linspace(T - 1, 0, pas).long()
for i in range(len(indices) - 1):
t, t_prev = indices[i], indices[i + 1]
epsilon_pred = unet(x, t.unsqueeze(0).expand(x.size(0)))
a_bar, a_bar_prev = alphas_cum[t], alphas_cum[t_prev]
x_0_pred = (x - torch.sqrt(1 - a_bar) * epsilon_pred) / torch.sqrt(a_bar)
x = torch.sqrt(a_bar_prev) * x_0_pred + torch.sqrt(1 - a_bar_prev) * epsilon_pred
return x

مع 50 خطوة بدل 1000، الجودة تبقى مقارنة تقريبًا، والزمن ينخفض بمعامل 20. هذه هي الحلقة العمليّة الافتراضية اليوم، ومن ورائها ظهرت مُخطِّطات أفضل كـDPM-Solver الذي يعطي جودة تكاد تكون كاملة في 15 إلى 25 خطوة فقط.

الانتشار الكامن: Stable Diffusion

تطبيق الانتشار على صورة 512 في 512 مباشرةً مكلف جدًّا: كلّ خطوة تعمل على تنسور بأبعاد كاملة. الفكرة العبقريّة لـRombach وآخرون (2022) في Stable Diffusion كانت في نقل الانتشار إلى فضاء كامن مضغوط:

  • مرمّز تلقائي مُدرَّب مسبقًا يضغط الصورة من 512 في 512 في 3 قنوات إلى تمثيل كامن 64 في 64 في 4 قنوات (تخفيض ب64 في الحجم).
  • U-Net الانتشار يعمل على هذا التمثيل الكامن، لا على البكسلات.
  • عند الانتهاء من إزالة التشويش، فكّ الترميز يُعيد الصورة إلى مساحة البكسل.

هذا الخفض بمعامل 64 يجعل التدريب والاستدلال ممكنين على بطاقة رسوميّات استهلاكيّة. وهو ما يفسّر انتشار Stable Diffusion الواسع مقارنة بـImagen (من Google) الذي يعمل على البكسلات مباشرة ويحتاج بنية تحتيّة أكبر.

جدول الضجيج ليس تفصيلًا

اختيار جدول βt\beta_t يبدو مسألة صغيرة لكنّه يُبدّل النتائج بشكل كبير. الجدول الخطّي الأصليّ لـDDPM يُنتج انتقالًا سريعًا جدًّا إلى الضجيج على صور صغيرة، ما يجعل الخطوات الوسيطة قليلة الفائدة. الجدول الجيب تمامي لـNichol وDhariwal (2021) يُوزّع الجرعات بحيث لا تُتلَف بنية الصورة قبل الخطوة t=T/2t = T/2، ويعطي عيّنات أفضل بوضوح. اعتماد الجدول الجيب تمامي هو تحسين مجّاني ينبغي فعله من البداية.

نماذج الانتشار مقابل GAN

الجانبGANنماذج الانتشار
استقرار التدريبهشّممتاز
التنوّعمحدود، انهيارممتاز، يغطّي التوزيع
جودة الصورةممتازةممتازة، الأفضل حاليًّا
سرعة أخذ العيّنةمللي ثوانيثوانٍ عديدة
قابليّة التكييفصعبةطبيعيّة عبر الانتباه المتقاطع

النقطة الأخيرة هي ما تفتح الوحدة التالية: كيف نُخبر النموذج ماذا يولّد، عبر النصّ.

في الخلاصة

  • نموذج الانتشار يتعلّم إزالة الضجيج خطوة خطوة؛ خسارته تربيعيّة على الضجيج المتوقّع، والتدريب مستقرّ بشكل مذهل.
  • U-Net مع تضمين للخطوة الزمنيّة هي البنية القياسية؛ الاتّصالات الجانبيّة تحفظ التفاصيل، والانتباه الذاتيّ يلتقط الاعتماديّات البعيدة.
  • DDPM بطيء (ألف نداء)، وDDIM يقفز على شبكة فرعيّة (خمسين خطوة) بجودة مقاربة دون إعادة تدريب.
  • الانتشار الكامن (Stable Diffusion) يضغط الصورة إلى فضاء صغير قبل الانتشار، فيقسّم التكلفة بمعامل 64 ويجعل التدريب ممكنًا محلّيًّا.

الوحدة التالية تُضيف القطعة التي حوّلت الانتشار إلى ظاهرة عامّة: التكييف بالنصّ، الذي يجعل «شمس تغرب على الصحراء» تتحوّل إلى صورة.