Transformers documentation

الدفعية المستمرة

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

الدفعية المستمرة

يعظّم الدفع المستمر (Continuous batching) استغلال وحدة معالجة الرسوميات (GPU) من خلال إعادة جدولة الدفعة ديناميكيًا في كل خطوة من خطوات التوليد. فمع انتهاء الطلبات، تنضم طلبات جديدة فورًا بدلاً من الانتظار حتى اكتمال الدفعة بأكملها. وبذلك تبقى وحدة معالجة الرسوميات مشغولة بالكامل ويظل معدل الإنتاجية مرتفعًا.

للاستخدام في بيئات الإنتاج، استخدم transformers serve. فهو يعتمد على ContinuousBatchingManager ويعرض نقطة نهاية HTTP متوافقة مع OpenAI.

generate_batch

يُتاح دعم الدفع المستمر (Continuous batching) من خلال generate_batch(). مرّر قائمة من الموجهات المُرمّزة (tokenized prompts) واحصل على النتائج الخاصة بها جميعاً عند اكتمالها. يتولى generate_batch جدولة المهام داخلياً ويبقى في وضع الانتظار (blocks) حتى تكتمل جميع الطلبات.

لحالات الاستخدام المتعلقة بتقديم الخدمة والبث، استخدم ContinuousBatchingManager مباشرةً لإدارة الطلبات.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.generation import ContinuousBatchingConfig, GenerationConfig

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen3-4B",
    attn_implementation="flash_attention_2",
    device_map="auto",
    dtype=torch.bfloat16,
)
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-4B")

prompts = [
    "What's up?",
    "Name a cat breed.",
    "Write a detailed history of quantum mechanics.",
]
inputs = [tokenizer.encode(p) for p in prompts]

generation_config = GenerationConfig(
    max_new_tokens=64,
    eos_token_id=tokenizer.eos_token_id,
)

outputs = model.generate_batch(inputs=inputs, generation_config=generation_config)

for request_id, output in outputs.items():
    text = tokenizer.decode(output.generated_tokens, skip_special_tokens=True)
    print(f"[{request_id}] {text}")

ContinuousBatchingManager

يعمل ContinuousBatchingManager بخيط خلفية (background thread) ويتيح لك إرسال الطلبات واستخراج النتائج بشكل مستقل. في كل خطوة توليد، يتحقق من الطلبات المكتملة ويحدد جدولة لطلبات جديدة للانضمام إلى الدفعة (batch). وهذا مفيد للبث (streaming) أو الخدمة في الوقت الفعلي أو إرسال الطلبات لحظة وصولها.

استخدم continuous_batching_context_manager() لبدء المدير وإيقافه بأمان. يحتوي المثال أدناه على مدخلات بطول متغير. بمجرد اكتمال أقصر موجه، يغادر الدفعة بينما تستمر الموجهات الأطول في التوليد. مع الدفعات الثابتة، كان عليك ملء جميع المدخلات حتى الطول نفسه. تتيح لك الدفعات المستمرة تحرير الموجه المكتمل لبدء معالجة الموجه التالي فورًا.

with model.continuous_batching_context_manager(generation_config=generation_config) as manager:
    manager.add_request(
        input_ids=tokenizer.encode("Write a detailed history of quantum mechanics."),
        request_id="long",
        max_new_tokens=512,
    )
    manager.add_request(
        input_ids=tokenizer.encode("What's up?"),
        request_id="short_0",
        max_new_tokens=32,
    )
    manager.add_request(
        input_ids=tokenizer.encode("Name a cat breed."),
        request_id="short_1",
        max_new_tokens=32,
    )

    for result in manager:
        text = tokenizer.decode(result.generated_tokens, skip_special_tokens=True)
        print(f"[{result.request_id}] {text}")

يمكنك أيضًا استدعاء init_continuous_batching() لإدارة دورة الحياة بنفسك.

manager = model.init_continuous_batching(generation_config=generation_config)
manager.start()

# submit and retrieve requests...

