"CUDA out of memory": لماذا يحدث، وكيف تُشغّل نموذجاً أكبر من كرتك

الأسباب الخمسة الحقيقية لخطأ نفاد ذاكرة الـGPU، والحلول بالترتيب من المجاني إلى الملاذ الأخير، ومتى تحتاج ببساطة إلى كرت أكبر.

من فريق benchr · · عرض سجل التغييرات

الأسباب المعتادة 5 الأوزان، الـKV cache، الدفعة، التجزّؤ، بلا تكميم
مثال على الـKV cache ~16GB Llama-3-8B، سياق 8K، دفعة 16 — فوق الأوزان
يوفّره التكميم 50–75٪ أوزان FP16 نزولاً إلى 4-bit
أول أمر nvidia-smi شاهد ما يستهلك الكرت فعلاً

حاولت تحميل نموذج أو إقامة خادم، فمات التشغيل على جدار من النص الأحمر ينتهي بـ torch.cuda.OutOfMemoryError: CUDA out of memory. هو أكثر عطل يصادفه الناس حين ينتقلون من API إلى تشغيل الأوزان بأنفسهم، والرسالة أصدق مما تبدو. الـGPU طلب ذاكرة لم تكن لديه. السؤال المفيد ليس هل نفدت منك الذاكرة، فقد نفدت فعلاً. السؤال هو أيّ جزء من العبء التهمها، لأن الحل يعتمد على ذلك كلياً.

قبل أن تغيّر أي شيء، شغّل nvidia-smi. يُظهر إجمالي الـVRAM، وما المستخدَم الآن، وأي العمليات تحتجزه. هذا الأمر وحده يخبرك إن كانت مهمة أخرى جاثمة على الكرت، وإن كنت متجاوزاً قليلاً أم بإفراط، وإن كان الرقم يعقل أصلاً للنموذج الذي تحمّله. كل ما يلي يفترض أنك نظرت.

الأشياء الخمسة التي تلتهم الـVRAM

ذاكرة الـGPU أثناء الاستدلال تذهب إلى ثلاثة دلاء: أوزان النموذج، والـKV cache الذي يحمل حالة الانتباه لكل رمز قيد المعالجة، والتنشيطات للتمريرة الأمامية الحالية. خطأ نفاد الذاكرة هو نمو أحد هذه الثلاثة فوق ما يحمله الكرت. وإليك كيف ينقسم ذلك عملياً، مع العَرَض الذي يشير إلى كل سبب والحل الذي يستهدفه فعلاً.

الأسباب الخمسة لخطأ نفاد ذاكرة CUDA، والعَرَض الذي يدلّ على كل سبب، والـflag الذي يُصلحه. الـflags المعروضة من vLLM
السببالعَرَضالحلالـflag الدقيق
الأوزان تتجاوز الـVRAMنفاد ذاكرة لحظة تحميل النموذج، قبل أي طلبكمِّم الأوزان--quantization awq
الـKV cache أكبر من اللازم (سياق طويل)يُحمَّل بسلاسة ثم ينفد عند أول أمر طويل أو تحت الحملحُدّ طول السياق--max-model-len 4096
حجم الدفعة كبير جداًنفاد ذاكرة فقط حين تعمل عدة طلبات معاًقلّل التزامن--max-num-seqs 16
تجزّؤ الذاكرةنفاد ذاكرة رغم أن nvidia-smi يُظهر ذاكرة فارغةعطِّل CUDA graphs--enforce-eager
بلا تكميمنموذج كان يُفترض أن يتّسع يعمل بدقة FP16/FP32حمِّل بناءً بتكميم 4-bit/8-bit--quantization awq

