TRL documentation

GRPO غير المتزامن

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

and get access to the augmented documentation experience

to get started

GRPO غير المتزامن

يتطلب هذا المدرب vllm وtransformers>=5.2.0 وkernels (حيث يقوم التدريب بتحميل FlashAttention من Hub عبره). فيما يتعلق بالتدريب الموزع، يُدعم FSDP2 فقط (لا يُدعم DeepSpeed ZeRO).

حاليًا، توجد قيود متضاربة على التبعيات بين vllm وtransformers. للتحايل على ذلك، ثبّت vLLM أولاً، ثم ثبّت transformers قسريًا، ثم أضف kernels عبر الإضافة الإضافية لـ TRL، والتي تثبّت الإصدار الذي يقبله transformers:

pip install vllm
pip install 'transformers>=5.2.0' --no-deps
pip install 'trl[kernels]'

نظرة عامة

تنفّذ experimental.async_grpo.AsyncGRPOTrainer خوارزمية GRPO نفسها، لكنها تفصل بين توليد النتائج (rollout) والتدريب. يعمل عامل في الخلفية على بثّ الاكتمالات (completions) بشكل مستمر من خادم vLLM، بينما تستهلك حلقة التدريب هذه الاكتمالات، مما يؤدي إلى تداخل عمليات التوليد وتحديثات التدرّجات بدلاً من تعاقبها. تعكس واجهة البرمجة (API) تلك الخاصة بـ GRPOTrainer — للحصول على تفاصيل كاملة حول طريقة GRPO نفسها (حساب الميزة، تقدير KL، صياغة الدالة الخاسرة، دوال المكافأة، إلخ)، راجع وثائق GRPO Trainer. ليست جميع الميزات المتوفرة في GRPOTrainer مدعومة؛ يُرجى الرجوع إلى experimental.async_grpo.AsyncGRPOConfig للاطلاع على المعلمات المدعومة.

تمت مساهمة هذا المدرب بواسطة Quentin Gallouédec و Amine Dirhoussi.

كيف يختلف عن GRPOTrainer

في GRPOTrainer القياسي، تكون عملية التوليد والتدريب متسلسلة: توليد دفعة، حساب الخسارة، تحديث الأوزان، ثم التكرار. وحتى في وضع vLLM colocate، حيث يتم تنفيذ التوليد على وحدات معالجة الرسوميات نفسها، يجب أن ينتهي أحد المرحلتين قبل أن تبدأ الأخرى.

يفصل experimental.async_grpo.AsyncGRPOTrainer بين هاتين المسألتين:

  • عامل النشر (عملية في الخلفية) — يرسل الاستعلامات إلى خادم vLLM، ويقيّم المكملات باستخدام دوال المكافأة، ويحسب المزايا، ويدفع العينات الجاهزة للتدريب إلى طابور.
  • حلقة التدريب (العملية الرئيسية) — تستخرج العينات من الطابور، وتحسب خسارة الوكيل المقصوصة، وتحديث أوزان النموذج.

يعمل عامل النشر (rollout worker) في عملية منفصلة تنشأ من المُدرِّب، لذا لا تتنافس عملية حساب المكافأة مع حلقة التدريب على قفل GIL. لهذا الأمر نتيجتان فيما يتعلق بما يمكنك تمريره كـ reward_funcs وtools وenvironment_factory (بالنسبة للأخير، راجد دليل OpenEnv الذي يغطي العقد والتكاملات المتاحة):

بما أننا نُشغّل عامل التوليد (rollout worker) في عملية منفصلة، فإن كل ما يُمرَّر إليه يكون مُجمَّداً (pickled). وعليه، يجب أن تكون كل دالة مكافأة، وأداة، وenvironment_factory (وأي شيء تغلق عليه) قابلة للتجميد: استخدم دالة على مستوى الوحدة (module-level function)، أو functools.partial، أو كائن فئة قابل للاستدعاء (callable class instance). الأدوات هي الاستثناء: يستدعي النموذج الأداة باسمها، لذا تُسجَّل كل أداة تحت __name__ الخاصة بها، ويجب أن تكون دالة على مستوى الوحدة. ستُثير الدوال اللامبدا (Lambdas) والدوال المغلقة (closures) خطأً من نوع TypeError عند trainer.train(). وهذا يختلف عن GRPOTrainer، حيث تُستدعى دوال المكافأة داخل العملية نفسها وتعمل الدوال المغلقة بشكل صحيح.

تعمل عملية النشر أيضًا مع CUDA_VISIBLE_DEVICES=""، لذا لا يمكنها استخدام وحدة معالجة الرسوميات. يتم تحميل نموذج مكافأة مدعوم بوحدة معالجة الرسوميات (مثل مُقيّم AutoModelForSequenceClassification) دون خطأ، لكنه يعود بصمت إلى CPU (لاحظ أنه في GRPOTrainer، يتشارك نموذج المكافأة من هذا النوع وحدات معالجة الرسوميات الخاصة بالمدرّب). حافظ على دوال المكافأة على جانب المعالج المركزي وخفيفة الوزن (مثل أدوات التحقق accuracy_reward، وفحوصات التنسيق والطول).

إذا كنت بحاجة إلى نموذج مكافآت يعمل على وحدة معالجة رسومية، فإن النهج الموصى به هو تقديمه خلف محرك استدلال خاص به (vLLM، TGI، …) على وحدات معالجة رسومية منفصلة، مع استخدام دالة مكافآت خفيفة الوزن وقابلة للتسلسل (picklable) لاستدعائه عبر HTTP. هذا يحافظ على بقاء نموذج المكافآت على جهازه الخاص بينما تبقى عملية النشر (rollout) تعمل على وحدة المعالجة المركزية فقط، كما أنه يتوسع بشكل مستقل عن المدرب.

يمكن أن تكون أدوات وبيئة الأساليب متزامنة أو غير متزامنة. تعمل الأدوات المتزامنة على مجموعة خيوط (thread pool) بحجم max_concurrent_rollouts، لذا فإن الأداة البطيئة لا تحجب أبدًا طلبات vLLM الأخرى الجارية. ضمن دور مساعد واحد، تُنفَّذ استدعاءات الأدوات بالترتيب الذي أصدرها به النموذج. لذلك، يمكن أن تعمل حتى max_concurrent_rollouts أداة متزامنة في وقت واحد، مما يعني أن أي أداة تقرأ أو تكتب حالة مشتركة يجب أن تكون آمنة من الخيوط (thread-safe).

بعد كل weight_sync_steps خطوات تدريب، يتم نقل الأوزان المحدّثة إلى خادم vLLM عبر NCCL بحيث تعكس عمليات التوليد اللاحقة أحدث سياسة.

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

التزامن

يُحدَّد عدد الطلبات المتزامنة المرسلة إلى خادم vLLM بواسطة max_concurrent_rollouts. افتراضيًا، يتم ضبطه تلقائيًا على max(max_staleness, 1) × per_device_train_batch_size × gradient_accumulation_steps × num_processes — وهو الحد الأقصى لعدد العينات التي يمكن للمدرِّب استهلاكها قبل أن تصبح قديمة. توليد عدد أكبر من ذلك يُعدّ هدرًا لأن العينات الزائدة ستُستبعد.

max_concurrent_rollouts هو حد أقصى وليس العدد الفعلي للطلبات قيد التنفيذ. يستطلع العامل نقطة النهاية /metrics على الخادم كل بضع ثوانٍ ويحافظ على حد حي تحته (rollout/concurrency_cap): فبعد تجاوز حد معين من التزامن، تؤدي الطلبات الإضافية إلى إبطاء vLLM بشكل أكبر، لأن ذاكرة KV cache تمتلئ، وتُستبق السلاسل وتُعاد حسابها، وتُطرد البادئات المخزنة وتُعاد تعبئتها. يبدأ الحد عند KV cache tokens / max_model_len، ويُقرأ من الخادم عند الإقلاع: أي عدد من الطلبات يتسع بطول كامل، بحيث لا يمكن للخطوة الأولى أن تسبب اضطراباً. طالما يبقى الاستخدام دون 0.6 دون أي طلبات في الطابور، يزداد الحد بنسبة 25% كل مرة يكتمل فيها عدد من عمليات rollout يعادل الحد، حتى يصل إلى الحد الأقصى. عندما يتجاوز استخدام ذاكرة KV cache قيمة 0.8، يُخفَّض الحد بنسبة 30%؛ لا يُلغى أي طلب قيد التنفيذ، بل تتوقف القبولات فقط حتى ينخفض مستوى الطابور دون الحد الجديد، ولا يُجرى أي تخفيض إضافي حتى ذلك الحين. إذا لم يعرض الخادم /metrics، يبقى الحد عند الحد الأقصى.

التحقق من الحالة واستئناف التدريب: القيمة الافتراضية لـ ignore_data_skip هي True؛ حلقة التخطي وإعادة التشغيل الأساسية في Trainer لا تنطبق على طابور النشر المباشر. بدلاً من ذلك، يتم حفظ فهرس أول موجه لم يتم تدريبه بعد في rollout_state.json جنباً إلى جنب مع كل نقطة تحقق، ويُستعاد عند الاستئناف، بحيث يتقدم العامل بسرعة إلى ذلك الموجه دون إعادة تشغيل العينات. إنه موضع التدريب، وليس موضع المولّد: يعمل العامل بأكثر من عمق طابور النشر من التدريب، وتُفقد العينات المخزنة مؤقتاً عند انتهاء التشغيل، لذا فإن الاستئناف من موضع المولّد سيتخطى الموجهات التي تم توليدها لكن لم يتم تدريبها عليها. لا يمكن إعادة تموضع مجموعات البيانات البثية (IterableDataset)؛ حيث يعيد عاملها التشغيل من الموجه 0 عند الاستئناف. عند استخدام FSDP مع bf16=True (الافتراضي) أو fp16=True، يُكتب model.safetensors في ذلك النوع من البيانات على الرغم من أن الأوزان الرئيسية هي fp32، لذا فإن نقطة التحقق المُرسلة تكون بحجم النموذج المُقدَّم، وليس ضعفه؛ لا تزال الأوزان الرئيسية fp32 وحالة المُحسِّن تذهب إلى ملفات الاستئناف (pytorch_model_fsdp.bin، optimizer.bin)، وهي ما يقرأه الاستئناف، لذا لا يتأثر الاستئناف. بدون FSDP، تكون نقطة التحقق هي أيضاً ملف الاستئناف، لذا فهي تحتفظ بنوع البيانات الرئيسي.

البدء السريع

# train_async_grpo.py
from datasets import load_dataset
from trl.experimental.async_grpo import AsyncGRPOTrainer
from trl.rewards import accuracy_reward

dataset = load_dataset("trl-lib/DeepMath-103K", split="train")

trainer = AsyncGRPOTrainer(
    model="Qwen/Qwen3-4B",
    reward_funcs=accuracy_reward,
    train_dataset=dataset,
)
trainer.train()

يجب أن يعمل خادم vLLM والمدرب على وحدات معالجة رسومية منفصلة. استخدم CUDA_VISIBLE_DEVICES لتقسيم وحدات المعالجة الرسومية لديك. على سبيل المثال، مع وجود وحدتين، يمكنك تشغيل خادم vLLM على وحدة 0 والمدرب على وحدة 1 على النحو التالي:

# Terminal 1: vLLM server on GPU 0 (dev mode + NCCL weight transfer are required)
CUDA_VISIBLE_DEVICES=0 VLLM_SERVER_DEV_MODE=1 vllm serve Qwen/Qwen3-4B \
    --max-model-len 4096 \
    --logprobs-mode processed_logprobs \
    --api-server-count 8 \
    --weight-transfer-config '{"backend":"nccl"}'

اضبط --max-model-len على أقصى طول إجمالي للتسلسل (الموجّه + الإكمال) الذي تتوقعه. تقلل القيمة المنخفضة من استخدام ذاكرة وحدة معالجة الرسوميات على الخادم، مما يحرر مساحة أكبر لذاكرة KV cache ويزيد من الإنتاجية. نقطة بداية جيدة هي طول الموجّه بالإضافة إلى max_completion_length من إعداداتك.

# Terminal 2: training on GPU 1
CUDA_VISIBLE_DEVICES=1 accelerate launch train_async_grpo.py

بطاقات AMD الرسومية

يعمل المدرب على معالجات AMD الرسومية (ROCm) دون أي إعداد إضافي: فالأوامر المذكورة أعلاه تعمل كما هي. يستخدم التدريب نواة الانتباه kernels-community/aiter-flash-attn على معالجات AMD الرسومية، وkernels-community/flash-attn4 على معالجات NVIDIA Blackwell الرسومية، وkernels-community/flash-attn3 على معالجات NVIDIA الرسومية الأخرى، وكلها تُحمَّل من Hub بواسطة مكتبة kernels. النماذج التي تحدّ من قيم الانتباه (attn_logit_softcapping)، مثل Gemma 2، غير مدعومة على معالجات AMD الرسومية أو على معالجات NVIDIA Blackwell الرسومية.

نماذج الرؤية واللغة