إيقاف تشغيل المدير

يعمل المدير بخيط في الخلفية ويحتفظ بالموارد الموزعة. يتم إيقاف التشغيل في مرحلتين حتى تتمكن من اختيار ما تريد فعله مع العمل الجاري.

استدعِ stop() لإيقاف الخيط الخلفي. افتراضيًا، يتوقف المُدير عن قبول الطلبات الجديدة وينتظر حتى تنتهي الطلبات الموجودة في قائمة الانتظار والطلبات النشطة قبل خروج الخيط.

manager.stop()

مرّر hard_stop=True للتخلي عن العمل المعلق فوراً. تُفشل الطلبات المجدولة والنشطة مع RuntimeError بدلاً من إتمامها.

manager.stop(hard_stop=True)

بمجرد استدعاء stop، تتجاهل add_request() وadd_requests() الطلبات الجديدة وتسجّل تحذيرًا. يمكنك ما زال استدعاء start مرة أخرى لتشغيل جلسة توليد أخرى باستخدام نفس المُدير.

استدعِ destroy() لإطلاق الموارد الموزعة. يوقف destroy المُدير أولاً إذا كان لا يزال قيد التشغيل، ولا يمكن إعادة تشغيل المُدير بعد ذلك. استخدمه عند الانتهاء من الدفع المستمر (continuous batching) طوال عمر العملية.

manager.destroy()

يتولى continuous_batching_context_manager() معالجة هذه العملية. فهو يستدعي stop عند الخروج، ويستدعي destroy ما لم تقم بتمرير persistent_manager=True لتخزين المدير في النموذج للجلسة التالية.

إضافة الطلبات

يقوم add_request() بإرسال طلب واحد. يمكنك تقديم request_id أو ترك المدير يولّد معرّفًا تلقائيًا.

manager.add_request(input_ids=input_ids, request_id="my_request")

يقوم add_requests() بإرسال دفعة كاملة دفعة واحدة. وهو يرتّب المدخلات تلقائيًا لتعظيم إصابات ذاكرة التخزين المؤقت للبدايات المشتركة عند تمكين مشاركة الكتل.

manager.add_requests(inputs=inputs)

إلغاء طلب باستخدام cancel_request().

manager.cancel_request(request_id="my_request")

معاملات أخذ العينات لكل طلب

فعّل per_request_processors لتطبيق temperature وtop_k وtop_p بشكل مستقل لكل طلب ضمن نفس مسار الأمامي، مما يتيح استخدام معاملات أخذ عينات مختلفة للطلبات المختلفة (على سبيل المثال، مخرجات إبداعية ذات درجة حرارة عالية مقابل مخرجات دقيقة ذات درجة حرارة منخفضة).

cb_config = ContinuousBatchingConfig(per_request_processors=True)

# each request gets its own sampling parameters
manager.add_request(input_ids=inputs_a, temperature=0.9, top_p=0.95)
manager.add_request(input_ids=inputs_b, temperature=0.1, top_k=10)

يجب أن يكون كل معامل في GenerationConfig بقيمة غير افتراضية من أجل إنشاء معالج logits المرتبط به وقت التشغيل. على سبيل المثال، اضبط temperature على قيمة أخرى غير None أو 1 لدعم التحكم في درجة الحرارة لكل طلب. يمكن إنشاء الطلبات التي تكون درجة حرارتها 1 بعد ذلك.

استرجاع النتائج

تكرّر على المدير لاستلام النتائج فور وصولها.

for result in manager:
    print(tokenizer.decode(result.generated_tokens, skip_special_tokens=True))

تجلب get_result() النتيجة التالية من طابور الإخراج. مرّر request_id لتصفية طلب محدد. إذا لم تتطابق النتيجة التالية في الطابور، تُعاد إلى الطابور وتعيد الطريقة None.

# next available result
result = manager.get_result()

# filter for a specific request
result = manager.get_result(request_id="my_request")

البث