خذ الأول حرفياً. نموذج 70B بدقة FP16 يحتاج نحو 140GB من الـVRAM للأوزان وحدها: بايتان لكل معامل، و70 ملياراً منها. لا كرت استهلاكي واحد، ولا كرت مركز بيانات واحد بسعة 80GB، يحمل ذلك. ونسخة شائعة من هذا الفخّ أدقّ: قصدت تحميل بناء بتكميم 4-bit فحمّلت بيئة التشغيل أوزان BF16 الكاملة بدلاً منه، فنموذج توقّعت أن يتّسع عند 40GB يحاول حجز 140GB ويموت عند التحميل. إن حدث نفاد الذاكرة قبل أن ترسل طلباً واحداً، فالسبب الأوزان، والتكميم هو الجواب.

الـKV cache هو الجزء الذي يفوت الناس

السبب الثاني هو ما يوقع الحذرين، لأن النموذج يُحمَّل بنظافة ثم يسقط لاحقاً. الجاني هو الـKV cache. خادم مثل vLLM يحجز الـKV cache مسبقاً لأسوأ حالة أُخبر بتوقّعها: max_model_len مضروباً في أقصى دفعة قد يخدمها. ذلك الحجز قد يضاهي الأوزان نفسها.

الأرقام الملموسة تجعله حقيقياً. Llama-3-8B بدقة FP16 نحو 16GB من الأوزان. اخدِمه بسياق 8K ودفعة 16، فإن الـKV cache لتلك الحالة الأسوأ يصل إلى نحو 16GB وحده — فيحتاج الخادم نحو 32GB قبل أن يجيب أي شيء، على عبء أوزانه نصف ذلك فقط. على كرت بسعة 24GB يُحمَّل ثم يموت لحظة وصول حركة حقيقية. لهذا "يعمل النموذج نفسه على حاسوبي المحمول" ثم ينفد في الإنتاج: الدفعة والسياق أكبر في الإنتاج.

~16GB الـKV cache لـ Llama-3-8B عند سياق 8K ودفعة 16 — يساوي الأوزان تقريباً، ومحجوز فوقها

الحل الذي يستهدف هذا مباشرةً هو --max-model-len. اضبطه على ما تخدمه فعلاً — --max-model-len 4096 إن لم تتجاوز أوامرك 4K — فيتقلّص الحجز بالتناسب. وهذا يهم لسبب يعثر فيه الجميع تقريباً: التكميم يقلّص الأوزان لكنه لا يفعل شيئاً للـKV cache. إن كان نفاد ذاكرتك آتياً من الـKV cache، فبإمكانك أن تُكمّم طوال اليوم وتظل تنفد. تقليص السياق هو الحركة الأنجع. وعلى كروت من فئة Hopper تستطيع أيضاً تخزين الـcache نفسه بدقة FP8 بـ --kv-cache-dtype fp8، ما يقصّ ذاكرة الـKV بنحو 40-50٪ بكلفة جودة ضئيلة، كما توثّق مقالات الـKV cache في vLLM.

الحلول، بالترتيب من المجاني إلى الملاذ الأخير

لا تمدّ يدك إلى المطرقة الكبيرة أولاً. اعمل بهذه القائمة وتوقّف عند أول خطوة تُوسِّع النموذج على كرتك. كل خطوة هنا لا تكلّف إلا تغيير إعداد أو ملف نموذج مختلف — والشيء الوحيد الذي تنفقه قليلٌ من السرعة.

1. كمِّم الأوزان

--quantization awq أو بناء GGUF بتكميم Q4. يقصّ ذاكرة الأوزان 50-75٪.

2. حُدّ السياق

--max-model-len 4096. يهاجم الـKV cache مباشرةً — عادةً المكسب الأكبر.

3. قلّل التزامن

--max-num-seqs 16. تسلسلات متزامنة أقل، تنشيطات وcache أصغر.

4. حرّر التجزّؤ

--enforce-eager يُسقط CUDA graphs، يحرّر ~1.5-2GB، ينهي نفاد الذاكرة من التجزّؤ.

5. احجز هامشاً، ثم فرِّغ

--gpu-memory-utilization 0.92، ثم --cpu-offload-gb 4 كملاذ أخير بطيء.