يمكن تدريب نماذج الرؤية واللغة (Qwen3.5, Qwen3.6, Qwen3-VL, …) على مجموعات بيانات نصية فقط. مرّر معرّف النموذج كما هو معتاد؛ لا يتغير شيء آخر:

CUDA_VISIBLE_DEVICES=0 VLLM_SERVER_DEV_MODE=1 vllm serve Qwen/Qwen3.5-2B \
    --max-model-len 4096 \
    --logprobs-mode processed_logprobs \
    --api-server-count 8 \
    --weight-transfer-config '{"backend":"nccl"}'

برج الرؤية مجمّد. مجموعة البيانات النصية فقط لا تنتج رموز صور أبدًا، لذا لا يُختبر البرج أبدًا عبر مسار الأمامي. كل ما يقع خارج برج النص (برج الرؤية، المُشغِّل متعدد الوسائط) يحمل requires_grad=False: فلا يتلقى تدرجات ولا حالة مُحسِّن، ويتخطى مزامنة الأوزان البرج بالكامل — حيث يحتفظ الخادم بالقيم التي حمّلها من نقطة التفتيش. لا يزال البرج محمّلًا، لذا يستهلك ذاكرة وحدة معالجة الرسوميات لأوزانه.

لا تُدعَم الصور بعد. لا يتم تمرير الأوامر التي تحتوي على صور إلى خادم vLLM أو إلى مسار التقدّم في التدريب. كما يتطلب التدريب متعدد الوسائط مسار التعبئة الخالية من الحشو لبناء مواضع M-RoPE ثلاثية الأبعاد من شبكة الصورة، وهو ما لم يُنفَّذ هنا.

عينة أعلى ك وأعلى با

يعيد Top-k و top-p تطبيع توزيع العينة على مجموعة مرشّحة محدودة بدلاً من المفردات الكاملة. تعكس احتمالات السجلات (log-probabilities) التي يعيدها الخادم ذلك (--logprobs-mode processed_logprobs)، لذا يجب على المُدرِّب (trainer) أن يُطبِّع على المجموعة نفسها، وإلا فستكون كل نسبة أهمية (importance ratio) منحازة: فاحتمال الرمز (token) ضمن المفردات الكاملة أقل منه ضمن مجموعة المرشحين التي سُحِب منها فعلياً (DeepSeek-V3.2، القسم 3.1). عند استخدام top_p < 1 أو top_k > 0، يطلب العامل (worker) من الخادم مجموعة المرشحين لكل رمز مُسحوب، ثم يُعيد المُدرِّب تطبيع احتمالات السجلات الخاصة به عليها. يتطلب ذلك علمين إضافيين للخادم، ويجب تعيين top_k، لأن vLLM يحدّ حجم مجموعة المرشحين به:

CUDA_VISIBLE_DEVICES=0 VLLM_SERVER_DEV_MODE=1 vllm serve Qwen/Qwen3-4B \
    --max-model-len 4096 \
    --logprobs-mode processed_logprobs \
    --api-server-count 8 \
    --weight-transfer-config '{"backend":"nccl"}' \
    --return-sampling-mask \
    --enable-scale-out
config = AsyncGRPOConfig(top_p=0.95, top_k=512)

يجعل --return-sampling-mask نظام vLLM يسجّل مجموعة المرشحين (vLLM 0.28 أو أحدث، على مشغّل نماذج V2 الخاص به: VLLM_USE_V2_MODEL_RUNNER=1 إذا رفض الخادم هذا العلم)، بينما يكشف --enable-scale-out نقطة النهاية التي تستقبل الرموز وتُخرجها والتي تُرجع هذه المجموعة. يتحقق العامل من كلا العَلَمَين على الخادم عند بدء التشغيل. لا يمكن لنسخة أقدم من vLLM إرجاع المجموعة، لذا يستمر المدرب في تطبيع التوزيع على كامل المفردات ويصدر تحذيرًا بشأن النسبة المتحيزة.

مركزية الدرجات

احتمالات السجلات (log-probabilities) التي يعيدها الخادم لا تتطابق تمامًا مع تلك الخاصة بمدرّب النموذج: نواة مختلفة، ودقة مختلفة، وسياسة متأخرة بخطوات قليلة. أوزان الأهمية وحدها لا تُصحّح ذلك، لأن ∇θlog⁡πθ \nabla_\theta \log \pi_\theta الرمز المُعيَّن لا تتوسط إلى صفر تحت مُعيّن العينة، لذا فإن كل تحديث يسحب السياسة نحو مُعيّن العينة (توسيط الدرجات). بشكل افتراضي، يطرح المدرّب ذلك التوقع في كل موضع (score_centering=True), يُقدَّر عبر num_sampler_logprobs أكثر الرموز احتمالًا لدى مُعيّن العينة، ويستبعد الرموز التي يقع نسبة الأهمية الخاصة بها مقارنةً بمُعيّن العينة خارج [vllm_importance_sampling_clip_min, vllm_importance_sampling_clip_max]. لذلك، يطلب العامل أعلى احتمالات السجلات لكل رمز مُولَّد من الخادم، والتي يقوم بتسلسلها لكل رمز: قيمة كبيرة لـ num_sampler_logprobs تُبطئ الخادم، و --max-logprobs تحدد ما يقبله. score_centering=False يُدرّب باستخدام الدالة الهدف المقصوصة فقط. sampling/masked_mean هو نسبة الرموز التي استُبعدت بسبب الحدود، و sampling/sampler_mass هو كتلة الاحتمال الخاصة بمُعيّن العينة (sampler) المغطاة بأعلى الرموز احتمالًا.

تُعدّ تسلسلية أعلى قيم الاحتمال اللوغاريتمي (log-probabilities) عملاً يُنفَّذ على وحدة المعالجة المركزية (CPU) في خادم واجهة برمجة التطبيقات (API server) الخاص بـ vLLM، ومع خادم واجهة برمجة التطبيقات المفرد الافتراضي، يُقلّص الإعداد num_sampler_logprobs=8 من إنتاجية التوليد إلى النصف. ابدأ الخادم باستخدام --api-server-count 8 في إصدار vLLM 0.32 أو أحدث: فقد قُيِّس على بطاقة H100 واحدة مع نماذج تتراوح بين 1.5 مليار و7 مليارات معامل، فتكلفة أعلى 8 قيم للوغ-احتمالات لا تتجاوز 3% من إنتاجية التوليد. أما في إصدار vLLM 0.31، فإن نفس العلم (flag) لا يزال يُسبّب خسارة تتراوح بين 20% و40%، وقد تم إصلاح ذلك في المصدر الأصلي عبر vllm-project/vllm#58181.

LoRA

مرّر peft_config لتدريب مُكيّف LoRA بدلاً من النموذج الكامل:

from peft import LoraConfig

trainer = AsyncGRPOTrainer(
    model="Qwen/Qwen3-4B",
    reward_funcs=reward_len,
    train_dataset=dataset,
    peft_config=LoraConfig(r=32, lora_alpha=64, target_modules="all-linear"),
)

يجب أن تحصل كل مزامنة للأوزان على السياسة المحدّثة على الخادم. افتراضيًا، يدمج المدرب المُكيّف (adapter) في النموذج الأساسي ويرسل الأوزان المدمجة كاملة، وهو ما يعادل حوالي 15 غيغابايت لنموذج بحجم 7B في كل مزامنة. ابدأ خادم vLLM باستخدام --enable-lora وسيكتفي بإرسال المُكيّف فقط، أي حوالي 160 ميغابايت عند r=32:

CUDA_VISIBLE_DEVICES=0 VLLM_SERVER_DEV_MODE=1 VLLM_ALLOW_RUNTIME_LORA_UPDATING=1 vllm serve Qwen/Qwen3-4B \
    --max-model-len 4096 \
    --logprobs-mode processed_logprobs \
    --api-server-count 8 \
    --weight-transfer-config '{"backend":"nccl"}' \
    --enable-lora \
    --max-lora-rank 32 \
    --max-loras 6

يعرّف VLLM_ALLOW_RUNTIME_LORA_UPDATING=1 نقطة النهاية التي يرسل إليها المُدرِّب كل مُكيِّف جديد. احتفظ بـ --weight-transfer-config حتى عند استخدام --enable-lora: فمُحدِّد وضع المزامنة يُختار فقط عند بدء المُدرِّب، وحينها يكون الخادم قيد التشغيل بالفعل، وتُعدّ المزامنة المدمجة هي الوضع الاحتياطي.

يجب أن يكون --max-lora-rank أحد القيم التالية: 1, 8, 16, 32, 64, 128, 256, 320, 512. يحدد هذا الخيار أعلى رتبة يمكن للخادم تقديمها، وليس الرتبة التي سيقدمها بالضرورة، لذا فإن مُكيّف r=4 يعمل بشكل سليم تحت حد 8. يجب أن يكون --max-loras مساوياً على الأقل لـ max_staleness + 2: حيث يحتفظ المُدرّب بعدد من إصدارات المُكيّفات يساوي max_staleness + 1 مسجّلة، حتى يتمكن التمرين الذي بدأ تحت سياسة أقدم من الاكتمال تحت تلك السياسة بدلاً من تبديل السياسات في منتصف التوليد، كما يقوم كل مزامنة بتحميل الإصدار التالي قبل تفريغ أقدم إصدار. يتحقق المُدرّب من كلا القيمتين عند بدء التشغيل ويخبرك بالقيم التي يجب إعادة تشغيل الخادم بها.

يحمّل vLLM المُكيّفات من القرص بدلاً من الشبكة، لذا يكتب المُدرّب كل إصدار تحت <output_dir>/.vllm_lora/ ويمنح الخادم المسار. إذا كان الخادم يعمل على جهاز مختلف، فيجب أن يكون ذلك المجلد على نظام ملفات يمكن لكلٍّ منهما رؤيته.

<output_dir>/.vllm_lora/ هو ذاكرة تخزين مؤقتة للخدمة، وليس المكان الذي يُحفظ فيه المُكيّف الذي درّبتَه. فهو يحتفظ فقط بأحدث الإصدارات، ويُحذف كل إصدار بعد فترة وجيزة من خروجه من نافذة الصلاحية. نقاط التفتيش هي ما يحفظ المُكيّف الذي درّبتَه، لذا لا تُعطِلها: مع save_strategy="no"، تنتهي عملية تدريب تستغرق ساعات دون أن تترك أي أثر. كما يجب أن يكون output_dir قابلاً للقراءة من قِبل الخادم، وأن يستمر في الوجود بعد انتهاء المهمة، لذا لن تعمل المساحة المؤقتة المحلية على العقدة، رغم أنها كانت ستُبقي عمليات المزامنة بعيداً عن نظام الملفات المشترك البطيء.

لا يكون مزامنة المُكيِّف (Adapter) أسرع دائمًا. يولّد vLLM بطيئًا بحوالي 1.33–1.39 مرة لكل رمز عند تقديم مُكيِّف LoRA مقارنةً بتقديم الأوزان المدمجة، وعادةً ما يكون التوليد هو ما يهيمن على الوقت الكلي (wall-clock) في التعلم المعزز. ما تحصل عليه مقابل ذلك هو توقف أقصر بكثير عند كل مزامنة، ونحو 1% من عرض نطاق المزامنة. إذا كان معدل إنتاجية التوليد هو عنق الزجاجة لديك، فإن المزامنة المدمجة غالبًا ما تبقى الخيار الأفضل.

تخصيص حلقة النشر

تتم عمليات التوليد والمكافآت والمزايا والتصفية في عملية التمرير (rollout) داخل experimental.async_grpo.AsyncRolloutLoop. لتعديل إحدى هذه العمليات، قم بإنشاء فئة فرعية من الحلقة، ثم تجاوز (override) الطريقة الخاصة بالخطوة المعنية، واضبط الفئة الفرعية كقيمة لـ loop_cls على فئة فرعية من المدرب. لا يتغير منشئ المدرب.

الطريقةتم استدعاءافتراضي
filter_prompt(row_index, row, epoch)مرة واحدة لكل موجه، قبل التوليديقبل كل موجه
generate_one(prompt, tools, group_id)مرة واحدة لكل تمرينحلقة الأدوات متعددة الأدوار
generate_one_turn(prompt_ids)مرة واحدة لكل طلب أخذ عينةطلب واحد من vLLM باستخدام إعدادات أخذ العينات من التهيئة
compute_advantages(group)مرة واحدة لكل مجموعة، بعد جمع المكافآت في group.rewardsالمكافأة المعيارية داخل المجموعة
setup(), close()عند بدء الحلقات وتوقفهالا شيء

على سبيل المثال، منهج يتوقف عن أخذ عينات من الأوامر التي يحلها بالفعل، مع تحديد عتبة في فئة فرعية من التهيئة:

from dataclasses import dataclass

import numpy as np

from trl.experimental.async_grpo import AsyncGRPOConfig, AsyncGRPOTrainer, AsyncRolloutLoop


@dataclass
class CurriculumConfig(AsyncGRPOConfig):
    pass_rate_cap: float = 0.9