اضبط streaming=True على الطلب، ثم استخدم request_id_iter() للتكرار على المخرجات الجزئية أثناء توليد الرموز.

from transformers.generation.continuous_batching import RequestStatus

manager.add_request(input_ids=input_ids, request_id="streamed", streaming=True)

for chunk in manager.request_id_iter(request_id="streamed"):
    token = tokenizer.decode(chunk.generated_tokens[-1:], skip_special_tokens=True)
    print(token, end="", flush=True)
    if chunk.status == RequestStatus.FINISHED:
        break

ContinuousBatchingConfig

يتحكم ContinuousBatchingConfig في ذاكرة KV، والجدولة، ورسوم CUDA، واستخدام الذاكرة، وغيرها. مرّره إلى generate_batch أو init_continuous_batching() عبر الحجة continuous_batching_config، بشكل منفصل عن GenerationConfig. تصف الإعدادات الثنائيتان أشياء مختلفة. فـGenerationConfig يركّز على النموذج ويحتوي على معاملات العينة والتوقف، بينما يركّز ContinuousBatchingConfig على العتاد ويحتوي على معاملات الذاكرة والجدولة.

إعداد continuous_batching_config على GenerationConfig لم يعد مدعوماً، ويُصدر تحذيراً FutureWarning، وسيتم إزالته في الإصدار v5.19.

بشكل افتراضي، يكون max_batch_tokens بقيمة 8192، محددًا بذاكرة وحدة معالجة الرسوميات المتاحة ولا يقل أبدًا عن 256، بينما يملأ num_blocks الذاكرة المتبقية. استخدم الجدول أدناه لمساعدتك في اختيار الميزات المناسبة.

ميزةالذاكرةمعدل الإنتاجيةزمن الاستجابة
max_memory_percent / page_size✓ يتحكم في ميزانية KV
max_batch_tokens↑ مخازن إدخال أكبر✓ دفعات تمهيد أكبر✓ زمن TTFT عند كونه محكومًا بالتهيئة المسبقة
scheduler✓ سياسة الجدولة✓ TTFT
رسوم CUDA↑ تخزين الرسم البياني✓ تقليل نفقات الإرسال✓
الدفعة غير المتزامنة↑ ~2× مخازن الإدخال/الإخراج✓ يتداخل مع المعالج المركزي/وحدة معالجة الرسوميات
التجميع↑ زمن الإحماء فقط✓ عمليات تمرير أمامي أسرع✓
مسار فك الترميز السريع↑ جدول الكتل لكل طلب✓ خطوات فك الترميز فقط أسرع✓
إزاحة المعالجة إلى وحدة المعالجة المركزية↑ ذاكرة وحدة المعالجة المركزية المثبتة✓ يتخطى بعض عمليات إعادة التمهيد
التخزين المؤقت للبادئة↓ كتل KV المشتركة✓ يتخطى التعبئة الأولية المكررة✓ TTFT
الانتباه الصفحي↓ لا تجزئة✓ عضوية ديناميكية للدفع
نافذة المنزلقة↓ ذاكرة KV محدودة لكل طبقة
المعالجات لكل طلب✓ معلمات أخذ عينات مختلطة لكل دفعة
max_requests_per_batch↓ يحدّ من مخزن القيم اللوجستية✓ تحديد حد لحجم الدفعة
safety_margin✓ يحمي زمن فك الترميز
from transformers.generation import ContinuousBatchingConfig

cb_config = ContinuousBatchingConfig(
    max_memory_percent=0.8,
    page_size=256,           # KV cache page size in tokens
    scheduler_type="fifo",        # "fifo" or "prefill_first"
)

outputs = model.generate_batch(
    inputs=inputs,
    generation_config=generation_config,
    continuous_batching_config=cb_config,
)

حجم صفحة ذاكرة KV

page_size يحدد عدد رموز KV التي تستوعبها صفحة الانتباه الكاملة الواحدة لطبقة واحدة. يجب أن يكون هذا الرقم على الأقل 4، وإلا فإن التهيئة تثير ValueError. القيمة الافتراضية 256 تعمل لمعظم الأحمال.

