باختصار: على رف واحد من نوع NVIDIA GB300 NVL72، يقدّم vLLM مع فصل P/D وWide-EP خدمة DeepSeek-V4.1-Flash على SemiAnalysis AgentX بمعدل 954K من الرموز/ثانية لكل GPU وبقيمة P90 تبلغ 196 رمز/ثانية لكل مستخدم، 7.9× نتيجتنا على عقدة واحدة في المنشور الأول و 38.96 دولارًا لكل ساعة GPU بأسعار DeepSeek خارج أوقات الذروة. ويحقق مسار فك ترميز متخصص سرعة 826 رمزًا/ثانية لمستخدم واحد. مقارنةً بـ DeepInfer، محرك DeepSeek الخاص، فإن معدل نقل فك الترميز لدى vLLM يقع ضمن 6% عبر أحجام الدفعات من 8 إلى 256، ويتتبع التعبئة المسبقة لديه المنحنى المنشور لـ DeepInfer.
تأتي الكفاءة من هندسة مدروسة للمكوّنات التي يمتلكها vLLM بالفعل، مبنية على النوى التي قام DeepSeek بمصدرها المفتوح. يستعرض هذا المنشور دراسة الأداء التي أجريناها، ويشرح كل تحسين، ويشارك الدروس التي تعلمناها:
- يمكن لمحرك متعدد الأغراض أن يوازي محركًا مخصصًا لنموذج بعينه
- افهم النموذج قبل التحسين
- مثيلات DEP الصغيرة هي الأفضل للتعبئة المسبقة1
- فك الترميز عبر Wide-EP يتوسع جيدًا مع EPLB
- نفقات CPU تصبح حرجة على نطاق NVL72
- مسار فك ترميز متخصص يفتح الباب أمام زمن استجابة منخفض
نظرة عامة على الأداء
الشكل 1: SemiAnalysis AgentX على NVIDIA GB300 NVL72: يحقق vLLM مع فصل P/D وWide-EP (باللون الذهبي) زيادة إضافية في الإنتاجية بمقدار 7.9 أضعاف مقارنةً بنتيجتنا المجمعة على عقدة واحدة في المنشور الأول. تحسب الإنتاجية الرموز المدخلة المخزنة مؤقتًا والمدخلة غير المخزنة والمخرجة (المصدر).
مقارنةً بـ DeepInfer
DeepInfer هو محرك الاستدلال الخاص بـ DeepSeek لنموذج DeepSeek-V4.1-Flash، وقد صدر هذا الأسبوع كمحرك غير متصل مع منحنيات منشورة للتعبئة المسبقة وفك الترميز. وهو المرجع الأكثر صلة بهذا النموذج، لذا قبل الخوض في تحسيناتنا نعرض موقع vLLM مقارنةً به.
فك الترميز. تحت إعداد فك الترميز الخاص بـ DeepSeek (سياق 131K، nextn=3)، يحقق vLLM على GB200 إنتاجية ضمن 6% من النتائج المنشورة لـ DeepInfer عبر أحجام الدفعات من 8 إلى 256 (الشكل 2).
الشكل 2: إنتاجية خرج فك الترميز لكل وحدة GPU مقابل حجم الدفعة عند سياق 131K مع nextn=3. vLLM على GB200 مقابل النتائج المنشورة لـ DeepInfer، مقروءة من المخططات في ملف README الخاص به (المصدر).
التمهيد (Prefill). يستخدم منحنى التمهيد المنشور لـ DeepInfer نظام EP4DP4 مع 32 خبيرًا زائدًا (redundant experts) وإعادة تشغيل محدودة بـ 140 رمزًا، على عتاد لا يذكره المخطط، ونحن نقرأ قيمه من المخطط. تشغيلنا يستخدم DEP2 على GB300 بدون خبراء زائدين، وإعادة تشغيل بـ 128 رمزًا، ومجموعات المطالبات الخاصة بنا. ولأن الإعدادات تختلف، لا نقرأ الفجوة بين المنحنيين كتسريع من محرك إلى محرك. ما يبيّنه الشكل 3 هو أن تمهيد DEP2 في vLLM يواكب محرك DeepSeek نفسه عبر النطاق الذي نشروه.
الشكل 3: إنتاجية التمهيد مقابل الرموز الجديدة. vLLM DEP2 على GB300 مقابل المنحنى المنشور لـ DeepInfer (EP4DP4، 32 خبيرًا زائدًا، إعادة تشغيل بـ 140 رمزًا، العتاد غير مذكور)، مقروء من المخطط في ملف README الخاص به (المصدر).
يقع المحركان قريبين من بعضهما لأنهما يتشاركان أصلًا مشتركًا في الاتجاهين. بُني DeepInfer في الأصل على vLLM، وفي المقابل دمجت vLLM باستمرار النوى (kernels) من مكتبات DeepSeek، بما في ذلك MegaAttn وMegaMoE وMega-mHC، وحقّقت تحسينات مكثفة لبقية المكدس حولها. يستهدف DeepInfer نموذجًا واحدًا في الوضع غير المتصل (offline)؛ بينما يخدم نفس بناء vLLM هذا النموذج أيضًا عبر الإنترنت مع فصل P/D وWide-EP عبر رف NVL72 كامل، وهو ما تقيسه بقية هذا المنشور. تصف الأقسام التالية ذلك العمل.
داخل الكواليس: من أين تأتي السرعة
قِس النموذج أولًا
قبل الضبط، بدأنا بقياس التصميمات المعمارية الفعالة لـ DeepSeek-V4.1-Flash:
- بصمة KV cache صغيرة. 890 بايت فقط لكل رمز لذاكرة KV cache العامة، بفضل مشاركة KV عبر الطبقات وضغط FP4 (انظر التقرير التقني لـ DeepSeek-V4.1-Flash).
- انتباه خفيف الوزن. تستخدم الطبقات 2 و8 و14 ضغطًا بمقدار 2× لفهرسة السياق الكامل. مع إعادة التشغيل المحدودة، تكتب الطبقة 20 ذاكرة KV عامة لجميع الرموز لكنها تجري الفهرسة والانتباه على آخر 128 فقط؛ وتعالج الطبقات 21–39 تلك الرموز فقط.
- فك الترميز محكوم بـ MoE حتى في السياق الطويل. انظر الشكل 5 أدناه. مع DEP4 عند فك الترميز بسياق 128K و64 طلبًا لكل رتبة، يستهلك MoE 62% من الخطوة المستهدفة، بينما يستهلك الانتباه والفهرس معًا 13% فقط.
يوضح الجدول أدناه زمن المقدمة (forward) للنموذج الهدف عند DEP32، مع 16 طلبًا لكل رتبة، و6 رموز (tokens) لكل طلب (رمز واحد بالإضافة إلى خمسة رموز مسودة DSpark)، وكل طلب عند طول السياق نفسه، على GB300. فالانتقال من 128K إلى 855K، أي 6.7 أضعاف السياق، لا يضيف سوى 0.6 مللي ثانية (+7%) إلى زمن فك الترميز (decode) للنموذج الهدف.
| السياق لكل طلب | 64K | 128K | 256K | 512K | 855K |
|---|---|---|---|---|---|
| المقدمة للنموذج الهدف (ms) | 8.86 | 8.93 | 9.03 | 9.25 | 9.53 |
| مقارنة بـ 128K | −0.8% | – | +1.1% | +3.6% | +6.7% |
تشكل هذه الخصائص بقية استراتيجية التحسين لدينا:
- يجب أن يعمل الـ Prefill بحجم DEP صغير. حتى نسخة DEP2 على B300 أو GB300 يمكنها استيعاب أوزان النموذج وذاكرة KV المؤقتة للعديد من الجلسات المتزامنة. حجم عالمي أصغر يبسط إلى حد كبير موازنة الحمل DP/EP.
- سعة KV نادرًا ما تحد حجم الدفعة. تتسع ذاكرة KV المؤقتة بشكل مريح في HBM، مما يسمح لنا بدفع كل عملية نحو حدودها من حيث الحوسبة أو عرض نطاق الذاكرة بدلًا من العمل حول سعة KV. هذا يحافظ أيضًا على اتساق قياساتنا ومنخفضة الضجيج دون أي استباق أو ضغط على ذاكرة KV المؤقتة.
- Wide-EP فعّال لفك الترميز. فك ترميز MegaMoE محدود بقراءات الأوزان، وWide-EP يقلل مباشرةً هذه التكلفة المهيمنة لـ MoE.
- موازنة حمل DP لفك الترميز أبسط. زمن خطوة فك الترميز لهذا النموذج يتفاوت قليلًا مع طول السياق، لذا يمكن تبسيط موازنة حمل DP إلى الأقل تحميلًا حسب عدد الطلبات لكل رتبة.
- تظل أحمال العمل الاصطناعية ممثِّلة لفك الترميز. استخدام متوسط أطوال المدخلات والمخرجات يمنحنا تقديرًا جيدًا للأداء دون إعادة تشغيل التتبع الوكيلي الكامل.
كيف قسنا
قياس الأداء بدقة دون تعقيد المنهجية بشكل مفرط ليس أمرًا بديهيًا. نقسمه إلى سؤالين: ما الذي يجب أن تكلفه خطوة prefill أو decode، وكم مقدار الحمل الإضافي الناتج عن عدم توازن DP وEP؟
- زمن خطوتي prefill وdecode.
vllm bench forward(#61339) يقيس زمن مقدمة النموذج لدفعة prefill أو decode دقيقة عبر مسارexecute_modelالفعلي عبر رتب DP وEP. هذا يقيس وقت GPU فقط ويعطي تتبعًا نظيفًا. علاوة على ذلك، فإنDecodeBenchConnectorيقيس أداء فك الترميز من البداية إلى النهاية على مستوى المحرك عند تزامن معين. الفجوة بين أزمنة GPU فقط وأزمنة خطوات الخدمة تكشف عن أعباء غير متوقعة. - عدم توازن DP في prefill: إعادة تشغيل النسخ المتطابقة مقابل المتأخرة. التتبعات الوكيلية تتفاوت من تشغيل لآخر، لذا يصعب عزل عدم توازن DP. لذلك نعيد تشغيل طلبات متطابقة على كل رتبة DP. في تشغيل mirror ، تستلم جميع الرتب طلباتها في الوقت نفسه. في تشغيل lag ، تستلم الرتبة r تتلقى الطلبات نفسها r × 5 ثوانٍ لاحقًا، لذا تكون الرتب غير متزامنة ولكنها تنجز المجموع نفسه من العمل. الفرق بين التشغيلين هو كلفة اختلال توازن DP.
- فك اختلال توازن EP: توجيه حقيقي مقابل توجيه موحّد. لكل طبقة MoE، نعرّف التوازن على أنه متوسط حمل الرتبة مقسومًا على أقصى حمل للرتبة، لكل خطوة وعبر نافذة EPLB. وكمرجع متوازن، نشغّل دفعة فك الترميز نفسها مع توجيه الرموز (tokens) بشكل موحّد عشوائيًا. لا يزال هذا المرجع يتضمن ضوضاء أخذ العينات: عند DEP32 مع 72 طلبًا لكل GPU، يحقق التوجيه الموحّد توازنًا يقارب 0.96 للهدف (توجيه top-6) و0.94 للمسودة (top-3). الفجوة بين التوجيه الحقيقي والموحّد هي الحد الأقصى الذي يمكن لموازنة الخبراء استعادته، ويُظهر تشغيل EPLB مقدار ما يستعيده فعليًا من تلك الفجوة.
الملء المسبق: DEP2 يعمل على أفضل وجه
كما نوقش أعلاه، فإن حجم DEP الصغير جذاب للملء المسبق. في تشغيل AgentX للملء المسبق فقط عند تزامن 256، قدّم DEP4 ما يمثل 83% فقط من إنتاجية DEP2 لكل GPU (53.3K مقابل 64.4K رمز/ثانية). إعادة تشغيلات mirror وlag مع تعطيل تخزين البادئات المؤقت تشير إلى اختلال توازن DP: عندما تفقد الرتب تزامنها، يفقد DEP4 13.6% من إنتاجيته.2 هذا يجعل DEP2 افتراضيًا بسيطًا بالنسبة لنا.
| إنتاجية الملء المسبق لكل نسخة (رمز/ثانية) | mirror (متوازن) | lag (غير متوازن) | الخسارة |
|---|---|---|---|
| DEP2 | 138.7K | 130.5K | 5.9% |
| DEP4 | 267.6K | 231.1K | 13.6% |
تحسينات مخفية خلف التتبع
تناولت مشاركتنا الأولى مجموعة واسعة من تحسينات prefill. ساعدتنا التتبعات الأنظف في تحديد الاختناقات المتبقية، ولا سيما تلك التي تنمو مع طول السياق. على سبيل المثال، على وحدتي معالجة رسومية GB300، يستغرق prefill بحجم 8K من الرموز 87.9 ms بدون سياق مسبقلكنه 189.4 ms مع سياق مخزّن بحجم 512Kواجهنا ثلاثة اختناقات إضافية:
توسيع إعادة التشغيل المحدود لـ SWA لتشمل الطبقة 20 (#59894): +19.9% عند 32K من الرموز الجديدةتؤدي إعادة التشغيل المحدودة لـ SWA بالفعل إلى تقييد الطبقات 21–39 بآخر 128 رمزاً. سابقاً، كانت الطبقة 20 لا تزال تجري حسابات الفهرس عبر جميع الرموز الجديدة. الآن تكتب KV لجميع الرموز الجديدة لكنها تنفذ بقية حساباتها فقط على دفعة إعادة التشغيل المكونة من 128 رمزاً. يحسّن هذا إنتاجية prefill بنسبة 19.9% عند 32K من الرموز الجديدةمع مكاسب تتصاعد من 10.1% عند 4K إلى 23.1% عند 64K.
استخدام صفحات بحجم 2 MB لجداول Engram المشتركة على المضيف (#62359): +2.8% إضافية عند 32Kتنجز Engram قراءات عشوائية من جداول على المضيف مشتركة بين رتب DP. كان /dev/shm التعيين السابق يستخدم صفحات GPU بحجم 64 KB، مما تسبب في حالات فقدان متكررة لـ TLB في الـ GPU. إن نقل الجداول إلى تخصيصات cuMem على NUMA المضيف يتيح صفحات GPU بحجم 2 MB، محسّناً إنتاجية prefill بنسبة إضافية 2.8% عند 32K من الرموز الجديدة.
يستخدم مفهرس prefill الآن DeepSelect لترتيب الكتل المرشحة، بما يطابق مسار decode. وتزداد فائدته مع عدد المفاتيح التي يتم ترتيبها، محسّناً إنتاجية prefill بنسبة إضافية 15.6% عند 32K من الرموز الجديدة و15.2% عند 64K.
معاً، تحسّن هذه التغييرات إنتاجية prefill للرموز الجديدة بنسبة 35.6–43.9% على مدى 4K–64K من الرموز الجديدة فوق بادئة مخزّنة بحجم 128K. عند 32K، يبلغ المكسب المجمع 42.5%؛ وعند 64K، ترتفع الإنتاجية من 71.2K إلى 102.5K رمز/ث/GPU (+43.9%).
الشكل 4: إنتاجية prefill للرموز الجديدة لكل GPU على DEP2 بعد إصابة ذاكرة تخزين مؤقت بحجم 128K، مع إضافة إعادة تشغيل الطبقة 20، وصفحات Engram بحجم 2 MB، وDeepSelect top-k واحداً تلو الآخر.
Decode: توسيع Wide-EP وموازنة الخبراء باستخدام EPLB
على جانب decode، تعد Wide-EP مع EPLB ممارسة راسخة، موصوفة في نظرة عامة على نظام الاستدلال لدى DeepSeek. يدعم vLLM كليهما منذ فترة (انظر منشورنا حول الخدمة على نطاق واسع)، وقد وجدنا أنهما لا يزالان يعملان بشكل جيد. يركز هذا القسم على نتائجنا الجديدة والدروس التجريبية.
توسّع Wide-EP
قمنا بقياس توسّع فك الترميز من DEP4 إلى DEP32 مع 64 طلبًا لكل GPU عند سياق 128K (مع تمكين EPLB؛ انظر القسم التالي). ينخفض زمن MegaMoE المستهدف من 13.4 إلى 6.0 مللي ثانية حيث يحمل كل رتبة خبيرات أقل، بينما يبقى العمل المتبقي حوالي 10 مللي ثانية. ونتيجة لذلك، تتناقص مكاسب الإنتاجية لكل GPU تدريجيًا. عند DEP32، يبدأ أيضًا عبء الاتصالات الخاص بالمسودة في إبطال فوائد التوازي الأوسع.
الشكل 5: زمن خطوة فك الترميز لكل رتبة من DEP4 إلى DEP32 على NVIDIA GB200 مع 64 طلبًا لكل GPU عند سياق 128K، والإنتاجية الناتجة لكل GPU.
EPLB
تركناه ليعيد EPLB ترتيب الخبيرات كل 3,000 خطوة، بناءً على حمل 1,000 خطوة السابقة. يرفع EPLB التوازن من 0.35 إلى 0.94 للنموذج المستهدف ومن 0.21 إلى 0.89 للمسودة، مستعيدًا حوالي 97% و93% من الفجوة إلى التوجيه الموحد.
الشكل 6: فك الترميز على GB300 NVL72 مع تعطيل EPLB، وEPLB للنموذج المستهدف فقط، وEPLB لكل من النموذج المستهدف ومسودة DSpark. تعرض التبويبات التوازن لكل خطوة، وتفصيل زمن كل خطوة عند DEP32، والإنتاجية (متوسط ثلاث تشغيلات؛ تُظهر الأعمدة النطاق).
تغييران يجعلان هذا ممكنًا. #62009 يقدم symm_mem خلفية قائمة على NVLink تعيد موازنة كامل DEP32 في أقل من ثانية دون إيقاف فك الترميز، وتدمج تعيين النسخ وتسجيل الحمل الخاصين بـ EPLB في نوى MegaMoE (موفرة حوالي 0.2 مللي ثانية لكل خطوة)، وتزيل مزامنة المضيف من حلقة فك الترميز. #61395 يدعم EPLB مع نماذج مستهدفة ومسودة غير متجانسة. تحتوي مسودة DSpark على 128 خبيرًا موجّهًا بتوجيه top-3، مقابل 384 بتوجيه top-6 للنموذج المستهدف، لذلك يتتبع EPLB موضع الخبيرات والحمل بشكل منفصل لكل نموذج ويعيد موازنة كليهما.
التغلب على عبء CPU في فك الترميز السريع واسع النطاق
يزامن فك الترميز Wide-EP جميع الرتب في كل طبقة، لذا فإن رتبة واحدة بطيئة تعطّل المثيل. يخفي الجدولة غير المتزامنة عبء CPU جيدًا على نطاق صغير، لكن زيادة عدد الرتب تجعل الأمر أصعب بطريقتين: تصبح خطوات GPU أقصر، مما يترك فسحة أقل لعمل CPU، ويصبح من الأرجح أن تتخلف رتبة واحدة عن الركب.
من الناحية العملية، لاحظنا أن DEP32 غير محسّن كان يعمل أبطأ من DEP16 (17.57 مقابل 13.84 مللي ثانية لكل خطوة)، على الرغم من أن تنفيذه على GPU كان أسرع بمقدار 1.1 مللي ثانية. يسرد الجدول أدناه كل سبب وجدناه، مرتبًا حسب التأثير. التأثيرات مأخوذة من إعدادات مختلفة، لذا يعطي كل صف تأثيره الخاص.
اعرض الأسباب والإصلاحات وتأثيراتها| السبب | الإصلاح | طلبات السحب (PRs) | التأثير | الإعداد |
|---|---|---|---|---|
| قراءة KV المنشورة بشكل متزامن على خيط عامل فك الترميز | دفع NIXL مع UCX scatter-gather؛ وإرسال صفوف KV المعبأة كمنطقة NIXL واحدة | موصل دفع NIXL, #61121 | 141K → 440K رمز/ثانية لكل GPU؛ P90 ~40 → 159 رمز/ثانية لكل مستخدم | GB300، 8P1D، تزامن 3,072 |
| زمن التأخير في Gloo all-reduce يزداد خطيًا مع عدد الرتب | تصغير تكراري مزدوج لـ all-reduce على المعالج المركزي | #61767، استنادًا إلى #60267 | مزامنة DP من 10.8 → 1.5 مللي ثانية لكل خطوة؛ الخطوة من 16.10 → 13.15 مللي ثانية | فك ترميز DEP32 |
| دفاعات القبول: قبول ما يصل إلى 140 طلبًا في خطوة واحدة | حد اختياري قدره 4 عمليات تحميل KV جديدة لكل خطوة | #61725 | 460K → 516K رمز/ثانية لكل GPU؛ P90 109 → 153 رمز/ثانية لكل مستخدم | GB300، 7P1D، تزامن 4,800، مع إصلاحين آخرين على مستوى المعالج المركزي |
| عمل قبول يتزايد مع طول الموجه | الموجه كمخزن مؤقت واحد من نوع int32؛ تخطي الكتل الفارغة في جداول كتل النافذة المنزلقة؛ نواة نسخ موجه مقسمة إلى أجزاء | #59908, #62702, #61724, #62698 | موجه من 855K: من 38.8 → 6.0 مللي ثانية من زمن المعالج المركزي لكل عملية قبول | قياس أداء دقيق للمحرك |
زمن استجابة منخفض: مسار فك ترميز متخصص للدفعات الصغيرة
كما وسّعنا دعم النواة منخفضة زمن الاستجابة لـ DeepSeek-V4.1-Flash (#61868 و #61869)، مواصلين الجهود من منشورنا السابق. في جلسات AgentX الحقيقية، يصل مسار فك الترميز المتخصص إلى 826 رمز/ثانية عند P90 لمستخدم واحد على أربع وحدات B300 GPU، بزيادة قدرها 44% عن مسار فك الترميز القياسي (575).
الشكل 7: SemiAnalysis AgentX مع TP4 على أربع وحدات B300 GPU عند تزامن 1 و8 و16، قبل وبعد InferenceX #4332 انتقل إلى مسار فك الترميز المتخصص.
شكر وتقدير
نود أن نشكر DeepSeek على إتاحة DeepSeek-V4.1-Flash ونواتها المحسّنة كمصدر مفتوح ومشاركتها، والتي وفرت الأساس لهذا العمل، وعلى نشر DeepInfer ونتائج أدائه، والتي منحتنا مرجعًا قويًا للتعلم والمقارنة. نشكر أيضًا SemiAnalysis على منصة معيار AgentX وعلى كل المساعدة.
نحن ممتنون بشكل خاص إلى Pei Li وHanjie Qiu وLisa Wang وYaoyao Ding وRohit Nagraj وXin Li من NVIDIA على تعاونهم الوثيق في تحسين الأداء، ودعمهم المستمر عبر vLLM وDynamo، ومساعدتهم في مشاريع AgentX. نشكر أيضًا Canlin Guo من مجتمع vLLM على تحسينه القيّم لمرحلة prefill.
قاد هذا العمل فريق Inferact.
الحواشي
-
DEPn تعني انتباهًا متوازيًا للبيانات مع توازٍ خبري على n وحدة معالجة رسومات. المرور الأمامي الهدف هو المرور الأمامي الكامل للنموذج الرئيسي في كل خطوة فك ترميز، حيث يتحقق من الرموز المسودة وينتج المخرجات؛ أما المرور الأمامي للمسودة فهو المرور الأمامي الكامل لنموذج المسودة DSpark، الذي يقترح الرموز للخطوة التالية. ↩
-
قيس على نسخة مبكرة؛ وتكلفة عدم التوازن خاصية لحجم DEP، وليست خاصية للنوى البرمجية (kernels). ↩