كمِّم أولاً. تحميل أوزان AWQ أو GPTQ بدقة 4-bit، أو بناء GGUF بتكميم Q4، يقصّ ذاكرة الأوزان بنسبة 50-75٪ مقابل FP16 بهبوط جودة لا تلحظه معظم أعباء العمل. في vLLM يكون ذلك --quantization awq موجَّهاً إلى نقطة فحص مُكمَّمة مسبقاً؛ ومع llama.cpp يكفي تنزيل ملف Q4 بدل الكامل. وإن كان النموذج أكبر بقليل، فهذا وحده يُصلحه عادةً. ونموذج أصغر لكنه جيد كثيراً ما يكون الجواب الأنظف من مصارعة كبير. تلك هي الحجة التي يبنيها مقال النماذج اللغوية الصغيرة بالتفصيل.

ثم قلّص السياق. إن كان النموذج يُحمَّل ثم ينفد لاحقاً، فهذه رافعتك، لا التكميم. --max-model-len 4096 يحجم حجز الـKV على سياق ستستخدمه فعلاً. اقرنه بـ --kv-cache-dtype fp8 على كرت Hopper لتوفير 40-50٪ أخرى من الـcache.

ثم قلّل التزامن. --max-num-seqs 16 يحدّ كم تسلسلاً يعمل دفعةً واحدة. التنشيطات والـKV كلاهما يتمدّد مع الدفعة، فقيمة افتراضية عالية على كرت صغير سبب شائع وصامت لنفاد الذاكرة تحت الحمل.

ثم عالِج التجزّؤ. إن أظهر nvidia-smi ذاكرة فارغة وظل ينفد منك، فالمساحة الفارغة غير متّصلة. التقاط CUDA graph هو السبب المعتاد، و--enforce-eager يعطّله، فيحرّر نحو 1.5-2GB ويزيل التجزّؤ. وضبط PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True في البيئة يساعد PyTorch على إعادة استخدام الكتل المجزّأة أيضاً. وضع eager أبطأ قليلاً لكل رمز، وتلك هي المقايضة.

ثم احجز هامشاً. vLLM يحجز 90٪ من الـVRAM افتراضياً. على كرت يقود أيضاً شاشة أو عملية أخرى، هذا يتجاوز الحدّ. --gpu-memory-utilization 0.92 يضبط الحصة — خفّضها إن احتاج شيء آخر الكرت، وارفعها بحذر إن كان الـGPU مخصّصاً.

والتفريغ ملاذٌ أخير فقط. --cpu-offload-gb 4 يسكب ذلك العدد من الغيغابايتات من الأوزان إلى ذاكرة النظام كي يعمل نموذج أكبر بقليل. ينجح، لكن كل طبقة مُفرَّغة تعبر ناقل PCIe عند كل رمز، فتهبط الإنتاجية بقوة. استخدمه لتفكّ عالقك، لا كحالة دائمة.

لما تحتاج GPU أكبر

أحياناً يكون النموذج ببساطة أكبر من أي كرت تملكه، ولا قدر من الضبط يسدّ الفجوة. نموذج 70B بتكميم 4-bit ما زال يريد نحو 40GB للأوزان زائد متّسع للـcache؛ ولن يتّسع ذلك على كرت بسعة 24GB مهما قصّرت السياق. عند تلك النقطة غادرت عالم حلول الإعدادات. والخيار الصادق بين شراء كرت أكبر واستئجار واحد.

لمهمة عابرة — ضبط دقيق، أو تشغيل دفعي، أو أسبوع تقييم — يفوز الاستئجار بالحساب. كرت A100 بسعة 80GB بنحو 1.39 دولار للساعة وH100 بنحو 2.89 دولار، وكرت بسعة 80GB يحمل نموذج 70B بتكميم 4-bit مع متّسع للـKV cache. قارن ذلك بآلاف الدولارات لعتاد ستستخدمه بين الحين والآخر. وإن كنت ستشغّل استدلالاً محلياً ثقيلاً يومياً وبلا نهاية، فإن امتلاك الكرت يغيّر المعادلة — ودليل تشغيل النماذج على جهازك يعمل على أين تقع نقطة التعادل تلك. ولاختيار نموذج بحجم الكرت الذي لديك، يسرد فهرس النماذج نوافذ السياق وأعداد المعاملات جنباً إلى جنب.