تم إيقاف استخدام معامل block_size واستبداله بـ page_size.

تقليل حجم الصفحة يزيد من كفاءة إدارة المسجل، لكنه يهدر مساحة عندما يتوقف تسلسل في منتصف الصفحة. أما الصفحات الأصغر فتهدر مساحة أقل لكنها تتطلب إدارة مسجل أكثر. عادةً لا تحتاج إلى ضبط page_size. إذا كان حمل عملك يحتوي على العديد من الطلبات القصيرة، جرّب قيمة أصغر. وإذا كان يحتوي على عدد قليل من الطلبات الطويلة جدًا، جرّب قيمة أكبر. راجع إدارة الذاكرة لمعرفة كيفية تداخل الصفحات والكتل والمقاطع معًا.

cb_config = ContinuousBatchingConfig(page_size=128)

حجم دفعة التعبئة المسبقة

max_batch_tokens يحدد ميزانية الرموز لمرور أمامي واحد، أي الحد الأقصى لعدد رموز الاستعلام التي يعالجها النموذج دفعة واحدة. يؤدي زيادة الميزانية إلى حشد المزيد من رموز الموجز في كل عملية تعبئة مسبقة، مما يرفع معدل إنتاجية التعبئة المسبقة ويقلل زمن الوصول إلى الرمز الأول في الأحمال التي تعتمد بشكل كبير على الموجزات. يقسم المجدول الموجزات التي تتجاوز الميزانية عبر خطوات متعددة. راجع التعبئة المسبقة المقسمة لمعرفة كيفية معالجة الموجزات التي تتجاوز الحجم.

افتراضيًا، تكون قيمة max_batch_tokens هي 8192. وتُقيَّد هذه القيمة بذاكرة وحدة معالجة الرسوميات المتاحة حتى لا تُزاحم تينسورات الإدخال لكل دفعة ذاكرة KV، ولا تنخفض أبدًا عن 256. على وحدة معالجة رسوميات ذات ذاكرة حرة قليلة، تُخفض هذه القيود القيمة عن 8192.

يستمد max_batch_tokens وnum_blocks من ميزانية الذاكرة نفسها، لذا فهما يتبادلان التأثير مع بعضهما البعض. ميزانية الرموز الأكبر تخصص مخازن إدخال أكبر وتترك عددًا أقل من كتل ذاكرة KV للطلبات المتزامنة أو الطويلة. ارفع قيمة max_batch_tokens لزيادة معدل معالجة التمهيد (prefill) عندما تتوفر لديك ذاكرة إضافية، وقلّلها لتحرير الذاكرة من أجل المزيد من كتل KV أو لتجنب أخطاء نفاد الذاكرة.

cb_config = ContinuousBatchingConfig(max_batch_tokens=16384)

حدود الدفعات والجدولة

يحدد max_requests_per_batch الحد الأقصى لعدد الطلبات التي تُنفَّذ في تمريرة أمامية واحدة. ينتج النموذج متجه logits بأبعاد تحدد بواسطة عدد رموز الدفعة وحجم قاموس الكلمات، ويُحوَّل إلى fp32 لأغراض العينة، مما يضاعف حجم الذاكرة المستهلكة. بما أن كل طلب يحتاج فقط إلى توقع الرمز التالي، فإن تحديدًا أصغر يحافظ على صغر حجم هذا المتجه ويتجنب أخطاء نفاد الذاكرة في الدفعات التي تركز على مرحلة التعبئة الأولية وتتميز بقواميس كبيرة. افتراضيًا، يُضبط هذا الحد على عدد الموجهات المُرسلة، مع قيمة احتياطية تبلغ 1024، ثم يُقيَّد ليلائم max_batch_tokens وnum_blocks.

cb_config = ContinuousBatchingConfig(max_requests_per_batch=256)

