Continuous Batching
يعيد التجميع المستمر بناء دفعة خادم النموذج اللغوي الكبير عند كل خطوة من خطوات فك الترميز، بحيث تغادر الطلبات المكتملة وتنضم طلبات جديدة وتظل وحدات GPU مشغولة.
التجميع المستمر، ويُسمّى أيضًا الجدولة على مستوى التكرار أو التجميع أثناء التنفيذ، هو تقنية جدولة لتقديم النماذج التوليدية، حيث يعيد الخادم بناء الدفعة عند كل خطوة من خطوات فك الترميز. يخرج التسلسل المكتمل من الدفعة فورًا ويعيد نتيجته، ويحلّ طلبٌ قيد الانتظار محلَّه في الخطوة التالية. قدّم Gyeong-In Yu وزملاؤه في جامعة سيول الوطنية وFriendliAI هذا النهج في Orca خلال OSDI 2022، وأفادوا بأن الإنتاجية كانت أعلى بمقدار 36.9x من إنتاجية NVIDIA FasterTransformer على GPT-3 175B عند زمن الاستجابة نفسه. وشاع مصطلح التجميع المستمر في عام 2023 عندما تبنّاه vLLM وخدمة Text Generation Inference التابعة لـHugging Face، وأصبح التجميع المستمر الآن هو المُجدول الافتراضي في محركات تقديم النماذج التي تشغّل النماذج اللغوية الكبيرة (LLMs).
لماذا يهدر التجميع على مستوى الطلبات موارد GPU#
ينتج توليد النصوص رمزًا مميزًا واحدًا في كل تمريرة أمامية، وتحتاج الطلبات إلى أعداد متفاوتة جدًا من التمريرات: فإجابة بنعم أو لا تنتهي بعد بضعة رموز مميزة، بينما قد يصل ملف برمجي إلى آلافها. في التجميع الثابت، تبقى مجموعة من الطلبات معًا حتى ينتهي أطولها. وتظل الخانات التي انتهت سلاسلها مبكرًا خاملة، بينما تنتظر الطلبات الجديدة إفراغ المجموعة كاملة، ما يزيد زمن استدلال كل طلب قصير يأتي بعد طلب طويل.
يجمع التجميع الديناميكي، وهو مخطط على مستوى الطلبات يُستخدم في خوادم مثل NVIDIA Triton، الطلبات التي تصل خلال نافذة زمنية قصيرة ويشغّلها معًا كدفعة واحدة حتى اكتمالها. يناسب ذلك النماذج ذات التكلفة الثابتة لكل مُدخل، مثل مصنّف الصور أو كاشف الكائنات، لأن كل مُدخل يكتمل في تمريرة أمامية واحدة. ينشئ وضع التنبؤ في Ultralytics YOLO دفعات على مستوى الطلبات من مُدخلات YOLO26 الواردة من المصدر: يشغّل ملف .streams لعناوين URL للكاميرات كدفعة واحدة تضم أحدث إطار من كل تدفق، لذلك تعمل 8 تدفقات بحجم دفعة 8، كما تجمع الوسيطة batch إطارات من فيديو أو دليل أو قائمة صور .txt في تمريرة أمامية واحدة.
كيف تعمل الجدولة على مستوى التكرار#
يشغّل المجدول خطوة فك ترميز واحدة لكل سلسلة نشطة، ثم يتحقق مما إذا كانت كل سلسلة قد بلغت رمز نهاية التسلسل أو حد طولها. تُعاد السلاسل المكتملة وتُحرر ذاكرتها، وتُقبل الطلبات في قائمة الانتظار إذا كانت ذاكرة KV المؤقتة تتسع لها. يعالج Orca (مرحلة التهيئة المسبقة) مطالبة الطلب الجديد في الخطوة نفسها التي يفك فيها ترميز الطلبات الأخرى، وتفعل المحركات الحالية الأمر نفسه باستخدام التهيئة المسبقة المقسمة إلى كتل.
تطلّب مزج السلاسل مختلفة الأطوال فكرة أخرى، أطلق عليها Orca اسم التجميع الانتقائي. تُنفذ العمليات التي تتعامل مع كل رمز مميز على نحو مستقل، مثل عمليات ضرب المصفوفات الكبيرة في كل طبقة Transformer، على جميع الرموز المميزة لكل السلاسل معًا. أما الانتباه فيُنفذ لكل سلسلة على حدة، لأن لكل منها طول سياق خاصًا بها.
تحاكي هذه المحاكاة جدولة الطلبات الثمانية نفسها على GPU يفك ترميز أربع سلاسل في كل مرة:
import heapq
output_lengths = [5, 50, 8, 12, 40, 3, 30, 7] # tokens each queued request will generate
slots = 4 # sequences the GPU decodes together at each step
# Static batching: each group of 4 runs until its longest request finishes
static_steps = sum(max(output_lengths[i : i + slots]) for i in range(0, len(output_lengths), slots))
# Continuous batching: the next request takes the first slot that frees up
slot_free_at = [0] * slots
for length in output_lengths:
start = heapq.heappop(slot_free_at)
heapq.heappush(slot_free_at, start + length)
continuous_steps = max(slot_free_at)
for name, steps in [("static", static_steps), ("continuous", continuous_steps)]:
print(f"{name}: {steps} decode steps, slots busy {sum(output_lengths) / (steps * slots):.0%}")يحتاج التجميع الثابت إلى 90 خطوة لفك الترميز، وتظل الخانات مشغولة بنسبة 43% من الوقت. أما التجميع المستمر فيكتمل خلال 50 خطوة، أي بمدة أطول طلب، وتظل الخانات مشغولة بنسبة 78% من الوقت.
القيود والتقنيات المكمّلة#
يزيد حجم دفعة التشغيل من الإنتاجية الإجمالية، لكن كل خطوة تستغرق وقتًا أطول، فيزداد الزمن لكل رمز مميز مُخرَج. لذلك تحدد المحركات سقفًا لعدد السلاسل المتزامنة ولعدد الرموز المميزة المعالجة في كل خطوة، ويعرضهما vLLM باسم max_num_seqs وmax_num_batched_tokens، كما تجمع بين التجميع المستمر وبعض التقنيات ذات الصلة:
- PagedAttention: يخصّص ذاكرة KV المؤقتة في كتل صغيرة، بحيث تحرر السلسلة المكتملة ذاكرتها فورًا، ولا تحصل السلسلة الجديدة إلا على القدر الذي تستخدمه.
- التهيئة المسبقة المقسمة إلى كتل: تقسّم المطالبات الطويلة إلى أجزاء، كيلا تؤدي التهيئة المسبقة لطلب جديد إلى تعطيل فك ترميز الطلبات الأخرى.
- فك الترميز التخَمُّني: يحقق أكبر مكاسبه عند أحجام الدفعات الصغيرة، إذ تستخدم الدفعات المستمرة الكبيرة بالفعل معظم قدرة GPU الحسابية.