النقطة الأوسع: خطأ نفاد ذاكرة CUDA مشكلة تحجيم، لا طريق مسدود. اقرأ nvidia-smi لترى أي دلو فاض، كمِّم وقلّص السياق لتستعيد الغيغابايتات السهلة، حرّر التجزّؤ بوضع eager، ولا تستأجر كرتاً أكبر إلا حين لا يتّسع النموذج فعلاً على أي شيء تملكه. ومعظم الوقت لن تصل إلى تلك الخطوة الأخيرة.

أسئلة شائعة

كيف أُصلح خطأ CUDA out of memory في vLLM؟

اعمل بالقائمة بالترتيب. كمِّم الأوزان (--quantization awq، أو حمِّل بناء GGUF بتكميم Q4) لتقليص ذاكرة الأوزان بنسبة 50-75٪. حُدّ السياق بـ --max-model-len 4096 لتقليص الـKV cache، وهو غالباً المكسب الأكبر. قلّل التزامن بـ --max-num-seqs 16. أضف --enforce-eager لتحرير ذاكرة CUDA graph وإيقاف التجزّؤ. احجز هامشاً بـ --gpu-memory-utilization 0.92. وبعد كل ذلك فقط، فرِّغ إلى الذاكرة بـ --cpu-offload-gb 4 أو استأجر كرتاً أكبر.

هل يُصلح التكميم خطأ CUDA out of memory؟

جزئياً. يقلّص التكميم أوزان النموذج، غالباً بنسبة 50-75٪ بالانتقال من FP16 إلى 4-bit، فيساعد كثيراً حين تكون الأوزان هي ما يفيض عن كرتك. لكنه لا يقلّص الـKV cache، الذي يتمدّد مع طول السياق وحجم الدفعة. إن كان نفاد الذاكرة آتياً من max_model_len طويل، فإن تقليل --max-model-len أنجع من التكميم.

لماذا يظهر لي CUDA out of memory بينما nvidia-smi يُظهر ذاكرة فارغة؟

هذا تجزّؤ في الذاكرة دائماً تقريباً، وعادةً من التقاط CUDA graph. الذاكرة الفارغة موجودة لكن ليست ككتلة متّصلة واحدة كبيرة بما يكفي للتخصيص. أضف --enforce-eager لتعطيل CUDA graphs، فيُحرّر نحو 1.5-2GB ويزيل التجزّؤ. وضبط PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True يساعد PyTorch على إعادة استخدام المساحة المجزّأة أيضاً.

أي GPU أحتاج لتشغيل نموذج 70B؟

نموذج 70B بدقة FP16 يحتاج نحو 140GB للأوزان وحدها، فلا يتّسع على كرت واحد. وبتكميم 4-bit يهبط إلى نحو 40GB، ما يتّسع على كرت A100 أو H100 بسعة 80GB مع متّسع للـKV cache، أو على كرتين بسعة 24GB. وإن لم تملك كرتاً بسعة 80GB، فإن استئجاره بالساعة (A100 80GB بنحو 1.39 دولار/ساعة، وH100 80GB بنحو 2.89 دولار/ساعة) أرخص من شراء عتاد لمهمة عابرة.

سجل التغييرات

  • 19 يونيو 2026 — نُشر أول مرة.

المراجع

  1. "How to fix vLLM out of memory errors," markaicode.com، اطُّلع عليه في يونيو 2026.
  2. "Fix vLLM out of memory: KV cache," gigagpu.com، اطُّلع عليه في يونيو 2026.
  3. RunPod, "GPU instance pricing," runpod.io/gpu-instance/pricing، اطُّلع عليه في يونيو 2026.
  4. RunPod, "Get started with the vLLM worker," docs.runpod.io، اطُّلع عليه في يونيو 2026.