يحتجز safety_margin نسبة من سعة الكاش المتاحة للطلبات النشطة. عندما تنخفض السعة المتاحة دون safety_margin (وهي نسبة من إجمالي حجم الكاش)، يتوقف الجدول عن قبول طلبات جديدة ويستمر فقط في فك ترميز الطلبات الجارية بالفعل. وهذا يعطي الأولوية لإنهاء العمل النشط على بدء طلبات جديدة، مما يحمي زمن استجابة فك الترميز ويؤخر offloading. يجب أن تقع القيمة بين 0 و1، حيث يؤدي تحديد 0 إلى تعطيل الهامش.

cb_config = ContinuousBatchingConfig(safety_margin=0.15)

يعتمد الافتراضي على مُجدول المهام. فبالنسبة لمُجدول FIFO، يكون 0.15، وبالنسبة إلى prefill_first، يكون 0.0. راجع القبول لمعرفة كيفية تفاعل الهامش مع جدولة المهام.

احتمالات السجل

يعيد ContinuousBatchingConfig احتمال السجل (log probability) لكل رمز مُولَّد عند تعيين return_logprobs=True. وهذا مفيد في التعلم المعزز (RL) حيث تُعد قيم logprobs مدخلاً لبعض حلقات التدريب.

cb_config = ContinuousBatchingConfig(return_logprobs=True)

# generate_batch()

for request_id, output in outputs.items():
    for token_id, log_prob in zip(output.generated_tokens, output.logprobs):
        token = tokenizer.decode([token_id])
        print(f"{token} | logprob: {log_prob}")

رسوم CUDA

تُزيل رسوم CUDA الرسوم الإضافية المرتبطة بإرسال الأوامر من وحدة المعالجة المركزية (CPU) عن طريق تسجيل مخطط تنفيذ وحدة معالجة الرسوميات (GPU) مرة واحدة ثم إعادة تشغيله للدفعات التي تتطابق أشكالها. فعّلها صراحةً باستخدام use_cuda_graph=True.

cb_config = ContinuousBatchingConfig(use_cuda_graph=True)

عند التفعيل، يقوم المدير بتعبئة أطوال الاستعلام وقيم KV إلى فترات ثابتة بحيث تتكرر الأشكال وتُعاد استخدام الرسوم البيانية. تقلل القيم الأصغر لـ q_padding_interval_size وkv_padding_interval_size من هدر الحسابات المخصصة للتعبئة، لكن هذا يعني وجود أشكال فريدة أكثر يجب على الرسم البياني تسجيلها وتخزينها، مما يستهلك ذاكرة أكبر.

cb_config = ContinuousBatchingConfig(
    use_cuda_graph=True,
    q_padding_interval_size=64,
    kv_padding_interval_size=16384,
)

الدفعة غير المتزامنة

يتداخل الدفع غير المتزامن (Async batching) بين جدولة وحدة المعالجة المركزية (CPU) للدفعة التالية وحساب وحدة معالجة الرسوميات (GPU) للدفعة الحالية. يتطلب هذا الأمر استخدام مخططات CUDA (CUDA graphs) ويضاعف تقريبًا ذاكرة الفيديو (VRAM) المستخدمة لمصفوفات الإدخال.

cb_config = ContinuousBatchingConfig(
    use_cuda_graph=True,
    use_async_batching=True,
)

التجميع

يطبّق default_compile_level على عمليات الأمامية (forward passes) للنموذج torch.compile. تقوم عملية التجميع بتبادل تكلفة إحماء لمرة واحدة مقابل تسريع عمليات الأمامية أثناء التوليد. تؤدي المستويات الأعلى إلى تنفيذ تحسينات أكثر عدوانية، مما يحسّن الإنتاجية (throughput) لكنه يطيل مدة الإحماء. حافظ على المستوى منخفضًا أثناء الاختبارات وتكرار قياس الأداء (benchmarking)، وارفعه في حالات تقديم الخدمة (serving) طويلة الأمد حيث تُعوَّض تكلفة الإحماء عبر العديد من الطلبات.