class CurriculumRolloutLoop(AsyncRolloutLoop):
    def filter_prompt(self, row_index, row, epoch):
        return self.pass_rates.get(row_index, 0.0) < self.config.pass_rate_cap

    async def setup(self):
        self.pass_rates = {}

    def compute_advantages(self, group):
        scored = group.rewards[~np.isnan(group.rewards)]
        if len(scored):
            self.pass_rates[group.row_index] = float(np.mean(scored > 0))
        return super().compute_advantages(group)


class CurriculumTrainer(AsyncGRPOTrainer):
    loop_cls = CurriculumRolloutLoop

تُجمع المكافآت عبر reward_funcs، والبيئات التي تُعرّف get_reward، وreward الذي يضبطه generate_one المخصص على experimental.async_grpo.Rollout الخاص به: لتقييم بواسطة قاضٍ، مرّر دالة مكافأة غير متزامنة، أو قيّم داخل generate_one. يُنفَّذ compute_advantages لكل مجموعة، بما في ذلك المجموعة التي تُستبعد لاحقًا لأن جميع مكافآتها المُقيَّمة متساوية؛ فالاستبعاد ينظر إلى المكافآت، لا إلى المزايا. يُبنى الحلقة في عملية مولَّدة، لذا عرّف الفئة الفرعية على مستوى الوحدة. أنشئ العملاء في setup، الذي يعمل على حلقة أحداث الحلقة، بدلاً من تجاوز __init__. يُتخطى أي موجه ترفضه filter_prompt لذلك العصر ويُحتسب ضمنه، كما هو الحال مع المجموعة المستبعدة. إذا رفضت كل موجهات العصر، ترمي الحلقة استثناءً.

فلسفة التصميم

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

المقاييس المسجّلة

يمرّ التوليد بعدة مراحل قبل أن يتحول إلى تدرّج. لنلقِ نظرة أولاً على المراحل المختلفة، من الموجه إلى تكوين الدفعة النهائية لدينا:

Dataset row = PROMPT (message list + reward kwargs)
 └─ GROUP                  (1 prompt, `num_generations` rollouts, 1 advantage baseline)
     └─ ROLLOUT            (1 conversation, keyed by `rollout_id`)
         ├─ TURN           (1 vLLM /v1/completions call + tool messages fed back)
         │   └─ TurnRecord (prompt_ids, output_ids, output_log_probs)
         └─ reconcile      (`_chain_to_sequences` classifies drift per turn: CLEAN/REALIGN/FORK)
             └─ SEQUENCE   (≥1 per rollout; new one per fork; dropped if no trained token)
                 └─ SAMPLE (Sequence + group advantage + reward + metrics)

════════════ Trainer process boundary: `rollout_buffer` (mp.Queue) ════════════

                 └─ SAMPLE (Pulled 1 at a time; dropped if staleness > `max_staleness`)
                     └─ ROW            (Planner inserts it into one of `dp` prefix tries, attention-cost-balanced)
                         └─ MICRO-BATCH (`dp` rows, one per rank)
                             └─ PACKED ROW (Collator lays each trie out: unique tokens, depth as `position_ids`)
                                 └─ FORWARD (`compute_loss`, bs=1, padding stripped, FA3 per trie segment)
                     └─ OPTIMIZER STEP (from `grad_accum` micro-batches)

عند قراءتها من الأعلى إلى الأسفل:

  • المجموعة group هي موجه واحد تم توليده num_generations مرات. يتم حساب خط الأساس المميز داخلها، ولهذا السبب تُعد المجموعة هي الوحدة التي يتم تقييمها.
  • التوليد rollout هو محادثة واحدة. يعيد كل دور ترقيم قائمة الرسائل بأكملها، لذا يجب معالجة أي انحراف بين الأدوار في النهاية.
  • يمكن أن يؤدي التوفيق إلى تفرّع مسار واحد إلى عدة سلاسل، ولهذا السبب يمكن أن ينتج عن محادثة واحدة أكثر من عينة تدريب واحدة.
  • يُعدّ عينة تسلسلاً مع فائدتها ومكافأتها ومقاييسها. وهذا ما يعبر عن حد العملية.
  • عند تجاوز الحد، يخطط المدرب العينات إلى صفوف (واحد لكل رتبة DP)، ثم يطوي كل صف في شجرة بادئة (prefix trie) بحيث تُمرَّر الرموز المشتركة مرة واحدة فقط، ويجمع grad_accum من الدُفعات الدقيقة (micro-batches) في خطوة مُحسِّن واحدة.

لذلك نقسم مقاييسنا بناءً على المرحلة (أو الكيان) التي تتعلق بها:

namespaceالكيان الذي يحسبه
rollout/يمثل محادثة كاملة واحدة: جولاتها، وتفرعاتها، ومدى المدة التي استغرقها توليدها
completions/ما ولّده النموذج (vLLM) لموجّه واحد
tools/مقاييس استدعاءات الأدوات
sample/يمثل عينة تدريب واحدة، كما تصل في الطابور
batch/دفعة مصغرة واحدة أو خطوة مُحسِّن واحدة (مبنية من عينة واحدة أو عدة عينات)
perf/الثواني المقاسة وعمليات FLOPs
sampling/مدى ابتعاد السياسة المُدرَّبة عن المُعيّن الذي ولّد الرموز

