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

الوحدة 9 — كلفة الحساب وتحسين الذاكرة

بعد ثمانِ وحدات من التوليد، لاحظنا: SDXL على 8 غيغا VRAM يرمي CUDA out of memory، كلّ صورة تحتاج 12 ثانية على RTX 4070 و2.5 دقيقة على GTX 1660، ومحاولة تشغيل ControlNet + Refiner معًا يُقفل الجهاز. هذه الوحدة تُعطي أدوات ملموسة لجعل Stable Diffusion يعمل على جهازك أيًّا كان، وحسابات دقيقة لتقدير كلفة الإنتاج.

أين تذهب الذاكرة​

VRAM المُستهلَك في توليد SDXL نموذجيّ يتوزّع تقريبًا:

المكوّنfp32fp16
U-Net (2.6B معلمة)10.4 غيغا5.2 غيغا
مرمّزات النصّ (CLIP + OpenCLIP)2.6 غيغا1.3 غيغا
VAE0.7 غيغا0.35 غيغا
Latent + قيم انتباه (1024×1024)4-6 غيغا2-3 غيغا
إجماليّ نموذجيّ~18 غيغا~9 غيغا

الرقم الأخير يُفسّر لماذا SDXL في fp32 لا يعمل على أيّ بطاقة استهلاكيّة، ولماذا fp16 هو الافتراضيّ عمليًّا.

نصف الدقّة (fp16)​

أرخص وأهمّ تحسين. بدل تخزين كلّ وزن في 32 بت (float32)، نخزّنه في 16 بت (float16). النتيجة:

  • نصف الذاكرة.
  • تسريع 30-50% على GPU حديثة (RTX 30xx وأعلى، A100)، بلا فرق ملموس على أقدم.
  • بلا خسارة بصريّة في 99% من الحالات.

في diffusers:

pipe = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
variant="fp16", # يحمّل الوزن المحفوظ أصلًا في fp16
).to("cuda")

variant="fp16" يحمّل ملفّات وزن أصغر ويوفّر ذاكرة النظام أيضًا.

xFormers: انتباه فعّال​

بعض عمليّات U-Net الأكثر استهلاكًا للذاكرة هي «self-attention» و«cross-attention». مكتبة xFormers من Meta تعيد كتابتهما بطريقة أوفر ذاكرة (memory-efficient attention). التوفير: 30-40% إضافيّة على fp16.

pipe.enable_xformers_memory_efficient_attention()

قيود: تحتاج تثبيتًا صحيحًا (pip install xformers بنسخة متوافقة مع PyTorch وCUDA). على PyTorch 2.0+ التطبيق الأصليّ (Scaled Dot-Product Attention) يعطي نفس المكاسب تلقائيًّا، فـxFormers أقلّ ضرورة اليوم.

تقطيع الانتباه (attention slicing)​

بدل حساب الانتباه على كامل المصفوفة دفعة واحدة، نُقطّعها إلى شرائح. توفير ذاكرة كبير، مقابل تباطؤ 10-20%. مفيد على GPU متواضعة:

pipe.enable_attention_slicing()

الجمع بين هذا وfp16 يُنزل SDXL إلى 6 غيغا VRAM بدل 9، مقابل تباطؤ محدود.

VAE tiling​

لتوليد بدقّة عالية (1536×1536 وأعلى)، مرحلة VAE النهائيّة (فكّ latent إلى بكسل) تحتاج ذاكرة مفاجئة (10+ غيغا). VAE tiling يُقطّع هذا إلى مربّعات:

pipe.enable_vae_tiling()

بلا هذا، ستنفجر الذاكرة عند آخر خطوة توليد، بعد أن تكون قد أتمّت 30 خطوة U-Net. مؤلم جدًّا.

تفريغ CPU (CPU offload)​

الحلّ الأقصى لـGPU صغيرة (4-6 غيغا). كلّ مكوّن (مرمّز النصّ، U-Net، VAE) يُنقَل إلى GPU حين يُستعمَل ثمّ يعود إلى RAM:

pipe.enable_model_cpu_offload()

يُنزل الحاجة إلى 4-5 غيغا VRAM لـSDXL، مقابل تباطؤ 3-5 أضعاف بسبب النقل. مقبول للاستكشاف، غير مقبول للإنتاج المستمرّ.

بديل أقصى: pipe.enable_sequential_cpu_offload() ينقل حتّى داخل U-Net، ينزل إلى 2-3 غيغا مقابل تباطؤ ×10.

الوصفة حسب VRAM المتاح​

VRAMاستراتيجيّةزمن تقريبيّ (1024×1024، 30 خطوة)
4 غيغاSD 1.5 + fp16 + attention slicing + CPU offload60-120 ثانية
6 غيغاSDXL + fp16 + attention slicing + VAE tiling25-45 ثانية
8 غيغاSDXL + fp16 + attention slicing15-25 ثانية
12 غيغاSDXL + fp16 (كلّ شيء نشط، ControlNet ممكن)8-15 ثانية
24 غيغاSDXL + fp16 (Refiner + 2× ControlNet + LoRA معًا)6-12 ثانية

قياس الكلفة الاقتصاديّة​

للإنتاج التجاريّ، كلفة الصورة الواحدة تُقاس بوقت GPU:

  • GPU سحابيّ (A100 40GB): حوالي 2 USD/ساعة. صورة SDXL بـ8 ثوانٍ = 0.0044 USD. مئة صورة = 0.44 USD.
  • GPU محلّيّ (RTX 4070، 200 W): 0.2 kWh/ساعة × 0.20 USD/kWh = 0.04 USD/ساعة تشغيل. مئة صورة بـ12 ثانية = 0.013 USD كهرباء (بدون احتساب استهلاك البطاقة).
  • خدمة API (Replicate, Stability API): 0.02-0.05 USD للصورة. بلا صداع تشغيل، لكن أغلى بترتيب من مقدار.

للكتالوج (200-500 صورة/شهر): GPU محلّيّ يستحقّ. للنماذج التجريبيّة القليلة: API يوفّر وقت الإعداد.

الخيط الأحمر: تحسين الأنبوب الإنتاجيّ​

بعد الوحدة 7، أنبوب علامة الأثاث يُنتج صورة كلّ 15 ثانية على GPU 12 غيغا. تحسينات هذه الوحدة تُنزل الوقت إلى 8 ثوانٍ (fp16 + xFormers + torch.compile)، فيصير إنتاج 100 صورة كتالوج في 13 دقيقة بدل 25، وكلفة الكهرباء تحت السنت الواحد.

torch.compile (تسريع إضافيّ)​

PyTorch 2.0+ يوفّر torch.compile() الذي يُترجم النموذج إلى نسخة مُحسَّنة عند أوّل استدعاء:

pipe.unet = torch.compile(pipe.unet, mode="reduce-overhead")

الاستدعاء الأوّل يستغرق دقيقة (تجميع)، الاستدعاءات التالية أسرع بـ20-30%. مثاليّ لخادم إنتاج يبقى مشتغلًا؛ لا يستحقّ لاستدعاء يوميّ واحد.

عدم الاستقرار

xFormers وtorch.compile يُدخلان أحيانًا تباينًا بصريًّا صغيرًا في النتيجة مقابل نفس البذرة، بسبب فروقات دقّة عائمة. للاختبار A/B الصارم للتعليمة، عطّلهما مؤقّتًا لضمان حتميّة كاملة.

الخلاصة​

  • fp16 أرخص وأهمّ تحسين: نصف الذاكرة، بلا فقد بصريّ ملموس.
  • xFormers أو SDPA أصليّ يوفّران 30% إضافيّة على الانتباه.
  • attention slicing وVAE tiling وCPU offload أدوات متدرّجة لآلات محدودة الذاكرة.
  • الكلفة الفعليّة تحت السنت للصورة على GPU سحابيّ، وتحت الفلس على GPU محلّيّ إنتاجيّ.