يتراوح المستوى من 0 إلى 3. المستوى 0 هو الافتراضي ويتخطى التجميع بالكامل.

المستوىmodedynamicالمفاضلة
0——بدون تجميع (الافتراضي)، أسرع بدء تشغيل
1defaultTrueتحسين متواضع في السرعة، فترة إحماء قصيرة
2max-autotune-no-cudagraphsTrueسرعة أكبر، فترة إحماء أطول
3max-autotune-no-cudagraphsFalseأعلى معدل إنتاجية، أطول فترة إحماء
cb_config = ContinuousBatchingConfig(default_compile_level=1)

توفّر هذه المستويّة إعداد CompileConfig افتراضيًا لمساري التنفيذ varlen وdecode. ولا تنطبق إلا على المسار الذي لا يحتوي على إعداد صريح، لذا فإن varlen_compile_config وdecode_compile_config لها الأولوية عند ضبطها. وفي ظل FlashAttention، يتخطّى مسار varlen عملية التجميع لأن max_length_k يُسبّب إعادة تجميع متكررة، وبالتالي فإن المستويّة تؤثر فقط على مسار decode في تلك الحالة.

مسار فك الترميز السريع

عندما يحتوي الدفعة على طلبات فك ترميز فقط (رمز استعلام واحد لكل تسلسل)، يمكن للمدير إرسال الطلب إلى نواة flash_attn_with_kvcache بدلاً من نواة الطول المتغير. هذا أسرع من مسار varlen لأن النواة تقرأ وتكتب ذاكرة KV المقسمة إلى كتل في مكانها عبر جدول كتل بدلاً من المرور عبر تحديث يدوي. راجع الانتباه المقسم إلى كتل للتفاصيل على مستوى النواة.

يُحدَّد حجم المسار السريع بواسطة max_blocks_per_request، وهو الذي يحدد أبعاد جدول الكتل لكل طلب. افتراضيًا، يتم استنتاج هذا الحجم تلقائيًا. إذا تم ضبط max_prompt_length وmax_generated_length على المُدير، فإن جدول الكتل يُحدَّد حجمه ليتناسب مع أقصى طول للتسلسل. وإلا، يُستخدم حد افتراضي احتياطي (32 كتلة لكل طلب).

اضبط max_blocks_per_request على قيمة محددة لتحديد حجم جدول الكتل صراحةً. يكون هذا مفيدًا عندما تعرف الحد الأقصى لطول التسلسل لكل طلب وتريد تحديد التكلفة الذاكرة لجدول الكتل.

cb_config = ContinuousBatchingConfig(max_blocks_per_request=64)

اضبط max_blocks_per_request=0 لتعطيل المسار السريع وإجبار كل دفعة على المرور عبر نواة varlen. يستعيد هذا الإعداد السلوك السابق للافتراضي، وهو مفيد عندما لا يتوفر المسار السريع لتنفيذ الانتباه لديك (كما أن المدير يعطّله تلقائيًا عندما لا يمكن استخدام النواة الأساسية).

cb_config = ContinuousBatchingConfig(max_blocks_per_request=0)

تعتمد المسار السريع على نواة flash_attn_with_kvcache، وهي متاحة لمجموعتين من تركيبات الأجهزة وتنفيذ الانتباه.

الجهازattn_implementation
CUDAflash_attention_2 أو flash_attention_3
XPUflash_attention_2

في أي تركيبة أخرى، أو عندما لا يمكن استيراد النواة، يلجأ المدير إلى مسار varlen. يسجّل تحذيرًا فقط عند تعيين max_blocks_per_request بشكل صريح.

يدعم الانتباه الكامل جداول كتل النواة، بينما لا يدعم الانتباه المنزلزل ذلك. إذا احتوى النموذج على أي طبقات انتباه منزلزل، بما في ذلك النماذج الهجينة التي تستخدم أيضًا الانتباه الكامل، فإن التهيئة تفرض قيمة max_blocks_per_request لتكون 0، وتتم تجاوز أي قيمة غير صفرية تقوم بإعدادها. ثم يسجّل المدير أن مسار فك الترميز السريع غير متاح لأن بعض أنواع الانتباه في النموذج لا تدعم جداول كتل النواة.