لنعرّف أيضًا بعض المصطلحات لجعل مقاييس الرموز غير ملتبسة:

  • الرموز المولّدة هي ما أنتجه النموذج (completions/*).
  • الرموز المُعاد توجيهها هي كل رمز يعالجه مسار forward: النص التوجيهي، وأي نتائج للأدوات، والرموز المُولَّدة.
  • الرموز المدربة هي المجموعة الفرعية التي يُحسب عليها الخسارة حيث completion_mask == 1. على سبيل المثال، يمكن أن يؤدي التفرع أو إعادة المحاذاة إلى تخفيض مستوى الرموز المولَّدة مسبقًا إلى سياق، وبالتالي فإن المدربة ≠ المولَّدة.

كيف تتكوّن أرقام الدفعة

الـ صف هو ما يمرّره رتبة واحدة من DP في دفعة مصغّرة واحدة: عدة عينات مُجمَّعة في غابة بادئة واحدة، بحيث تُمرَّر الرموز المشتركة بينها مرة واحدة — راجع تعبئة الشجرة. ويحدد المخطط أيّ العينات تقع في أيّ صف (مع موازنة تكلفة الانتباه حتى لا تتأخر أيّ رتبة)، بينما يتولى مُجمِّع البيانات عملية التعبئة.

في جميع مقاييسنا، يعني مصطلح «خطوة» دائمًا خطوة مُحسِّن كاملة، وليس دفعة فرعية. تُشكّل gradient_accumulation_steps من الدفعات الفرعية خطوة واحدة، وكل مقياس يحمل اسم _per_step يكون لكل خطوة مُحسِّن، بما يتوافق مع global_step وlogging_steps وباقي مصطلحات Trainer. حيث يكون المقياس لكل دفعة فرعية، يُصرَّح بذلك صراحةً (batch/microbatches_per_step) أو يكون كمية لكل صف (batch/row_*، batch/samples_per_row).

لذلك، يحتوي كل خطوة على عدد ثابت من row-slots:

row-slots per step = gradient_accumulation_steps x world_size

مما يجعل مقاييس الدفعة تتكوّن في سلّم يمكنك التحقق من بعضها البعض:

sample                                     sample/forwarded_tokens_mean
  └─ packed into a ROW                     batch/samples_per_row, batch/row_tokens_mean
      └─ one row per DP rank               = one micro-batch
          └─ gradient_accumulation_steps micro-batches = one STEP
                                           batch/samples_per_step, batch/forwarded_tokens_per_step

لذا batch/samples_per_step ≈ row-slots x batch/samples_per_row، وكذلك الأمر بالنسبة للرموز. يتطابق الجانبان فقط حتى مستوى التباين بين الدُفعات الدقيقة داخل الخطوة الواحدة — فمقاييس كل خطوة هي مجموع، بينما مقاييس كل صف هي متوسط — لذا توقع فرقًا بنسبة جزء من المئوية، وليس تطابقًا تامًا.

batch/row_fill_frac هو المؤشر الذي يجب مراقبته عندما تكون العينات طويلة: عينة من 10 آلاف رمز لا تملأ ميزانية 32 ألف رمز بشكل جيد (ثلاث عينات تتسع، وأربع لا تتسع أبدًا، لذا غالبًا ما يحصل الحاصد على عينتين فقط وتكون الصف ممتلئًا بنسبة 77% تقريبًا)، بينما تملأ العينات المكونة من 1000 رمز الميزانية بشكل شبه مثالي. هذا هو التكميم وليس خطأً برمجيًا، وtoken_budget هو العنصر الذي يمكن التحكم به — مع مراعاة أن الانتباه يعمل بتعقيد O(L²) لكل تسلسل، لذا فإن صفًا أكثر امتلاءً من التسلسلات الطويلة لا يستهلك ذاكرة أكثر بشكل خطي.

تعبئة الأشجار

الصف هو شجرة بادئات وليس دمجًا: الرمز المشترك بين عدة عينات يُمرَّر مرة واحدة، ولا يزال الانتباه يُظهر لكل عينة تاريخها الخاص بالضبط. فحالات التوليد لنفس الموجه تتكرر جميعًا، وكل جولة في التوليد متعدد الجولات تعيد إرسال المحادثة، لذا ينخفض عمل المُفكِّك بنسبة نسبة التعبئة (الرموز الخام ÷ الرموز الممرَّرة). إنها تغيير في التخطيط فقط: كل رمز مدرَّب يحتفظ بهدفه الخاص وميزته واحتمال السجل القديم، ويتطابق احتمال سجله مع تمرير العينة بمفردها.

مكان حدوثه:

planner    TreeRow.add            the trie grows sample by sample; a sample is priced by its novel tokens
   │                              (TreeRow.fits), so `token_budget` bounds unique tokens, not raw ones
collator   TreeRow.pack           DFS layout: unique tokens, depth as position_ids, one loss term per
   │                              original trained token (token_index), and per segment its queries and
   │                              the K/V indices of its root-to-segment path, all built on CPU
attention  tree_attention         gather K/V along the paths, one FA3 varlen call, causal

كيف يعمل، على مسارين من تنفيذ موجه واحد:

1. Rollouts             r0:  p1 p2 p3 a1 a2
                        r1:  p1 p2 p3 b1 b2                      10 raw tokens

2. Trie (one per row)   S0 [p1 p2] ─┬─ S1 [p3 a1 a2]          nodes are keyed on (token, next token),
                                   └─ S2 [p3 b1 b2]          so the fork happens one token early and
                                                              every node predicts exactly one token;
                                                              chains without a fork become segments

3. Packed row           idx           0  1 | 2  3  4 | 5  6  7
   (DFS order)          input_ids    p1 p2 | p3 a1 a2 | p3 b1 b2  8 tokens: MLPs, norms and projections
                        position_ids  0  1 |  2  3  4 |  2  3  4  run once per unique token
                        segment      S0    | S1       | S2

4. Attention            seg   queries      K/V gathered            kv_index
   (one FA3 call)       S0    [p1 p2]      [p1 p2]                 0 1
                        S1    [p3 a1 a2]   [p1 p2 | p3 a1 a2]      0 1 2 3 4
                        S2    [p3 b1 b2]   [p1 p2 | p3 b1 b2]      0 1 5 6 7

                        FA3 aligns the causal mask bottom-right      K:  p1 p2 p3 a1 a2
                        when queries are fewer than keys, so a       Q: p3   ■  ■  ■  ·  ·
                        segment's queries see their ancestors and       a1   ■  ■  ■  ■  ·
                        their own causal past, and nothing else.        a2   ■  ■  ■  ■  ■

5. Loss                 p2 (idx 1) predicts p3 for both rollouts; token_index points every trained
                        token of every rollout at the position that predicts it

بعض العواقب:

  • يُشارَك أي بادئة مشتركة: فمسارات التنفيذ لموجّه واحد، وكذلك الموجّه النظامي أو مخطط الأداة المشترك بين الموجّهات. يرسل المخطّط عينةً إلى الصف الذي يحتفظ بالفعل بمعرّف group_id الخاص به، حيث يوجد موجّهه مسبقًا. وعندما يمتلئ ذلك الصف، تنتقل العينة إلى صف آخر إذا كان هناك ترتيب فارغ، أو إذا لم يُسبّب ذلك زيادةً في الصف الأكثر تحميلًا، وهو ما يحدد زمن الدفعة الجزئية؛ وإلا تُغلق الدفعة الجزئية.
  • عدم مشاركة أي شيء يعني التعبئة العادية: حيث يكون كل عينة في هذه الحالة مقطعًا واحدًا يكون مساره هو نفسه، وهي تعبئة FA3 varlen بدون حشو عادية.
  • يتم تكرار K/V فقط: يتم جمع البادئة المشتركة مرة واحدة لكل مقطع فرع، وهو ما يعادل تقريبًا ما يحتفظ به التدريب غير المُفكَّك، وهو صغير في حالة GQA.
  • تُدعَّم هجائن Gated DeltaNet (Qwen3.5, Qwen3.6, Qwen3-Next, …): حيث تقرأ طبقة الالتفاف في كل منها أسلاف الرمز الخاص بها، وتبدأ قاعدة دلتا المقطّعة كل مقطع من الحالة النهائية لوالدها (trl/experimental/async_grpo/tree_gated_delta_rule.py). ويتطلب ذلك transformers>=5.15.0، حيث تستدعي هذه الطبقات الدوال على مستوى الوحدة التي تعيد حزم الشجرة تكييفها. وتُرفض النماذج التي تحتوي على أي طبقة غير انتباه أخرى عند التهيئة.

ما يقدّمه: عند عدم مشاركة أي شيء، يعمل بسرعة تقارب سرعة التعبئة بدون حشو، وتزداد السرعة تقريبًا مع نسبة التعبئة (حوالي 2.8–3 أضعاف عند نسبة 3.4 على Qwen3-0.6B/1.7B، H100). النسبة هي البادئة المشتركة × عدد العينات لكل صف، لذا فإن batch/samples_per_row هو المؤشر الرئيسي: عند اقترابه من 1، لا يمكن مشاركة أي شيء، والعنصر المؤثر هو token_budget.

احكم عليه من حيث الإنتاجية، batch/trained_tokens_per_step / perf/fwd_bwd_s. يحتوي الدُفع المصغّر المُجمَّع على عينات أكثر، لذا يرتفع perf/fwd_bwd_s وينخفض perf/mfu_*، الذي يُقسَّم على الرموز المُرسَلة، — ولا يُعدّ أيٌّ منهما تراجعاً. كما أن وجود عينات أكثر في كل صف يعني سحب المزيد من عمليات التوليد في كل خطوة، مما يجعل التشغيل المعتمد على التوليد أكثر اعتماداً عليه.

أي إجراء يُطيل الصفوف أو يُقلل عددها يُزيل المشاركة. تحقق أولاً من fork_threshold_tokens: لا يتحول الدور إلى صف مستقل إلا عندما ينحرف إعادة الترميز بمقدار ذلك العدد من الرموز، والانحراف في الوكلاء يكون عادةً بعشرات الرموز مقابل القيمة الافتراضية 1024، لذا لا يحدث أي تفرع وتنهار المحادثة إلى صف واحد لكل رتبة. يُظهر rollout/fork_frac النظام الذي تعمل فيه.

قائمة الانتظار للنشر

يدفع العامل العينات المُقيَّمة إلى طابور، بينما يسحب المدرب منها. أربعة مقاييس تصف ذلك الطابور الواحد، وتُجيب عن أسئلة مختلفة:

مقياسسؤال
sample/rollout_queue_sizeكم عدد العينات التي تنتظر الآن
sample/time_in_queue_sمدى المدة التي قضاها عينة واحدة هناك قبل أن تُدرَّب عليها — النصف الثاني من ثوانٍ من عدم توافقها مع السياسة
perf/rollout_wait_sكم من الوقت كان التدريب متوقفًا بسبب كون الطابور فارغًا
rollout/backpressure_sمدى الوقت الذي بقي فيه التوليد (العامل) محجوباً لأن الطابور كان ممتلئاً

المقياسان الأخيران (perf/rollout_wait_s وrollout/backpressure_s) هما انعكاسان لبعضهما البعض ولا يكونان كبيرين معًا أبدًا! قراءة هذين المقياسين معًا مع حجم الطابور تُظهر لك أي الجانب هو عنق الزجاجة:

  • الطابور شبه فارغ، وperf/rollout_wait_s مرتفع → مقيّد بالتوليد. المدرب يعاني من الجوع؛ راجع rollout/generated_tok_s وrollout/concurrency وrollout/score_queue_size.
  • الطابور شبه ممتلئ، وrollout/backpressure_s مرتفع → مقيّد بالمدرب. يتم تقييد التوليد وتعتري مخرجاته العتاقة في الطابور، لذا راقب ارتفاع sample/staleness_mean.
  • كلاهما قريب من الصفر → متوازن!

إكمالات

اكتمال هو ما ولّده vLLM لموجّه واحد، محسوبًا عبر كل جولة من التمرين.

مقياسالمعنى
completions/mean_lengthعدد الرموز المولّدة لكل تمريرة، مُتوسطًا على جميع دوراتها
completions/min_length, completions/max_lengthأقصر وأطول نشر في النافذة
completions/clipped_ratioالنسبة من عمليات التمرين التي لم ينتج فيها الدور الأخير رمز نهاية الجملة (EOS)، أي أنه تم قطعه بواسطة max_completion_length.

التشغيل

التوليد هو محادثة كاملة واحدة: موجه يُولَّد حتى اكتماله، بما في ذلك كل جولة ذهاب وإياب للأدوات التي استُخدمت للوصول إلى ذلك. تتشارك num_generations من عمليات التوليد موجهًا واحدًا وتكوّن مجموعة.

مقياسالمعنى
rollout/duration_sالوقت الفعلي لتمريرة واحدة، من الإرسال حتى تجمع الحلقة التمريرة المكتملة.
rollout/generated_tok_sمعدل الإنتاجية خلال آخر فترة زمنية (نافذة زمنية)، بحيث يظهر أي توقف
rollout/concurrencyعمليات النشر الجارية إلى vLLM.
rollout/turns_mean, rollout/turns_maxمتوسط وأقصى عدد الجولات في المحادثة
rollout/samples_per_rolloutعدد عينات التدريب المُنتَجة لكل محادثة. القيمة 1.0 تعني عدم حدوث أي تفرّع؛ (<1.0 تعني أن بعض المحادثات لم تُنتِ أي عينة قابلة للتدريب على الإطلاق)
rollout/fork_frac, rollout/realign_fracكيف تم تصنيف انحراف إعادة الترميز عند كل حدّ بين الأدوار
rollout/drift_tokens_mean, rollout/drift_tokens_maxعدد الرموز المحفوظة التي ألغتها إعادة الترميز في الجولة. قارن ذلك مع fork_threshold_tokens
rollout/score_queue_sizeالمجموعات المكتملة بانتظار التقييم.
rollout/score_s, rollout/score_wait_s, rollout/score_block_sscoring: الوقت اللازم لتقييم مجموعة، وقت انتظار المجموعة حتى يتم تقييمها، ومدى طول فترة حظر التوليد بسبب امتلاء قائمة الانتظار الخاصة بالتقييم
rollout/vllm_retry_totalطلبات vLLM التي تم إعادة إرسالها. يبدو الخادم المتدهور، في حال عدم وجود هذه الميزة، وكأنه بطء غير مبرر. تم وضعه هنا بدلاً من completions/ لأنه يعدّ الطلبات المرسلة إلى الخادم، وليس النص المولّد: فالطلب الذي تم إعادة إرساله لم يُنتج أي إكمال على الإطلاق.
rollout/backpressure_sمدى المدة التي تم فيها حظر التوليد بسبب امتلاء طابور النشر. راجع طابور النشر
rollout/concurrency_capالحد الأقصى الحالي لعمليات النشر الجارية. يبدأ عند KV cache tokens / max_model_len (بحد أقصى max_concurrent_rollouts) ويتغير مع حمل vLLM. راجع التزامن
rollout/kv_cache_usageاستخدام ذاكرة KV في vLLM (القيمة القصوى عبر المحركات) عند آخر استطلاع. يتم خفض الحد الأقصى عندما يتجاوز 0.8، ويزداد بينما يبقى دون 0.6
rollout/vllm_running_requestsالطلبات التي تقوم محركات الخادم بفك ترميزها (متغير num_requests_running في vLLM، المجموع عبر المحركات). الفارق عن rollout/concurrency هو ما يوجد في عملية خادم الواجهة البرمجية، حيث يتم بناء الاستجابات
rollout/vllm_queued_requestsالطلبات التي قبلها الخادم لكن لم يبرمجها بعد (قيمة num_requests_waiting في vLLM، مجمّعة عبر المحركات). لا يتزايد الحد الأقصى طالما أن هذه القيمة غير صفرية
rollout/vllm_preemptions_totalيطلب من الخادم أن يُسبَق أثناء نافذة التسجيل (مقياس num_preemptions_total الخاص بـ vLLM، المجموع عبر المحركات). يُبلَّغ عنه فقط: فمزامنة الأوزان تعيد ضبط ذاكرة التخزين المؤقت للخادم، مما يؤدي إلى تسبيق كل طلب قيد التنفيذ، وبالتالي لا يُعدّ مؤشراً على الضغط
frac_reward_zero_std, reward_keptنسبة المجموعات التي تم إسقاطها لأن كل مكافأة مُقيَّمة كانت متساوية، أو لأن عدد عمليات التوليف القابلة للتقييم كان أقل من اثنين (يحتسب GRPO الحالة الأولى فقط)، ومتوسط مكافأة المجموعات التي تم التدريب عليها. reward هي مكافأة السياسة عبر كل مجموعة مُقيَّمة، بما في ذلك المجموعات المُسقطة، لذا فهي المقياس الذي يجب تتبعه

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

الأدوات

تُسجَّل فقط عند تنفيذ النموذج للأدوات. يتكرر tools/<name>/* لكل اسم أداة، بنفس الطريقة التي يتكرر بها rewards/<func>/* لكل دالة مكافأة، لأن فشل أداة واحدة يكون غير مرئي في المتوسط العام لجميع الأدوات. يسجّل حلقة الأدوات المدمجة ومدرب إطار OpenEnv (HarnessAsyncGRPOTrainer، انظر التدريب على الأطر) نفس الأسماء، بحيث تقرأ لوحة تحكم واحدة كلا المصدرين؛ وتوضح عمود path المصدر الذي ينتج كل مقياس.

مقياسpathالمعنى
tools/call_frequency, tools/failure_frequencyمدمج، استغلالعدد الاستدعاءات لكل تمريرة، والنسبة التي فشلت. في مسار الإطار المسؤول عن الحلقة، يُعدّ الفشل نتيجة أداة يبدو نصّها كخطأ
tools/latency_s, tools/<name>/latency_sإطار مدمج شفافالوقت المستغرق لتنفيذ الأداة. في مسار إطار العمل الشفاف (white-box harness)، هو الوقت الفعلي (wall time) بين ردّ دورة النموذج وطلب الدورة التالية، ويشمل ذلك أعباء إطار العمل. أما المسار الذي يملك الحلقة فلا يوجد فيه زمن استجابة: لأن أثر OpenEnv لا يُضيف طوابع زمنية إلى مدخلاته، فلا يوجد ما يمكن اشتقاقه منه.
tools/<name>/call_total, tools/<name>/failure_totalمدمج، استغلالعدد استدعاءات الأدوات وعدد حالات الفشل لكل أداة
tools/unknown_name_totalمدمجطلب النموذج أداة غير موجودة: يتتبع خطأً في السياسة، على عكس أداة تم تشغيلها وأثارت
tools/parallel_calls_meanمدمجاستدعاءات الأدوات المطلوبة في رسالة مساعد واحدة
tools/loop_exhausted_fracمدمجالمحادثات التي تنتهي عند max_tool_calling_iterations بينما لا تزال تطلب أدوات

البيئات

يُسجَّل فقط مع environment_factory. تُنفَّذ كلا الاستدعاءين على مجموعة خيالات أدوات العامل، لذا فإن البيئة البطيئة تؤخر تنفيذها الخاص فقط دون التأثير على العمليات الأخرى الجارية.

مقياسالمعنى
env/reset_sالوقت المستغرق في reset() قبل بدء الجولة
env/reward_sالوقت في get_reward() بعد انتهاء الجولة

عينات تصل من الطابور

كل عينة هي RolloutSample: تسلسل مُتوافق مع مجموعة المزايا، والمكافأة ومقاييسها لكل عينة، تُجمّعها الوحدة العاملة في _score_group بمجرد انتهاء كل جيل في المجموعة وتقييمه. تدفع الوحدة العاملة هذه العينات إلى rollout_buffer؛ وكل ما يلي يُقاس على جانب المُدرِّب، حيث يسحبها للتدريب.

مقياسالمعنى
sample/forwarded_tokens_mean, sample/forwarded_tokens_maxالرموز في عينة واحدة: الاستعلام + سياق الأداة + النص المولّد. التعبئة مسألة على مستوى الصف، راجع batch/row_*
sample/trained_tokens_meanمن بين تلك، كم عدد ما يُحسب عليه الخسارة
sample/rollout_queue_sizeعينات مُقيَّمة تنتظر في الطابور
sample/time_in_queue_sمدى المدة التي قضاها هذا العينة في تلك الطابور قبل أن يُدرَّب عليها. ليس هو نفسه perf/rollout_wait_s — راجع طابور النشر
sample/staleness_mean, sample/staleness_maxكم عدد إصدارات السياسة التي تسبق البيانات. يُظهر sampling/importance_sampling_ratio/* وsampling/sampling_logp_difference/* التأثير لكون السياسة غير مطابقة على الخسارة؛ بينما يُظهر هذا السبب
sample/dropped_stale_totalعُزلت عينات لتجاوزها max_staleness

المكافآت وبعيداً عن السياسة

مقياسالمعنى
reward_group_stdانحراف معياري للمكافأة داخل مجموعة كل عينة، مُتوسطًا على العينات التي تم التدريب عليها. وهذا هو ما يقسم عليه compute_advantages الافتراضي. أما reward_std في GRPO فهو الانحراف المعياري على الدفعة بأكملها، وهو كمية مختلفة: فدفعة تحتوي على موجهات سهلة كلها عند 1 وموجهات صعبة كلها عند 0 يكون انحرافها المعياري على مستوى الدفعة 0.5 بينما يكون انحرافها المعياري على مستوى المجموعة 0
rewards/<func>/mean, rewards/<func>/group_stdمتوسط كل دالة مكافأة، وانحرافها المعياري داخل مجموعة كل عينة، مُتوسطًا على العينات التي تم التدريب عليها. أما rewards/<func>/mean في GRPO فهو متوسط على كل إكمال مُولّد في الدفعة، وrewards/<func>/std هو الانحراف المعياري على الدفعة
sampling/importance_sampling_ratio/mean, /min, /maxπ_θ / π_sampler لكل رمز إكمال، حيث π_sampler هو سياسة vLLM التي أُنشئ بها. يتضمن ذلك التقادم، وليس فقط عدم التطابق بين التدريب والاستدلال
sampling/sampling_logp_difference/mean, /max\|log π_θ − log π_sampler\| لكل رمز إكمال
num_tokensالرموز المُرسَلة منذ بدء التدريب. مع تعبئة الشجرة، يُحتسب البادئة المشتركة بين عدة عينات مرة واحدة

الدفعات

تتكوّن كل دفعة فرعية مصغّرة من world_size صفوف (تذكّر أن التعبئة تسطّح البيانات في تسلسل واحد)، أي صف واحد لكل رتبة من رتب التوازي، بحيث تمرّر الرتبة i الصف i. وتُشكّل gradient_accumulation_steps من هذه الدفعات خطوة واحدة لمُحسِّن المعاملات. وتغطي الخطوة إجمالاً gradient_accumulation_steps × world_size صفًا. وكل مقياس من مقاييس _per_step أدناه هو مجموع على مدى الخطوة كاملة وعبر كل الرتب؛ أما مقاييس batch/row_* فهي متوسطات على الصفوف.

مقياسالمعنى
batch/forwarded_tokens_per_step, batch/trained_tokens_per_stepالرموز في خطوة واحدة من المُحسِّن، مُرسَلة ومدرَّبة على التوالي
batch/samples_per_step, batch/groups_per_stepعينات التدريب، والأوامر المميزة، لكل خطوة من خطوات المُحسِّن. تختلف هذه القيم حسب معدل التفرّع
batch/microbatches_per_stepيتم احتسابها، وليس قراءتها من ملف الإعدادات
batch/masked_token_fracالرموز المُعاد توجيهها التي completion_mask == 0 — وهي الحصة من التمرير الأمامي التي لا تحقق أي تدرج
batch/samples_per_row, batch/row_tokens_mean, batch/row_tokens_maxكثافة تعبئة المخطط لصف كل رتبة
batch/row_fill_fracrow tokens مقابل token_budget. القيمة المنخفضة تعني أن الميزانية غير مستخدمة
batch/row_imbalancemax cost / mean cost عبر الصفوف، حيث التكلفة هي عمل الانتباه الخاص بالصف. يتنبأ هذا بالرتبة التي ستُبطئ عملية تجميع التدرجات (all-reduce). القيمة 1.0 مثالية
batch/packing_ratioرموز خام لكل رمز مُعاد توجيهه: العامل الذي تتقلص به مهمة المُفكِّك، وقيمته 1.0 عندما لا يوجد شيء مشترك
batch/pad_fracالحشو بين الرتب. تكلفته بايتات البث فقط؛ يتم إزالته قبل التمرير الأمامي
batch/dropped_oversize_totalعُزلت عينات لتجاوزها token_budget

الأداء

تقيس الإنتاجية عدد الرموز التي يعالجها المدرب في الثانية. استغلال عمليات النموذج (MFU) يقدّر النسبة المئوية من القدرة الحسابية النظرية لأجهزة التدريب المستخدمة في عمليات النموذج الأمامية والعكسية. تعتمد القدرة المستخدمة في هذا التقدير على العتاد ودقة التدريب.

يُبلَّغ عن معدل الإنتاجية وMFU على أساسَي زمنَين:

  • _fwd_bwd يقيس الأداء خلال المرورين الأمامي والخلفي.
  • _wall_clock يقيس الأداء على مدى خطوة المُحسِّن الكاملة، بما في ذلك تحديثات المُحسِّن، ومزامنة الأوزان، والوقت المنقضي في انتظار النتائج.

يساعد هذا الفرق في التمييز بين أداء الحساب وتكلفة الانتظار والتنسيق. تصف كلا مقياسي MFU أجهزة التدريب فقط: فهي لا تشمل قدرات الحساب أو العتاد لخوادم النشر الخارجي أو الخوادم المعلمة. يعكس مقياس MFU الزمني الفعلي الوقت الذي يقضيه المدرب في الانتظار على تلك الخدمات، وليس معدل استخدام تلك الخدمات نفسها.

يُبلَّغ عن MFU فقط عندما تكون سعة الحوسبة القصوى معروفة لجهاز التدريب المحلي عند الدقة المختارة. وإلا، يُستثنى MFU؛ يستمر التدريب وتبقى مقاييس الإنتاجية والتوقيت متاحة.

مقياسالمعنى
perf/step_sالوقت الفعلي بين خطوات المُحسِّن: يتضمن حسابات، المُحسِّن، مزامنة الأوزان وانتظار الطابور
perf/fwd_bwd_sالمرور الأمامي + الخلفي، المجموع عبر الدُفعات الدقيقة للخطوة. هذا هو المقام لكل مقياس _fwd_bwd أدناه
perf/fwd_sالجزء الأمامي منها. fwd_s / fwd_bwd_s بالقرب من 1/3 هو التقسيم المعتاد؛ والقيمة الأعلى تعني أن العملية العكسية رخيصة أو أن إعادة الحساب تُدفع في الجزء الأمامي
perf/optimizer_soptimizer.step()
perf/rollout_wait_sمدى الوقت الذي بقي فيه المدرب محجوباً بسبب كون قائمة الانتظار فارغة. راجع قائمة الانتظار للتوزيع
perf/weight_sync_sمزامنة كاملة، بالإضافة إلى _pause_s (انتظار vLLM)، و_barrier_s (انحراف الترتيب)، و_transfer_s (البايتات)
perf/forwarded_tok_s_fwd_bwd, perf/forwarded_tok_s_wall_clockالرموز المحوّلة في الثانية على كل أساس
perf/trained_tok_s_wall_clockنفس الشيء، مع احتساب الرموز التي رصدها الخسارة فقط
perf/mfu_fwd_bwd, perf/mfu_wall_clockاستخدام FLOPs للنموذج على كل أساس

AsyncGRPOConfig

فئة trl.experimental.async_grpo.AsyncGRPOConfig

< >

( output_dir: str | None = Noneper_device_train_batch_size: int = 8num_train_epochs: float = 3.0max_steps: int = -1learning_rate: float = 1e-06lr_scheduler_type: str = 'constant'lr_scheduler_kwargs: dict | str | None = Nonewarmup_steps: float = 0optim: transformers.training_args.OptimizerNames | str = 'adamw_torch_fused'optim_args: str | None = Noneweight_decay: float = 0.0adam_beta1: float = 0.9adam_beta2: float = 0.999adam_epsilon: float = 1e-08optim_target_modules: None | str | list[str] = Nonegradient_accumulation_steps: int = 1average_tokens_across_devices: bool = Truemax_grad_norm: float = 1.0label_smoothing_factor: float = 0.0bf16: bool | None = Nonefp16: bool = Falsebf16_full_eval: bool = Falsefp16_full_eval: bool = Falsetf32: bool | None = Nonegradient_checkpointing: bool = Truegradient_checkpointing_kwargs: dict[str, typing.Any] | str | None = Nonetorch_compile: bool = Falsetorch_compile_backend: str | None = Nonetorch_compile_mode: str | None = Noneuse_liger_kernel: bool = Falseliger_kernel_config: dict[str, bool] | None = Noneuse_cache: bool = Falseneftune_noise_alpha: float | None = Nonetorch_empty_cache_steps: int | None = Noneauto_find_batch_size: bool = Falselogging_strategy: transformers.trainer_utils.IntervalStrategy | str = 'steps'logging_steps: float = 1logging_first_step: bool = Falselog_on_each_node: bool = Truelogging_nan_inf_filter: bool = Trueinclude_num_input_tokens_seen: str | bool = 'no'log_level: str = 'passive'log_level_replica: str = 'warning'disable_tqdm: bool | None = Nonereport_to: None | str | list[str] = 'none'run_name: str | None = Noneproject: str = 'huggingface'trackio_space_id: str | None = Nonetrackio_bucket_id: str | None = Nonetrackio_static_space_id: typing.Union[str, NoneType, typing.Literal[False]] = Noneeval_strategy: transformers.trainer_utils.IntervalStrategy | str = 'no'eval_steps: float | None = Noneeval_delay: float = 0per_device_eval_batch_size: int = 8prediction_loss_only: bool = Falseeval_on_start: bool = Falseeval_do_concat_batches: bool = Trueeval_use_gather_object: bool = Falseeval_accumulation_steps: int | None = Noneinclude_for_metrics: list[str] = <factory>batch_eval_metrics: bool = Falsesave_only_model: bool = Falsesave_strategy: transformers.trainer_utils.SaveStrategy | str = 'steps'save_steps: float = 500save_on_each_node: bool = Falsesave_total_limit: int | None = Noneenable_jit_checkpoint: bool = Falsepush_to_hub: bool = Falsehub_token: str | None = Nonehub_private_repo: bool | None = Nonehub_model_id: str | None = Nonehub_strategy: transformers.trainer_utils.HubStrategy | str = 'every_save'hub_always_push: bool = Falsehub_revision: str | None = Noneload_best_model_at_end: bool = Falsemetric_for_best_model: str | None = Nonegreater_is_better: bool | None = Noneignore_data_skip: bool = Truerestore_callback_states_from_checkpoint: bool = Falsefull_determinism: bool = Falseseed: int = 42data_seed: int | None = Noneuse_cpu: bool = Falseaccelerator_config: dict | str | None = Noneparallelism_config: accelerate.parallelism_config.ParallelismConfig | None = Nonedataloader_drop_last: bool = Falsedataloader_num_workers: int = 0dataloader_pin_memory: bool = Truedataloader_persistent_workers: bool = Falsedataloader_prefetch_factor: int | None = Nonedataloader_multiprocessing_context: str | None = Nonedataloader_in_order: bool = Trueremove_unused_columns: bool = Truelabel_names: list[str] | None = Nonetrain_sampling_strategy: str = 'random'length_column_name: str = 'length'ddp_find_unused_parameters: bool | None = Noneddp_bucket_cap_mb: int | None = Noneddp_broadcast_buffers: bool | None = Noneddp_static_graph: bool | None = Noneddp_backend: str | None = Noneddp_timeout: int = 1800fsdp: str | None = Nonefsdp_config: dict[str, typing.Any] | str | None = Nonedeepspeed: dict | str | None = Nonedebug: str | list[transformers.debug_utils.DebugOption] = ''skip_memory_metrics: bool = Truedo_train: bool = Falsedo_eval: bool = Falsedo_predict: bool = Falseresume_from_checkpoint: str | None = Nonelocal_rank: int = -1model_init_kwargs: dict[str, typing.Any] | str | None = Nonedtype: str = 'float32'trust_remote_code: bool = Falserouter_aux_loss_coef: float | None = Nonenum_generations: int = 8max_completion_length: int = 2048temperature: float = 1.0top_p: float = 1.0top_k: int = 0min_p: float | None = Nonerepetition_penalty: float = 1.0chat_template_kwargs: dict | str | None = Nonemax_tool_calling_iterations: int | None = Nonefork_threshold_tokens: int = 1024vllm_server_base_url: str = 'http://localhost:8000'vllm_server_timeout: float = 1800.0epsilon: float = 0.2epsilon_high: float | None = Nonescore_centering: bool = Truevllm_importance_sampling_clip_min: float = 0.5vllm_importance_sampling_clip_max: float = 5.0num_sampler_logprobs: int = 8token_budget: int | None = Nonemax_concurrent_rollouts: int | None = Nonemax_staleness: int = 4queue_maxsize: int = 1024weight_sync_steps: int = 1rollout_worker_timeout: float = 300.0log_completions: bool = Falsenum_completions_to_print: int | None = None )

المعاملات التي تتحكم في النموذج

  • model_init_kwargs (dict[str, Any] أو str، اختياري) — حجج الكلمات المفتاحية لـ from_pretrained، تُستخدم عند إنشاء النموذج من مسار. تُستخدم قيمة revision أيضًا عند تحميل فئة المعالجة.
  • dtype (str, اختياري, الافتراضي هو "float32") — نوع البيانات الذي يُحمَّل به النموذج، وهو أحد "auto", "bfloat16", "float16" أو "float32". الافتراضي له "float32" لأن عدم التطابق بين التدريب والاستدلال الذي يُقاس عليه هذا المُدرِّب (تجاوز عدم التطابق بين التدريب والاستدلال عبر FP16, ، الذي تم شرحه لهذا المُدرِّب في تجاوز عدم تطابق الدقة بين المُدرِّب والمولِّد في TRL) ) حساس لدقة المُدرِّب نفسه. وإغلاق هذه الفجوة من البداية إلى النهاية يتطلب أيضًا تشغيل خادم vLLM بنفس نوع البيانات (dtype) (vllm serve --dtype); أي عدم تطابق يُسجَّل كتحذير عند بدء التدريب. و dtype في model_init_kwargs يتمتع بأولوية.

    هذا يضبط فقط نوع البيانات (dtype) الذي تُحمَّل به الأوزان. عند استخدام FSDP مع الدقة المختلطة (الافتراضي هو bf16=True)، يقوم accelerate بترقية كل معامل قابل للتدريب إلى fp32 قبل التقسيم، لذا فإن الأوزان الرئيسية وحالة المُحسِّن تكون من نوع fp32 بغض النظر عما يقوله dtype، بينما يتم تنفيذ التقدّم والتراجع في bf16 أو fp16. ثم تُكتب نقاط التفتيش (Checkpoints) في نوع البيانات الخاص بالدقة المختلطة، وليس في fp32. بدون FSDP لا يحدث أي ترقية: استخدام dtype="bfloat16" مع bf16=True يحافظ على أوزان وحالات مُحسِّن من نوع bf16، وهو ما يمثل تدريبًا خالصًا في bf16.

  • trust_remote_code (bool, optional, defaults to False) — Whether to allow loading models and tokenizers that ship custom Python code from the Hub. Forwarded to from_pretrained and from_pretrained.
  • router_aux_loss_coef (float, اختياري) — معامل خسارة التوازن على الأحمال المساعدة لنماذج مزيج الخبراء (MoE)، تُضاف إلى خسارة التدريب بهذا الوزن. عند عدم تعيينه، يُستخدم القيمة المُعلنة في إعدادات النموذج. عيّن 0.0 لتعطيله. يفشل عند استخدامه مع نموذج غير MoE.

المعاملات التي تتحكم في التوليد

  • num_generations (int، اختياري، القيمة الافتراضية 8) — عدد الأجيال التي يتم أخذ عينات منها لكل موجه.
  • max_completion_length (int، اختياري، القيمة الافتراضية 2048) — الحد الأقصى لطول الإكمال المولّد.
  • temperature (float، اختياري، القيمة الافتراضية 1.0) — درجة الحرارة للعينات. كلما زادت درجة الحرارة، زادت عشوائية المكملات.
  • top_p (float، اختياري، القيمة الافتراضية 1.0) — قيمة عشرية تتحكم في الاحتمال التراكمي لأعلى الرموز المراد أخذها في الاعتبار. يجب أن تكون ضمن المجال (0، 1]. اضبطها على 1.0 لاعتبار جميع الرموز. إذا كانت أقل من 1.0، فيجب ضبط top_k أيضًا، ويجب تشغيل خادم vLLM (>= 0.28) باستخدام --return-sampling-mask --enable-scale-out: حيث يعيد المدرب تطبيع احتمالاته اللوغاريتمية على مجموعة المرشحين التي تم أخذ كل رمز منها، تمامًا كما يفعل الخادم. أما إصدارات vLLM الأقدم فتحتفظ بالمفردات الكاملة.
  • top_k (int، اختياري، القيمة الافتراضية 0) — عدد رموز المفردات ذات أعلى احتمالات التي يجب الاحتفاظ بها لتصفية top-k. إذا كانت القيمة 0، يتم تعطيل تصفية top-k وتُعتبر جميع الرموز. أي قيمة أخرى تتطلب أعلام الخادم الموصوفة تحت top_p.
  • min_p (float, اختياري) — أدنى احتمال للرمز، والذي يُضرب في احتمال الرمز الأكثر احتمالاً. يجب أن يكون قيمة بين 0.0 و 1.0. القيم النموذجية تقع في نطاق 0.01-0.2. عند تجاوز 0.0، يجب ضبط top_k أيضاً، مع أعلام الخادم الموصوفة تحت top_p.
  • repetition_penalty (float، اختياري، القيمة الافتراضية 1.0) — قيمة عشرية تعاقب الرموز الجديدة بناءً على ما إذا كانت تظهر في الاستعلام والنص المولَّد حتى الآن. القيم > 1.0 تشجع النموذج على استخدام رموز جديدة، بينما القيم < 1.0 تشجع النموذج على تكرار الرموز.
  • chat_template_kwargs (dict[str, Any]، اختياري) — معلمات إضافية بالكلمات المفتاحية تُمرَّر إلى دالة apply_chat_template عند توليد الإكمالات.
  • max_tool_calling_iterations (int, اختياري) — الحد الأقصى لعدد جولات استدعاء الأدوات عند تدريب وكيل. إذا كانت None، فلا يوجد حد، ويتوقف التوليد عندما يولّد النموذج ردًا في جولة دون أي استدعاءات للأدوات، أو عندما يبلغ طول الرد الإجمالي max_completion_length.
  • fork_threshold_tokens (int، اختياري، القيمة الافتراضية 1024) — يتم تحويل محادثة متعددة الأدوار إلى صفوف تدريب عن طريق إعادة توكنيز المحادثة بأكملها في كل دور ومطابقة النتيجة مع الرموز المحفوظة حتى الآن: يبقى الإضافة النظيفة صفًا واحدًا، بينما يؤدي إعادة الكتابة (حذف الاستدلال، تلخيص السجل) إلى تفرع صف جديد. عندما ينحرف موجه الدور المُعاد توكنيزه داخل آخر إجابة مُولَّدة، يُتخذ القرار بناءً على حجم الانحراف — أي عدد الرموز المدرَّبة سابقًا التي ستُخفى كسياق عند إعادة المحاذاة. يُعامل الانحراف الأصغر من هذا العدد من الرموز كتذبذب في إعادة التوكنيز (يُعاد محاذاته كسياق)؛ أما الانحراف الأكبر — مثل كتلة استدلال طويلة تُسقطها القالب — فيُفرع صفًا جديدًا حتى تحتفظ تلك الرموز المدرَّبة بإشارة التدريب بدلاً من أن تُخفى بصمت.

المعاملات التي تتحكم في خادم vLLM

  • vllm_server_base_url (str، اختياري، القيمة الافتراضية "http --//localhost:8000"): العنوان الأساسي لخادم vLLM المستخدم للتوليد (مثل "http://localhost:8000").
  • vllm_server_timeout (float, اختياري، القيمة الافتراضية 1800.0) — مهلة بالثواني للاتصالات مع خادم vLLM: انتظار جهوزيته عند الإقلاع، كل طلب توليد، وكل استدعاء مزامنة الأوزان. يرفع خطأ عند انتهاء المهلة في انتظار الخادم واستدعاءات مزامنة الأوزان؛ أما طلب التوليد الذي تتجاوز مدته المهلة فيُعاد.

المعاملات التي تتحكم في التدريب

  • epsilon (float، اختياري، القيمة الافتراضية 0.2) — قيمة إيبسلون للقص.
  • epsilon_high (float, اختياري) — قيمة إبسيلون الحد الأعلى للتقليم. إذا لم يتم تحديدها، فإن القيمة الافتراضية هي نفس قيمة الحد الأدنى المحددة في الحجة epsilon. يوصي الورق DAPO بقيمة 0.28.
  • score_centering (bool، اختياري، القيمة الافتراضية True) — ما إذا كان سيتم التدريب مع توسيط الدرجات (الورقة) بدلاً من الهدف المقطوع: الدرجة المرجّحة بأهمية كل رمز مُستخرج مطروحاً منها توقعها تحت مُستخرج vLLM، بحيث لا تسحب ميزة ثابتة السياسة نحو المُستخرج. يُؤخذ التوقع على num_sampler_logprobs من أكثر الرموز احتمالاً في كل موضع، والتي يبلغ المُستخرج عن احتمالاتها اللوغاريتمية.
  • vllm_importance_sampling_clip_min (float, اختياري، القيمة الافتراضية 0.5) — الحد الأدنى C_min لنسبة الأهمية بين السياسة ومُعيّن vLLM. يتم استبعاد الرموز التي تقع نسبة أهميتها خارج النطاق [vllm_importance_sampling_clip_min, vllm_importance_sampling_clip_max] من دالة الخسارة (أخذ عينات الأهمية المقنّعة).
  • vllm_importance_sampling_clip_max (float، اختياري، القيمة الافتراضية 5.0) — الحد الأعلى C_max لنسبة الأهمية.
  • num_sampler_logprobs (int، اختياري، القيمة الافتراضية 8) — عدد أعلى قيم الاحتمال اللوغاريتمي (log-probabilities) المطلوبة من مُعيّن vLLM لكل رمز مُولَّد، وتُستخدم في عملية توسيط الدرجات. كلما زاد العدد، غطّى كتلة احتمالات المُعيّن بشكل أكبر، لكنه تكلّف أكثر في التسلسل (serialization)؛ ويحدّ من قيمته خادم --max-logprobs.
  • token_budget (int, اختياري) — الحد الأقصى لعدد الرموز المُرسلة في صف واحد (تمريرة أمامية لرتبة DP واحدة) لتجميع الميكرو-دفعات الديناميكي القائم على ميزانية الرموز. عندما يكون > 0، يُشكّل TokenBudgetBatcher ميكرو-دفعات متوازنة من حيث تكلفة الانتباه، بحيث تبقى كل صفوفها ضمن هذه الميزانية، مما يحدّ من ذروة الذاكرة بشكل مستقل عن عدد العينات (حيث يصبح عدد العينات لكل صف ديناميكيًا). تحدّ الميزانية من الرموز الفريدة وليس من الرموز الخام، لذا تُحتسب الرموز المشتركة بين عدة عينات مرة واحدة فقط، كما تحدّ من حدود الخسارة للصف أيضًا. إذا كانت None (الافتراضي)، يتم تعيينها إلى max_model_len لخادم vLLM (يتم الاستعلام عنه عند بدء التدريب) — وهو الحد الأقصى لطول الاستدعاء + الإكمال — بحيث لا يمكن لأي عينة rollout أن تتجاوز الميزانية أبدًا. العينة الأطول من token_budget لا تتسع في أي صف وتُستبعد مع تحذير. اضبط <= 0 لتعطيل ميزانية الرموز وبدلاً من ذلك حزم عدد ثابت من العينات per_device_train_batch_size × num_processes لكل ميكرو-دفعة، متوازنة عبر الصفوف.

المعاملات التي تتحكم في خط أنابيب النشر غير المتزامن

  • max_concurrent_rollouts (int, اختياري) — الحد الأقصى لعدد عمليات التوليد (rollouts) الجارية في وقت واحد إلى خادم vLLM. إذا كانت None, ، يتم ضبطه على `max(max_staleness, 1)` `per_device_train_batch_size` × `gradient_accumulation_steps` × `num_processes`: توليد عدد أكبر من العينات من هذا الحد يُعدّ هدرًا، نظرًا لأنها تُستبعد كعناصر قديمة قبل أن يتمكن المدرب من استهلاكها. إذا كنت تستخدم بيئات استخدام الأدوات، فقد ترغب في ضبط هذا الإعداد يدويًا بناءً على عدد البيئات المتوازية التي يمكنك تشغيلها.
    • per_device_train_batch_size gradient_accumulation_steps num_processes`: توليد عينات أكثر من هذا العدد يُعدّ هدرًا، إذ تُستبعد كعناصر قديمة قبل أن يتمكن المُدرِّب من استهلاكها. إذا كنت تستخدم بيئات استخدام الأدوات، فقد ترغب في ضبط هذا الإعداد يدويًا بناءً على عدد البيئات المتوازية التي يمكنك تشغيلها.
  • max_staleness (int، اختياري، القيمة الافتراضية 4) — الحد الأقصى لعدد خطوات تحديث الأوزان التي يمكن أن يتأخر عنها عينة rollout عن النسخة الحالية من النموذج قبل أن تُستبعد.
  • queue_maxsize (int، اختياري، القيمة الافتراضية 1024) — الحد الأقصى لعدد عينات rollout التي يتم تخزينها مؤقتًا في طابور rollout.
  • weight_sync_steps (int، اختياري، القيمة الافتراضية 1) — عدد خطوات التدريب بين مزامنات الأوزان إلى خادم vLLM.
  • rollout_worker_timeout (float, اختياري، القيمة الافتراضية 300.0) — عدد الثواني منذ آخر نبضة قلب من عامل التمرير (rollout worker) قبل أن يعتبر المدرب العامل متوقفًا عن الاستجابة ويُلغي العملية.

المعاملات التي تتحكم في التسجيل

  • log_completions (bool، اختياري، القيمة الافتراضية False) — ما إذا كان سيتم تسجيل عينة من أزواج (الموجّه، الإكمال) كل logging_steps خطوات.
  • num_completions_to_print (int, اختياري) — عدد الإكمالات التي سيتم طباعتها باستخدام rich. إذا كانت None، فسيتم تسجيل جميع الإكمالات.

فئة التهيئة الخاصة بـ experimental.async_grpo.AsyncGRPOTrainer.

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

تتميز هذه المعلمات بقيم افتراضية مختلفة عن TrainingArguments:

  • logging_steps: القيمة الافتراضية هي 1 بدلاً من 500.
  • gradient_checkpointing: القيمة الافتراضية هي True بدلاً من False.
  • bf16: القيمة الافتراضية هي True إذا لم يتم تعيين fp16، بدلاً من False.
  • learning_rate: القيمة الافتراضية هي 1e-6 بدلاً من 5e-5.
  • lr_scheduler_type: القيمة الافتراضية هي constant بدلاً من linear (انظر أدناه).
  • ignore_data_skip: القيمة الافتراضية هي True بدلاً من False؛ حلقة التخطي وإعادة التشغيل الخاصة بـ Trainer الأساسي لا تنطبق على طابور rollout غير المتزامن.

مدة التدريب ومعدل التعلم في وضع المصالحة القائم على الرسائل: يمكن أن تتفرع محادثة متعددة الأدوار إلى عدد متغير من صفوف التدريب (حيث يبدأ إعادة كتابة المحادثة صفًا جديدًا)، لذا فإن عدد العينات، وبالتالي عدد خطوات المُحسِّن، لكل حقبة غير معروف مسبقًا. ونتيجةً لذلك:

  • num_train_epochs يحدد التدريب بعدد الدورات الكاملة على مجموعة بيانات prompt، حيث يُحسب العدد بناءً على عدد الأوامر المميزة التي تم التدريب عليها فعليًا. وهذا مستقل عن عدد الصفوف التي تنتجها الفروع، لذا فإن طلب N دورة يعني دائمًا التدريب على N مرور على البيانات. عند ترك max_steps غير مُعيَّن، يكون هذا هو شرط التوقف، بينما max_steps مجرد حد أمان.
  • max_steps، إذا تم تعيينه بشكل صريح (> 0)، يصبح شرط التوقف (حيث يُحدَّد التوقف بناءً على خطوات المُحسِّن بدلاً من الفترات) ويعطّل شرط التوقف القائم على الفترات.
  • lr_scheduler_type افتراضيًا constant لأن أفق التلاشي يُقاس بخطوات المُحسِّن، والتي لا يمكن معرفتها مسبقًا عندما يعتمد عدد الخطوات على معدل التفرع. لمعدل تعلّم متلاشٍ، اضبط جدولًا متلاشيًا معًا مع max_steps صريح.

AsyncGRPOTrainer

فئة trl.experimental.async_grpo.AsyncGRPOTrainer

< >

( model: str | PreTrainedModelreward_funcs: collections.abc.Callable[..., list[float]] | list[collections.abc.Callable[..., list[float]]] | None = Noneargs: trl.experimental.async_grpo.async_grpo_config.AsyncGRPOConfig | None = Nonetrain_dataset: datasets.arrow_dataset.Dataset | datasets.iterable_dataset.IterableDataset | None = Noneprocessing_class: transformers.tokenization_utils_base.PreTrainedTokenizerBase | None = Nonecallbacks: list[transformers.trainer_callback.TrainerCallback] | None = Noneoptimizers: tuple[typing.Optional[torch.optim.Optimizer], typing.Optional[torch.optim.lr_scheduler.LambdaLR]] = (None, None)peft_config: PeftConfig | None = Nonetools: list[collections.abc.Callable] | None = Noneenvironment_factory: collections.abc.Callable[[], trl.experimental.async_grpo.async_grpo_trainer._SupportsReset] | dict[str, collections.abc.Callable[[], trl.experimental.async_grpo.async_grpo_trainer._SupportsReset]] | None = None )

المعاملات

  • model (str أو PreTrainedModel) — النموذج المراد تدريبه. يمكن أن يكون أحد ما يلي:
    • سلسلة نصية، تكون معرف النموذج لنموذج مُدرَّب مسبقًا مستضاف داخل مستودع نماذج على huggingface.co، أو مسارًا إلى مجلد يحتوي على أوزان النموذج المحفوظة باستخدام save_pretrained، مثل './my_model_directory/'. يتم تحميل النموذج مع البنية المُعلنة في ملفه الإعدادي: AutoModelForImageTextToText لنقطة تحقق لغوية-بصرية (حيث يتم تحميل برج الرؤية الخاص به لكنه مجمّد، راجع النماذج اللغوية-البصرية)، وAutoModelForCausalLM في الحالات الأخرى.
    • كائن PreTrainedModel. يتم تبديل تنفيذ الانتباه فيه إلى واجهة الانتباه الشجري الخاصة بالمدرّب للتدريب المعبأ.

    يُستخدم اسم النموذج من ملف الإعداد لتحديد النموذج على خادم vLLM المستخدم للتوليد.

  • reward_funcs (RewardFunc | list[RewardFunc], اختياري) — دوال المكافأة المستخدمة لحساب المكافآت. لحساب المكافآت، نستدعي جميع دوال المكافأة باستخدام الأوامر (prompts) والإكمالات (completions) ثم نجمع المكافآت. يمكن تجاهلها عندما تُوفَّر المكافأة من خلال البيئة عبر environment_factory (انظر أدناه). يمكن أن تكون:
    • دالة مكافأة واحدة: تُزوَّد الدالة بالموجِّهات (prompts) والإكمالات المولَّدة، بالإضافة إلى أي أعمدة إضافية في مجموعة البيانات. يجب أن تُرجع قائمة بالمكافآت. يمكن أن تكون دوال المكافأة متزامنة أو غير متزامنة، كما يمكنها أن تُرجع None عندما لا تنطبق المكافأة على تلك العينات. وهذا مفيد في التدريب متعدد المهام حيث تنطبق دوال مكافأة مختلفة على أنواع مختلفة من العينات. عندما تُرجع دالة مكافأة None لعينة معينة، تُستبعد تلك الدالة من حساب المكافأة لتلك العينة. لمزيد من التفاصيل، راجع استخدام دالة مكافأة مخصصة.
    • قائمة من دوال المكافأة، حيث يكون كل عنصر دالة مكافأة كما هو موصوف أعلاه. تُجمع المكافآت من جميع الدوال.

    على عكس GRPOTrainer، تُحسب المكافآت في عملية فرعية مُنشأة، لذا يجب أن تكون كل دالة مكافأة (إلى جانب tools وenvironment_factory) قابلة للتسلسل (picklable): استخدم دالة على مستوى الوحدة (module-level function)، أو functools.partial، أو كائن فئة قابل للاستدعاء — فالدوال اللامدا (lambdas) والإغلاقات (closures) ستفشل عند بدء التشغيل. تُسجَّل الأدوات تحت اسم __name__ الخاص بها، لذا يجب أن تكون دوالاً على مستوى الوحدة. كما تعمل العملية الفرعية مع CUDA_VISIBLE_DEVICES=""، لذا يعمل نموذج المكافأة المدعوم بوحدة معالجة رسومية (GPU) على وحدة المعالجة المركزية (CPU) (بطيئاً)، وليس على وحدة معالجة الرسومات الخاصة بالمدرب.

  • args (experimental.async_grpo.AsyncGRPOConfig، اختياري) — إعدادات لهذا المدرب. إذا كانت None، يتم استخدام إعداد افتراضي.
  • train_dataset (Dataset أو IterableDataset, اختياري) — مجموعة البيانات المستخدمة للتدريب. يجب أن تتضمن عمودًا "prompt". أي الأعمدة الإضافية في مجموعة البيانات تُتجاهل. يمكن أن يكون تنسيق العينات إما:
    • قياسي: يحتوي كل عينة على نص عادي.
    • حواري: تحتوي كل عينة على رسائل منظمة (مثل الدور والمحتوى).

    يمكن حذفه فقط عند توفير environment_factory وامتلاك البيئة (أو توليدها إجرائيًا) للبيانات، مع إرجاع الأمر التوجيهي من طريقة reset() الخاصة بها. في هذه الحالة، يجب تعيين max_steps لتحديد مدة التدريب.

  • processing_class (PreTrainedTokenizerBase، اختياري) — فئة المعالجة المستخدمة لمعالجة البيانات. يجب ضبط جانب الحشو على “يسار”. إذا كانت None، يتم تحميل فئة المعالجة من اسم النموذج باستخدام from_pretrained. يجب ضبط رمز الحشو، tokenizer.pad_token. إذا لم تضبط فئة المعالجة رمز الحشو، سيتم استخدام tokenizer.eos_token كقيمة افتراضية.
  • callbacks (قائمة من TrainerCallback, اختياري) — قائمة من استدعاءات المراجعة (callbacks) لتخصيص حلقة التدريب. ستُضاف هذه الاستدعاءات إلى قائمة استدعاءات المراجعة الافتراضية المفصّلة هنا.

    إذا كنت ترغب في إزالة أحد المراجعات الافتراضية المستخدمة، فاستخدم طريقة remove_callback.

  • optimizers (tuple[torch.optim.Optimizer | None, torch.optim.lr_scheduler.LambdaLR | None]، اختياري، القيمة الافتراضية (None, None)) — مجموعة (tuple) تحتوي على المُحسِّن (optimizer) والمُجدوِل (scheduler) المطلوبين للاستخدام. ستكون القيمة الافتراضية هي نسخة من AdamW على النموذج الخاص بك، مع مُجدوِل يُحدده get_linear_schedule_with_warmup ويُتحكم به عبر args.
  • peft_config (PeftConfig، اختياري) — إعدادات PEFT المستخدمة لتغليف النموذج. إذا كانت None، فلن يتم تغليف النموذج. عند بدء تشغيل خادم vLLM باستخدام --enable-lora، يتم مزامنة مُكيّف LoRA معه كمُكيّف بدلاً من أوزان مدمجة؛ راجع قسم LoRA في توثيق AsyncGRPO.
  • tools (قائمة من Callable، اختياري) — قائمة من دوال الأدوات القابلة للاستدعاء (مزامنة أو غير مزامنة) التي يمكن للنموذج استدعاؤها أثناء التوليد. يجب أن تكون كل أداة دالة بايثون قياسية مع حُجج وقيم إرجاع مُعلَّمة الأنواع بشكل صحيح، وتعليق مستند بنمط Google يصف غرضها وحُججها وقيمة الإرجاع. لمزيد من التفاصيل، راجع: https://huggingface.co/docs/transformers/en/chat_extras#passing-tools. يستخدم النموذج اسم الدالة، وتلميحات الأنواع، وتعليق المستند لتحديد كيفية استدعائها. تأكد من أن قالب الدردشة الخاص بالنموذج يدعم استخدام الأدوات وأنه تم ضبطه الدقيق (fine-tuned) لاستدعاء الأدوات.
  • environment_factory (EnvironmentFactory أو dict[str, EnvironmentFactory], اختياري) — دالة قابلة للاستدعاء تنشئ وتعيد نسخة من البيئة، أو قاموس يربط أسماء البيئات بدوال قابلة للاستدعاء من هذا النوع. يجب أن تعرّف فئة البيئة طرقًا يمكن استدعاؤها كأدوات أثناء التوليد. يجب أن تلتزم كل طريقة بنفس المتطلبات الخاصة بـ tools الموصوفة أعلاه. كما يجب على البيئة أن تنفّذ دالة قابلة للاستدعاء باسم reset يمكن استخدامها لإعادة تعيين الحالة بين عمليات التوليد. يجب أن تعيد دالة reset إما None أو نصًا: عند إرجاع نص، يُضاف هذا النص إلى آخر رسالة مستخدم قبل التوليد. كما يمكن للبيئة أن تعرّف دالة get_reward لا تتخذ أي حجة وتعيد قيمة من نوع float: عند وجودها، تمتلك البيئة المكافأة، وتُستدعى get_reward مرة واحدة لكل تمريرة مكتملة لتقييمها من الحالة الداخلية للبيئة. تعمل كمصدر مكافأة إضافي (بوزن 1، ويُسجَّل باسم فئة البيئة) إلى جانب reward_funcs, الذي يصبح اختياريًا في هذه الحالة.

    باستخدام دالة قابلة للاستدعاء واحدة، يستخدم كل مثال نفس البيئة، مع وجود نسخة واحدة لكل تمرين حتى تبقى تفاعلاتها معزولة. أما عند استخدام قاموس، فيجب أن يحمل كل مثال حقل environment لاختيار بيئته بالاسم، ولا تُعرض في موجهه إلا أدوات تلك البيئة — مما يتيح لتمرين واحد خلط المهام (مثل بيئة برمجة وبيئة لعبة). هذه الميزة تجريبية وقد تتغير أو تُحذف في أي وقت دون إشعار مسبق.

مدرب لطريقة تحسين السياسة النسبية للمجموعات (GRPO). تم اقتراح هذا الخوارزمية في الأصل في الورقة DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models. هذا المدرب هو النسخة غير المتزامنة من GRPO، حيث يتم تفويض التوليد إلى خادم vLLM خارجي يعمل بشكل غير متزامن بالتوازي مع التدريب، مما يفصل التوليد (rollout) عن حلقة تحديث التدرج.

مثال:

>>> from trl.experimental.async_grpo import AsyncGRPOTrainer
>>> from trl.rewards import accuracy_reward
>>> from datasets import load_dataset

>>> dataset = load_dataset("trl-lib/DeepMath-103K", split="train")

>>> trainer = AsyncGRPOTrainer(
...     model="Qwen/Qwen2.5-0.5B-Instruct",
...     reward_funcs=accuracy_reward,
...     train_dataset=dataset,
... )
>>> trainer.train()

لتخصيص العبارات التي يتم أخذ عينات منها، أو كيفية توليد تمريرة، أو كيفية حساب المزايا، قم بإنشاء فئة فرعية من experimental.async_grpo.AsyncRolloutLoop وقم بتعيينها كـ loop_cls للمدرّب. يقوم TRL ببناء الحلقة في

عملية النشر:

>>> class CurriculumTrainer(AsyncGRPOTrainer):
...     loop_cls = CurriculumRolloutLoop

AsyncRolloutLoop

فئة trl.experimental.async_grpo.AsyncRolloutLoop

< >

( config: AsyncGRPOConfigmodel_name: strdataset: Datasetreward_funcs: list[collections.abc.Callable[..., list[float]]]processing_class: PreTrainedTokenizerBaseeos_token_ids: list[int]rollout_buffer: Queuemodel_version_value: Synchronizedheartbeat_value: Synchronizedfailed_event: Eventexception_info_queue: Queuemetrics_queue: Queuetools: list[collections.abc.Callable] | None = Noneenvironment_factory: collections.abc.Callable[[], object] | dict[str, collections.abc.Callable[[], object]] | None = Nonescore_queue_maxsize: int = 16lora_name: str | None = Nonedataset_start_index: int = 0 )

يولّد التمريرات ويقيّمها لـ experimental.async_grpo.AsyncGRPOTrainer، في عملية تمرير مستحدثة.

يُنفّذ الإعداد الافتراضي خوارزمية GRPO. لتخصيص تشغيل، أنشئ فئة فرعية منه، وأعد تعريف الطرق التي تتغير فقط، ثم اضبط الفئة الفرعية كـ loop_cls للمدرّب. يمرّ كل موجه بالترتيب التالي:

  • filter_prompt(): ما إذا كان سيتم توليد أي شيء للموجّه.
  • generate_one(): تمريرة كاملة واحدة، تستدعي generate_one_turn() لكل طلب أخذ عينات.
  • يتم تقييم مجموعة من num_generations من عمليات النشر: حيث تكون مكافآتها هي مجموع reward_funcs الخاص بالمدرب، والبيئات التي تُعرّف get_reward، وRollout.reward. ثم يُنفَّذ compute_advantages() مرة واحدة لكل مجموعة.

ينشئ setup() و close() الموارد ويحررها على حلقة الأحداث الخاصة بالدورة، مثل عميل HTTP. يمكن للخطاف قراءة self.config (يمكن لفئة فرعية من experimental.async_grpo.AsyncGRPOConfig أن تحمل حقولها الخاصة) و self.tokenizer. وبما أن الدورة تُبنى في عملية مولّدة، يجب أن تكون الفئة الفرعية قابلة للاستيراد (معرّفة على مستوى الوحدة).

filter_prompt

< >

( row_index: introw: dict[str, typing.Any]epoch: int ) → bool

المعاملات

  • row_index (int) — مؤشر الصف في مجموعة بيانات التدريب.
  • row (dict[str, Any]) — صف مجموعة البيانات.
  • epoch (int) — عدد مرات المرور الكاملة على مجموعة البيانات قبل هذه المرة.

يعيد

bool

True لتوليد num_generations من عمليات التمرير للموجّه، وFalse لتخطيها.

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

generate_one

< >

( prompt: list[dict[str, str]]tools: list[collections.abc.Callable]group_id: int = 0 ) → Rollout

المعاملات

  • prompt (list[dict[str, Any]]) — رسائل الاستدعاء.
  • tools (list[Callable]) — الأدوات المتاحة لهذا التمرين: أدوات المدرب tools، بالإضافة إلى الطرق العامة للبيئة عند استخدام environment_factory.
  • group_id (int، اختياري، القيمة الافتراضية 0) — معرّف المجموعة التي ينتمي إليها التمرين.

يعيد

التنفيذ

النتيجة النهائية للتوزيع.

أنشئ تمريرة واحدة لموجّه.

بشكل افتراضي، يتبع حلقة الأدوات متعددة الأدوار: في كل دور، تُصيَّر المحادثة كاملةً باستخدام قالب الدردشة، ثم يُستخرج ردٌّ باستخدام generate_one_turn() وتُنفَّذ استدعاءات الأدوات التي يحتويها، حتى يتوقف النموذج عن استدعاء الأدوات أو حتى بلوغ max_tool_calling_iterations. يمكنك تجاوز هذا السلوك لتوليد الردود بطريقة مختلفة، على سبيل المثال باستخدام إطار عمل وكيل. أعد كل طلب استخلاص في Rollout.turns، إذ تُبنى تسلسلات التدريب منها، واضبط Rollout.reward هنا لتقييم مسار التنفيذ.

generate_one_turn

< >

( prompt_ids: list[int] ) → TurnRecord

المعاملات

  • prompt_ids (list[int]) — معرّفات الرموز (Token ids) للموجّه الكامل.

يعيد

TurnRecord

الموجّه والرموز المُستخرجة مع احتمالاتها اللوغاريتمية. عند استخدام top_k أو top_p، يحتوي أيضاً على مجموعة المرشحين لكل رمز مستخرج، ومع num_sampler_logprobs، يحتوي على أعلى الاحتمالات اللوغاريتمية للمستخرج.

استخرج ردًا واحدًا من خادم vLLM، مع إعدادات أخذ العينات الخاصة بالتكوين (temperature، top_p، top_k، min_p، repetition_penalty وmax_completion_length).

compute_advantages

< >

( group: RolloutGroup ) → np.ndarray

المعاملات

  • group (RolloutGroup) — التوليدات الـnum_generations لموجّه واحد، مع مجموع مكافآتها في group.rewards.

يعيد

np.ndarray

ميزة واحدة لكل تمريرة، بترتيب group.rewards.

احسب ميزة واحدة لكل تمريرة ضمن مجموعة. افتراضياً، يتم توحيد كل مكافأة ضمن المجموعة؛ وتُمنح ميزة 0 للتمريرة التي تحتوي على مكافأة بقيمة NaN، وتُستبعد من حساب المتوسط والانحراف المعياري.

يُنفَّذ لكل مجموعة. تُستبعد المجموعة التي تكون مكافآتها المُقيَّمة جميعها متساوية، بغض النظر عن المزايا التي تُرجعها.

إعداد

< >

( )

أنشئ الموارد التي تحتاجها الخطافات الأخرى، مثل عميل HTTP. يعمل على حلقة الأحداث الخاصة بالحلقة قبل أول مطالبة. لا يفعل شيئًا افتراضيًا.

إغلاق

< >

( )

تحرير ما أنشأه setup(). يُنفَّذ عند توقف الحلقات، بما في ذلك عند حدوث فشل. لا يؤدي أي إجراء افتراضيًا.

التنفيذ

فئة trl.experimental.async_grpo.Rollout

< >

( completion: list[dict[str, str]]completion_ids: list[int]turns: list[trl.experimental.async_grpo.async_rollout_worker.TurnRecord]tool_call_count: int = 0tool_failure_count: int = 0reward: float | None = None )

المعاملات

  • completion (list[dict[str, Any]]) — Messages generated after the prompt, in conversational format. Passed to the reward functions as completions.
  • completion_ids (list[int]) — معرّفات الرموز (Token ids) للإكمال المولّد. تُمرَّر إلى دوال المكافأة على أنها completion_ids.
  • turns (list[TurnRecord]) — طلبات العينة التي أنتجت التمرين، بالترتيب. تُبنى تسلسلات التدريب منها: يتم تدريب الرموز المُستخرجة، بينما يُعدّ باقي كل موجه سياقًا.
  • tool_call_count (int، اختياري، القيمة الافتراضية 0) — عدد استدعاءات الأدوات التي تمت خلال الجولة.
  • tool_failure_count (int، اختياري، القيمة الافتراضية 0) — عدد استدعاءات الأدوات التي فشلت.
  • reward (float، اختياري) — المكافأة المحسوبة أثناء التوليد، على سبيل المثال بواسطة مُقيِّم خارجي. تُضاف إلى مكافآت دوال المكافأة والبيئات. إذا كانت None، فلن تحصل هذه الجولة على أي مكافأة من هذا المصدر.

نتيجة واحدة مكتملة، كما تُعاد بواسطة generate_one().

TurnRecord

فئة trl.experimental.async_grpo.async_rollout_worker.TurnRecord

< >

( prompt_ids: list[int]output_ids: list[int]output_log_probs: list[float] = <factory>output_mask: list[int] | None = Noneoutput_sampling_mask: list[list[int]] | None = Noneoutput_sampler_logprobs: list[dict[int, float]] | None = None )

المعاملات

  • prompt_ids (list[int]) — معرّفات الرموز (Token ids) للموجّه الكامل المُرسَل لهذا الدور، بما في ذلك كل الأدوار السابقة في المحادثة.
  • output_ids (list[int]) — معرّفات الرموز التي ولّدها المُعيّن.
  • output_log_probs (list[float]، اختياري، القيمة الافتراضية []) — احتمالية السامبلر (log-probability) لكل رمز في output_ids. مطلوب عند تدريب أيٍّ منها.
  • output_mask (list[int]، اختياري) — قيمة واحدة لكل رمز في output_ids: 1 للتدريب على الرمز، و0 للاحتفاظ به كسياق فقط. إذا كانت None، يتم التدريب على كل رمز في المخرجات.
  • output_sampling_mask (list[list[int]]، اختياري) — قائمة واحدة لكل رمز في output_ids: معرّفات الرموز التي يمكن أن يسحب منها المُعيّن (sampler) تحت تقليص top_k / top_p. إذا كان None، فهي المفردات الكاملة.
  • output_sampler_logprobs (list[dict[int, float]], اختياري) — قائمة واحدة لكل رمز في output_ids: احتمالات السجل (log-probabilities) لأكثر الرموز احتمالًا من قبل العينة (sampler)، مفهرسة بمعرّف الرمز. يُستخدم في توسيط الدرجات (num_sampler_logprobs).

طلب أخذ عينة واحد: الأمر المُرسَل إلى مُولّد العينات والرموز التي أنتجها.

RolloutGroup

فئة trl.experimental.async_grpo.async_rollout_worker.RolloutGroup

< >

( prompts: list[list[dict[str, str]]]reward_kwargs: dict[str, list[typing.Any]]completions: list[list[dict[str, str]]]completions_ids: list[list[int]]completions_sequences: list[list[trl.experimental.async_grpo.async_rollout_worker.TrainingSequence]]tool_call_counts: list[int]tool_failure_counts: list[int]model_version: intgroup_id: introw_index: intenv_rewards: list[tuple[type, float] | None]rollout_rewards: list[float | None]queued_at: float = 0.0rewards: numpy.ndarray | None = None )

المعاملات

  • prompts (list[list[dict[str, Any]]]) — موجّه لكل تمرين.
  • reward_kwargs (dict[str, list[Any]]) — الأعمدة الأخرى في صف مجموعة بيانات الاستعلام، والتي تُمرَّر إلى دوال المكافأة كحجج مُسمّاة.
  • completions (list[list[dict[str, Any]]]) — رسائل الإكمال لكل تمرين.
  • completions_ids (list[list[int]]) — معرّفات رموز الإكمال لكل تمرين.
  • completions_sequences (list[list[TrainingSequence]]) — تسلسلات التدريب المبنية من كل تمرين. التمرين الذي تغيّر تاريخه المُعاد ترميزه بين الأدوار يعطي أكثر من تسلسل واحد.
  • tool_call_counts (list[int]) — عدد استدعاءات الأدوات في كل تمريرة.
  • tool_failure_counts (list[int]) — عدد استدعاءات الأدوات الفاشلة في كل تمريرة.
  • model_version (int) — إصدار النموذج عند بدء أول تمرين للمجموعة.
  • group_id (int) — معرّف المجموعة، يُحسب بدءًا من 0 في عملية النشر.
  • row_index (int) — مؤشر صف الموجه في مجموعة بيانات التدريب.
  • env_rewards (list[tuple[type, float] or None]) — بالنسبة إلى تمرين (rollout) تُعرّف بيئته get_reward، فهي فئة البيئة ومكافأتها؛ وإلا None.
  • rollout_rewards (list[float or None]) — Rollout.reward لكل عملية نشر.
  • queued_at (float، اختياري، القيمة الافتراضية 0.0) — time.monotonic() عند وضع المجموعة في قائمة الانتظار للتقييم.
  • rewards (np.ndarray، اختياري) — المكافأة الإجمالية لكل تمرين، مجمّعة على جميع مصادر المكافآت، وتكون NaN عندما لا تمنح أي مصدر تقييمًا لها. يتم تعيينها قبل استدعاء compute_advantages().

التوليدات num_generations لموجّه واحد، مُقيَّمة معًا. تحتوي كل قائمة على إدخال واحد لكل توليد.

Update on GitHub