أساسيات استدلال نماذج اللغة الكبيرة
استراتيجيات التجميع لأقصى إنتاجية
3 دقيقة للقراءة
التجميع هو المفتاح لتعظيم استخدام GPU والإنتاجية. دعنا نستكشف التطور من التجميع الثابت إلى المستمر.
مشكلة استخدام GPU
وحدات GPU هي معالجات متوازية ضخمة مصممة لعمليات المصفوفات. استدلال الطلب الواحد يهدر هذه القوة:
معالجة طلب واحد:
┌─────────────────────────────────────────────┐
│ استخدام GPU: 5% │
├─────────────────────────────────────────────┤
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
│ ███ │
│ └── جزء صغير فقط من GPU نشط │
│ │
│ المشكلة: عرض نطاق الذاكرة هو عنق الزجاجة │
│ وحدات حساب GPU تجلس خاملة بانتظار │
│ قراءات الذاكرة أثناء مرحلة الفك الترميزي │
└─────────────────────────────────────────────┘
التجميع الثابت
النهج التقليدي: الانتظار للدفعة، المعالجة معاً:
التجميع الثابت:
─────────────────
الخطوة 1: جمع الطلبات حتى امتلاء الدفعة
الخطوة 2: حشو جميع التسلسلات إلى الطول الأقصى
الخطوة 3: معالجة الدفعة بأكملها معاً
الخطوة 4: انتظار أبطأ طلب للانتهاء
الخطوة 5: إرجاع جميع الاستجابات معاً
┌─────────────────────────────────────────────┐
│ دفعة ثابتة (الحجم=4) │
├─────────────────────────────────────────────┤
│ الطلب A: "مرحبا" → [128 رمز استجابة] │
│ الطلب B: "أهلا" → [512 رمز استجابة] │
│ الطلب C: "هاي" → [64 رمز استجابة] │
│ الطلب D: "سلام" → [256 رمز استجابة] │
├─────────────────────────────────────────────┤
│ جميعها محشوة إلى 512 رمز │
│ A, C, D تنتهي مبكراً → انتظار B │
│ حساب ضائع: ~50% │
└─────────────────────────────────────────────┘
المشاكل:
- الطلبات التي تنتهي مبكراً تحجب الجديدة
- الحشو يهدر الحساب على رموز فارغة
- زمن استجابة غير متوقع
التجميع المستمر (أثناء التنفيذ)
النهج الحديث: إدارة الدفعة ديناميكياً مع اكتمال الطلبات:
الجدول الزمني للتجميع المستمر:
───────────────────────────────
الوقت 0: [A][B][C][D] تبدأ معاً
الوقت 5: [A][B][ ][D] → C انتهى، الفتحة متاحة
الوقت 5: [A][B][E][D] → E يبدأ فوراً
الوقت 10: [ ][B][E][D] → A انتهى
الوقت 10: [F][B][E][D] → F يبدأ فوراً
...
┌─────────────────────────────────────────────┐
│ التجميع المستمر │
├─────────────────────────────────────────────┤
│ │
│ الوقت → │
│ ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ │
│ │A │A │A │A │A │ │ │ │ │ │ │ │ A │
│ │B │B │B │B │B │B │B │B │B │B │ │ │ B │
│ │C │C │ │ │ │ │ │ │ │ │ │ │ C │
│ │D │D │D │D │D │D │ │ │ │ │ │ │ D │
│ │ │ │E │E │E │E │E │E │E │ │ │ │ E │
│ │ │ │ │ │ │F │F │F │F │F │F │ │ F │
│ │ │ │ │ │ │ │ │G │G │G │G │G │ G │
│ └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘ │
│ │
│ الفوائد: │
│ • استخدام GPU قريب من 100% │
│ • لا انتظار للطلبات البطيئة │
│ • استجابة فورية عند الاكتمال │
│ • تحسين الإنتاجية 2-10 أضعاف │
│ │
└─────────────────────────────────────────────┘
تنفيذ التجميع المستمر
المكونات الرئيسية:
# المجدول يدير دورة حياة الطلب
class ContinuousBatchScheduler:
def __init__(self, max_batch_size: int):
self.waiting_queue = [] # الطلبات المنتظرة للبدء
self.running_batch = [] # الطلبات النشطة
self.max_batch_size = max_batch_size
def schedule(self):
# إزالة الطلبات المكتملة
self.running_batch = [
r for r in self.running_batch
if not r.is_complete
]
# ملء الفتحات الفارغة بالطلبات المنتظرة
available_slots = self.max_batch_size - len(self.running_batch)
for _ in range(available_slots):
if self.waiting_queue:
request = self.waiting_queue.pop(0)
self.running_batch.append(request)
return self.running_batch
الملء المسبق المقطع
تحسين للمحثات الطويلة: تقسيم الملء المسبق إلى قطع للتشابك مع الفك الترميزي:
بدون الملء المسبق المقطع:
────────────────────────
الملء المسبق الطويل يحجب جميع عمليات الفك
[PPPPPPPPPPPP][D][D][D][D]
└── ملء مسبق من 12 خطوة يحجب الاستجابات للطلبات الأخرى
مع الملء المسبق المقطع:
────────────────────────
[PPP][D][D][PPP][D][D][PPP][D][D][PPPP][D][D]
└── الملء المسبق مقسم إلى 4 قطع
الطلبات الأخرى تتقدم بين القطع
vLLM V1 (يناير 2025) يحسن الملء المسبق المقطع مع:
- ضبط تلقائي لحجم القطعة
- تخزين مؤقت للبادئة بدون تكلفة
- جدولة محسنة لأحمال العمل المختلطة
تكوين التجميع
المعاملات الرئيسية للضبط:
# مثال تكوين vLLM
from vllm import LLM
llm = LLM(
model="meta-llama/Llama-3.3-70B-Instruct",
# إعدادات التجميع
max_num_seqs=256, # أقصى تسلسلات متزامنة
max_num_batched_tokens=8192, # أقصى رموز لكل تكرار دفعة
# سياسة الجدولة
scheduling_policy="fcfs", # الأول وصولاً الأول خدمة
# البديل: "priority" للجدولة القائمة على الأولوية
# الملء المسبق المقطع
enable_chunked_prefill=True,
max_num_partial_prefills=4, # أقصى عمليات ملء مسبق متزامنة
)
قياس كفاءة التجميع
# المقاييس الرئيسية
batch_utilization = active_sequences / max_batch_size
# الهدف: >80%
# الرموز لكل تكرار
tokens_per_iter = sum(active_tokens) / iterations
# أعلى أفضل (عمل أكثر لكل رحلة ذهاب وإياب GPU)
# وقت انتظار الطابور
avg_wait = sum(queue_times) / num_requests
# الهدف: <100 مللي ثانية لأحمال العمل التفاعلية
التجميع المستمر أصبح الآن معياراً في أنظمة الإنتاج—إنه الأساس لجميع خدمات LLM الحديثة.
التالي، سنستكشف الفك الترميزي التخميني لتوليد أسرع. :::