إزاحة المعالجة إلى وحدة المعالجة المركزية

ينسخ نقل المعالجة إلى وحدة المعالجة المركزية (CPU) كتل ذاكرة KV المُستبعَدة إلى مخزن CPU مثبّت مُخصَّص مسبقًا عندما تمتلئ ذاكرة KV على وحدة معالجة الرسوميات (GPU). بعد أن يصبح مساحة التخزين متاحة، ينسخ المدير الكتل مرة أخرى إلى وحدة معالجة الرسوميات (GPU) ويستأنف الطلب دون إعادة حساب موجهه (prompt) والرموز المولَّدة.

اضبط cpu_offload_space على مساحة التبديل في المعالج المركزي بوحدة غيغابايت. القيمة الافتراضية، 0.0، تعطل نقل المهام إلى المعالج المركزي.

cb_config = ContinuousBatchingConfig(cpu_offload_space=8.0)

بشكل افتراضي، يحدّ cpu_offload_space_safety_threshold=0.8 المساحة المطلوبة إلى 80% من ذاكرة الوصول العشوائي المتاحة في النظام عند تثبيت psutil. اضبط cpu_offload_space=None لتحديد حجم بركة التبديل من عتبة الأمان.

مهلة انتهاء الوقت للتوازي على مستوى الموتر

في إطار توازي الموترات، ينشئ المُدير مجموعة اتصال على وحدة المعالجة المركزية لتنسيق إرسال الطلبات وإلغائها وإيقاف التشغيل عبر الرتب. يحدد cpu_group_timeout المدة القصوى التي يمكن أن تتوقف فيها عملية جماعية على هذه المجموعة قبل أن ينهار العملية. إذا تعطلت رتبة واحدة، يمنع المهلة الزمنية الرتب الأخرى من الانتظار إلى الأبد.

اضبط مهلة زمنية أطول للأحمال التي تُصدر عمليات جماعية نادرة الحدوث، أو مرّر None لتعطيلها.

cb_config = ContinuousBatchingConfig(cpu_group_timeout=600.0)

التخزين المؤقت للبادئة

عندما تتشارك طلبات متعددة بادئًا مشتركًا، مثل موجه النظام، يعيد المدير استخدام كتل ذاكرة KV الخاصة بها بدلاً من إعادة حسابها. القيمة الافتراضية لـ allow_block_sharing هي True. يكون مشاركة البادئ نشطة فقط عندما تدعم جميع مُخصِّصي أنواع الانتباه المشاركة، لذا فإن النماذج التي تعتمد كليًا على الانتباه فقط هي التي تستخدمه. تُعطَّل هذه الميزة في النماذج الانزلاقية البحتة والنماذج الهجينة حتى عندما تكون قيمة allow_block_sharing هي True.

cb_config = ContinuousBatchingConfig(
    allow_block_sharing=True,  # default
)

اختر واجهة خلفية للانتباه

Continuous batching supports FlashAttention, SDPA, and "paged|eager". Set attn_implementation when you load the model.

الواجهة الخلفيةattn_implementationالمتطلبات
FlashAttention 2“flash_attention_2”حزمة flash-attn أو kernels
FlashAttention 3“flash_attention_3”حزمة flash-attn-3 أو kernels
SDPA (أصلي في PyTorch)“sdpa”لا شيء
مباشر“paged|eager”لا شيء
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen3-4B",
    attn_implementation="flash_attention_2",
    device_map="auto",
    dtype=torch.bfloat16,
)

