المستوى المطلوب: محترف. هذا المقال يفترض أنك تشغّل LLM في إنتاج، تعرف KV cache و autoregressive decoding، وتقرأ من خرج vLLM/TGI أرقام throughput وlatency.
لو بتشغّل Llama 3 70B على A100 وبتلاقي إن TTFT متوسطه 280ms ومعدل التوليد 32 توكن/ثانية فقط، الـ GPU مش هو اللي بياخد كل المجهود. المشكلة في memory bandwidth، والحل اللي بينزل التوليد لـ 91+ توكن/ثانية بدون تغيير في الموديل اسمه Speculative Decoding.
المشكلة باختصار
أي LLM autoregressive بيولّد توكن واحد فقط في كل forward pass. ده مش حسابيًا غالي، ده memory bandwidth bound. الـ A100 بتقرأ 140GB من weights الموديل لكل توكن (FP16). النتيجة: أكتر من 90% من قدرة الـ GPU الحسابية بتروح هدر، والنظام بيعدّي زمنه في تحريك بايتات بدل ما يحسب FLOPs.
الحل المنطقي: استخرج توكنز أكتر من نفس الـ forward pass. ده اللي Speculative Decoding بيعمله بالظبط، باستخدام موديل تاني صغير اسمه draft model.
مثال للتقريب: لجنة المراجعة
تخيل عندك مراجع كبير بطيء، ومراجع مساعد سريع. المساعد بيكتب 5 جمل بسرعة وعلى عجلة. الكبير بدل ما يقعد يكتب جملة جملة (5 خطوات منفصلة)، بياخد الـ 5 جمل دفعة واحدة ويراجعها في خطوة واحدة. لو الجمل صح، خلّصنا في 1/5 الزمن. لو غلط في جملة، نوقف عندها ونرجع. ده Speculative Decoding بالظبط.
الفرق إن المراجع الكبير في حالتنا (Llama 3 70B) مش بيراجع الجمل بشكل بشري، بيحسب الـ probability distribution لكل توكن، وبيقارنه بالـ distribution اللي طلعت من الموديل المساعد.
التعريف العلمي بالتفاصيل
الفكرة من ورقة Leviathan et al. "Fast Inference from Transformers via Speculative Decoding" (ICML 2023). عندنا موديلين:
- Draft model (M_q): موديل صغير وسريع، مثلًا Llama 3.2 1B. بياخد ~2ms لكل توكن.
- Target model (M_p): الموديل الكبير اللي إنت عايزه يولّد، Llama 3 70B. بياخد ~30ms لكل توكن.
الخطوات في كل تكرار:
- Draft بيولّد γ توكنز autoregressive (مثلًا γ=5). بياخد 5×2 = 10ms.
- Target بيمرّر الـ γ توكنز كلهم في forward pass واحد parallel ويرجع probabilities لكل واحد. بياخد ~32ms (forward pass واحد بدل 5).
- لكل توكن x، نقارن p(x) من الـ target و q(x) من الـ draft. لو p(x) ≥ q(x) نقبل التوكن. لو أقل، نقبله باحتمال p(x)/q(x).
- عند أول رفض، نتجاهل باقي الـ draft tokens ونعيد عينة من distribution مصححة هي (p(x) − q(x))_+.
الإثبات الرياضي في الورقة (Theorem 3.5) بيضمن إن التوزيع النهائي للتوكنز المقبولة مطابق لتوزيع الـ target model نفسه. يعني الجودة لا تتغير، السرعة بس بتزيد. ده مش approximation، ده exact.
الكود التنفيذي على vLLM 0.7+
from vllm import LLM, SamplingParams
# Target model 70B + draft model 1B على نفس الـ tokenizer family
llm = LLM(
model="meta-llama/Meta-Llama-3-70B-Instruct",
speculative_model="meta-llama/Llama-3.2-1B-Instruct",
num_speculative_tokens=5,
use_v2_block_manager=True,
tensor_parallel_size=4,
gpu_memory_utilization=0.92,
)
sampling = SamplingParams(temperature=0.7, max_tokens=512)
prompts = ["اشرح Speculative Decoding في 3 جمل."] * 8
outputs = llm.generate(prompts, sampling)
for o in outputs:
print(o.outputs[0].text)
المهم في الكود ده: num_speculative_tokens=5 هو γ. زود الرقم لـ 8 لو الـ draft مدرب كويس على نفس domain، نزّله لـ 3 لو acceptance rate تحت 50%.
الأرقام المقاسة من إنتاج
على A100 80GB × 4، نتائج بعد 1000 طلب توليد عربي:
- بدون speculative: 32 tok/s، TTFT 280ms، GPU utilization 14%.
- مع speculative (γ=5): 91 tok/s، TTFT 240ms، acceptance rate 71%.
- مع speculative (γ=8): 87 tok/s — أبطأ قليلاً لأن acceptance rate نزل لـ 58% والـ wasted compute زاد.
المكسب الفعلي: 2.84x في توليد التوكنز، مقابل ~5GB ذاكرة إضافية للـ draft model و KV cache بتاعه.
الـ trade-offs اللي لازم تعرفها
- الـ draft model بياكل ذاكرة. Llama 3.2 1B + KV cache بتاعه = حوالي 4-5GB إضافية لكل replica. لو الـ GPU عندك على الحد، الـ speculative هيخلّيك OOM.
- Acceptance rate بيحدد المكسب. لو الـ draft model مدرّب على نفس distribution الـ target، acceptance بيوصل 70-80%. لو موديلين مختلفين بشكل جوهري، بينزل لـ 30-40% والمكسب بيتآكل لدرجة إن الـ speculative بيضرّك.
- Batch size كبير بيقلل المكسب. لما الـ batch ≥ 32، الـ GPU بقت compute-bound مش memory-bound. الـ speculative بقى بيضيف overhead بدون مكاسب فعلية. الفايدة الحقيقية في batch ≤ 16.
- Greedy أفضل من sampling عالي. temperature=0 بيدّي acceptance أعلى من temperature=1.0 بفرق 12-18%، لأن التوزيعات بقت deterministic أكتر.
متى لا تستخدم Speculative Decoding
- لو target model أقل من 7B — الـ overhead أكبر من المكسب لأن forward pass الأصلي مش بطيء.
- لو batch size ≥ 32 على H100 — أنت compute-bound، استخدم continuous batching بس وكفاية.
- لو الـ workload chat قصير (≤ 50 توكن لكل رد) — الـ TTFT هي اللي بتحدد التجربة، مش الـ throughput الإجمالي.
- لو ما عندكش draft model مدرّب على نفس domain ونفس tokenizer — acceptance rate بينزل تحت 30% والـ speculative بيبقى عبء صافي.
الخطوة التالية
افتح dashboard الإنتاج بتاعك واحسب الـ acceptance rate الفعلي عبر vLLM metrics: vllm:spec_decode_draft_acceptance_rate. لو طلع فوق 65% والمكسب أقل من 2x، الـ bottleneck في مكان تاني (غالبًا KV cache fragmentation أو batch sizing). لو طلع تحت 40%، غيّر الـ draft model لواحد قريب من target في الـ vocab والـ tokenizer وأعد القياس.
المصادر
- Leviathan, Y., Kalman, M., Matias, Y. — "Fast Inference from Transformers via Speculative Decoding" — ICML 2023، arxiv.org/abs/2211.17192.
- Chen, C. et al. — "Accelerating Large Language Model Decoding with Speculative Sampling" — DeepMind 2023، arxiv.org/abs/2302.01318.
- vLLM Speculative Decoding Documentation — docs.vllm.ai/en/latest/models/spec_decode.html.
- Llama 3 و Llama 3.2 model cards — huggingface.co/meta-llama.
- قياسات الـ throughput والـ acceptance rate من تجربة شخصية على A100 80GB × 4 مع Llama 3 70B-Instruct + Llama 3.2 1B-Instruct draft، مايو 2026.