يعمل الدفع المستمر (Continuous batching) بشكل أسرع مع FlashAttention مقارنةً بـ eager أو SDPA، وذلك بشكل رئيسي لأن FlashAttention لا يحتاج إلى قناع انتباه (attention mask). إذا كان النموذج يدعم FlashAttention، فإن النموذج المحمّل باستخدام "eager" أو "sdpa" ينتقل إلى FlashAttention 3، أو إلى FlashAttention 2 إذا لم يكن FlashAttention 3 مثبّتًا، مع تسجيل تحذير. أما إذا لم تكن أي من النسختين مثبّتة، فلا يتغير الخلفية (backend).

للحفاظ على eager أو SDPA، على سبيل المثال عند إجراء الاختبارات، اضبط auto_switch_to_flash=False في ContinuousBatchingConfig. في كل مرة يبقى فيها الخادم الخلفي "eager"، يعمل التقطيع المستمر (continuous batching) بـ "paged|eager" بدلاً من ذلك.

توازي الموتر

بالنسبة إلى النماذج التي تكون كبيرة جدًا بحيث لا تتسع على وحدة معالجة رسومية واحدة، قسّم الأوزان عبر الأجهزة باستخدام توازي الموترات. اضبط عدد الأجهزة باستخدام DistributedConfig(tp_size=N). يقرأ الدفع المستمر حجم توازي الموترات من النموذج لتحديد حجم ذاكرة KV الصفحية لكل شريحة. راجع توازي الموترات للاطلاع على قائمة البنى المدعومة وكيفية عمل التقسيم.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, DistributedConfig
from transformers.generation import ContinuousBatchingConfig, GenerationConfig

distributed_config = DistributedConfig(tp_size=4)
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen3-32B",
    attn_implementation="flash_attention_2",
    distributed_config=distributed_config,
)
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-32B")

inputs = [tokenizer.encode(p) for p in ["What's up?", "Name a cat breed."]]
generation_config = GenerationConfig(max_new_tokens=64, eos_token_id=tokenizer.eos_token_id)

outputs = model.generate_batch(inputs=inputs, generation_config=generation_config)

شغّل السكربت باستخدام torchrun، مع ضبط --nproc-per-node على عدد وحدات معالجة الرسوميات التي تريد توزيع الشرائح عليها.

torchrun --nproc-per-node 4 cb_tp.py

يجب أن يكون حجم التوازي للتينسور قاسماً لعدد رؤوس المفاتيح والقيم num_key_value_heads في النموذج (تحقق من إعدادات النموذج). وإلا، فسيُطلق ذاكرة الصفحات المخزنة خطأً عند بدء التشغيل، لذا اختر قيمة مناسبة لـ --nproc-per-node.

لا تضبط device_map مع distributed_config. يتعارض الاثنان لأن device_map يضع الوحدات الكاملة على وحدات معالجة رسومات محددة، بينما تقسيم المتجهات (Tensor Parallelism) يقسّم نفس المعاملات عبر جميع وحدات معالجة الرسومات.

انتباه النافذة المنزلقة

تعمل النماذج التي تستخدم انتباه النافذة المنزلقة (Mistral، Gemma 2) مع الدفع المستمر. تستخدم طبقات النافذة SlidingAttentionCacheAllocator، الذي يحتفظ فقط بنافذة ثابتة من الرموز الحديثة عن طريق إعادة تدوير مجموعة صغيرة من الصفحات. يأتي نوع الانتباه من layer_types أو sliding_window الخاص بالنموذج، وليس من ContinuousBatchingConfig.

from transformers import AutoConfig, AutoModelForCausalLM

config = AutoConfig.from_pretrained("google/gemma-2-2b")
config.sliding_window = 4096

model = AutoModelForCausalLM.from_pretrained(
    "google/gemma-2-2b",
    config=config,
    attn_implementation="sdpa",
    device_map="auto",
    dtype=torch.bfloat16,
)

يتم تعطيل تخزين البادئة ومسار فك الترميز السريع في أي وقت يكون فيه الانتباه المنزلق حاضراً، بما في ذلك النماذج الهجينة التي تحتوي أيضاً على طبقات انتباه كاملة.

الخطوات التالية

Update on GitHub