TRL documentation
تقليل استهلاك الذاكرة
تقليل استهلاك الذاكرة
يمكن تحسين سير عمل التدريب غالبًا لتقليل استهلاك الذاكرة، ويوفر TRL عدة ميزات مدمجة تساعد على تحقيق ذلك.
فيما يلي، نُلخّص هذه التقنيات ونوصي بالتجربة مع تركيبات مختلفة لتحديد الإعداد الذي يعمل بشكل أفضل لتنسيقك المحدد.
تتضمن كل طريقة أمثلة للمدرّبين المدعومين. إذا لم تكن متأكدًا من توافق تقنية مع مدرّبك، فيرجى الاطلاع على توثيق المدرّب المقابل.
للاستراتيجيات الإضافية، مثل التحقق من التدرج، المدعومة عبر جميع المدربين، راجد دليل أداء transformers.
الاقتطاع
يمكن أن تتفاوت أطوال التسلسلات في مجموعة البيانات تفاوتًا كبيرًا. عند تجميع البيانات في دفعات، يتم ملء التسلسلات لتطابق أطول تسلسل في الدفعة، مما قد يؤدي إلى استهلاك عالٍ للذاكرة، حتى لو كانت معظم التسلسلات قصيرة نسبيًا.

للتقليل من استهلاك الذاكرة، من المهم تقصير التسلسلات إلى طول معقول. على الرغم من أن مدرّبي TRL يقصّرون التسلسلات افتراضيًا، فقد ترغب في تعديل طول التقصير الافتراضي ليتناسب بشكل أفضل مع حالتك الخاصة.
يتم التحكم في تقصير DPO عبر max_length، والذي يقصّ تسلسل الموجه + الإكمال الموحّد.

لضبط معامل truncation، استخدم مقتطف الشيفرة التالي:
from trl import DPOConfig
training_args = DPOConfig(..., max_length=...)تمت إزالة المعاملين
max_prompt_lengthوmax_completion_lengthالتقليديين الآن؛ وبدلاً من ذلك، قم بتصفية أو تقصير المسبقات/المكملات الطويلة جداً في مجموعة بياناتك قبل التدريب.
يُطبَّق اقتطاع SFT على تسلسل الإدخال عبر معامل max_length.

لضبط معامل truncation، استخدم مقتطف الشيفرة التالي:
from trl import SFTConfig
training_args = SFTConfig(..., max_length=...)كيف تختار قيمة max_length؟
إذا كان max_length صغيراً جداً، فسيتم التخلص من جزء كبير من الرموز الخاصة بك ولن تساهم في التدريب. وإذا كان كبيراً جداً، فقد يرتفع استهلاك الذاكرة بشكل حاد، مما قد يؤدي إلى أخطاء نفاد الذاكرة (OOM). وبدون التعبئة أو التدريب بدون حشو، قد يؤدي max_length الكبير أيضاً إلى تدريب غير فعال، حيث ستكون العديد من الرموز حشواً.
لمساعدتك في اختيار قيمة مناسبة، نوفر أداة لعرض توزيع طول التسلسل في مجموعة البيانات الخاصة بك.
التعبئة
يتوفر هذا الأسلوب فقط لتدريب SFT والإعدادات التي تستخدم FlashAttention (أو متغيراته).
لـالاقتطاع عدة عيوب:
- فقدان المعلومات: قد يتم تجاهل الرموز المهمة في نهاية التسلسلات.
- اختيار طول الاقتطاع: إذا كان قصيرًا جدًا، يُفقد جزء من البيانات؛ وإذا كان طويلًا جدًا، تنخفض الكفاءة.
تُخفّف تقنية التجميع (Packing) من هذه المشكلات عن طريق تجميع تسلسلات متعددة في صف تدريب واحد، مع ملء كل صف حتى max_length.

تنفّذ TRL التعبئة باستخدام تعبئة الصناديق Best-Fit Decreasing (BFD)، والتي تجمع التسلسلات بكفاءة مع تقليل الحشو إلى أدنى حد. عندما يتجاوز تسلسل max_length، تحدد استراتيجيات مختلفة كيفية معالجة الرموز الزائدة.
يدعم TRL ثلاث استراتيجيات:
"bfd"(الافتراضي): يستخدم تعبئة أفضل ملاءمة تنازلية. إذا تجاوزت التسلسلmax_length، يتم تجاهل الرموز الزائدة."bfd_split": يستخدم تعبئة أفضل ملاءمة تنازلية، لكن يتم تقسيم التسلسلات الطويلة إلى مقاطع ≤max_lengthقبل التعبئة. يحافظ هذا على جميع الرموز ويتبع النهج المقترح في Fewer Truncations Improve Language Modeling."wrapped": يتم دمج جميع الرموز في تدفق واحد ثم تقسيمها إلى كتل ذات طول ثابت. يقلل هذا النهج من الحشو (Padding) إلى الحد الأدنى، لكنه قد يخلط بين أمثلة غير ذات صلة. يتوافق هذا الإجراء مع معالجة concatenate-then-split الموصوفة في الأدبيات (مثل Fewer Truncations Improve Language Modeling). ولديه عيب يتمثل في كسر استمرارية التسلسل لجزء كبير من مجموعة البيانات، مما يضر بالأداء، كما هو موضح في Qwen3-Coder-Next Technical Report.
إذا كانت جميع التسلسلات أقصر من
max_length، فإنbfdوbfd_splitتتصرفان بشكل متطابق، إذ لا حاجة إلى أي تقصير أو تقسيم.
from trl import SFTConfig
training_args = SFTConfig(
...,
packing=True,
packing_strategy="bfd",
max_length=512,
)PEFT للضبط الدقيق الفعال من حيث المعلمات
تُعدّ طرق الضبط الدقيق الفعّال من حيث المعاملات (PEFT) مثل LoRA من بين أكثر التقنيات فعاليةً لتقليل استهلاك الذاكرة أثناء التدريب. فبدلاً من تدريب جميع معاملات النموذج، تُدرّب طرق PEFT عدداً صغيراً فقط من معاملات المُكيِّف (adapter)، مما يُقلّل بشكل كبير من متطلبات الذاكرة ويُتيح ضبط النماذج الأكبر حجماً على أجهزة محدودة الموارد.
لتفاصيل شاملة حول استخدام PEFT مع TRL، بما في ذلك طرق المحوّلات المختلفة، وخيارات التكميم، والإعدادات المتقدمة، راجع تكامل PEFT.
لاستخدام PEFT لتقليل استهلاك الذاكرة:
from datasets import load_dataset
from peft import LoraConfig
from trl import SFTTrainer
dataset = load_dataset("trl-lib/Capybara", split="train")
peft_config = LoraConfig()
trainer = SFTTrainer(
model="Qwen/Qwen2.5-0.5B",
train_dataset=dataset,
peft_config=peft_config,
)يمكن دمج PEFT مع تقنيات تقليل الذاكرة الأخرى مثل التكميم (4 بت أو 8 بت) لتحقيق توفير أكبر في الذاكرة. راجع تكامل PEFT لمزيد من الأمثلة على التكميم.
بدون حشو
يُعدّ الدفع بدون حشو (Padding-free batching) نهجًا بديلًا لتقليل استهلاك الذاكرة. في هذه الطريقة، يتم أولًا أخذ عينة من الدفعة ثم تسطيحها في تسلسل واحد، مما يتجنب الحشو. على عكس التعبئة (Packing)، التي قد تؤدي إلى تسلسلات غير مكتملة من خلال دمج أجزاء من عينات مختلفة، يضمن الدفع بدون حشو بقاء جميع التسلسلات مكتملة وسليمة.

ميزة Padding-free غير متاحة مؤقتًا في DPOTrainer: فمنذ إعادة هيكلة DPO، يؤدي تعيين
padding_free=Trueإلى إصدار تحذير والعودة إلى التعبئة القياسية. ومن المقرر إعادة تفعيلها في تحديث مستقبلي.
from trl import DPOConfig
training_args = DPOConfig(..., padding_free=True, model_init_kwargs={"attn_implementation": "kernels-community/flash-attn2"})from trl import SFTConfig
training_args = SFTConfig(..., padding_free=True, model_init_kwargs={"attn_implementation": "kernels-community/flash-attn2"})تفريغ التفعيل
تُعدّ تقنية تفريغ التفعيلات (Activation offloading) أسلوبًا لتحسين كفاءة الذاكرة، حيث تقلّل من استهلاك ذاكرة الفيديو (VRAM) على وحدة معالجة الرسوميات (GPU) من خلال نقل متجهات التفعيل مؤقتًا إلى ذاكرة الوصول العشوائي (RAM) في وحدة المعالجة المركزية (CPU) أثناء المرور الأمامي، ثم إعادتها فقط عند الحاجة إليها في المرور العكسي. يؤدي هذا إلى تقليل ذروة استهلاك الذاكرة بشكل كبير، مقابل زيادة طفيفة في وقت التدريب.
لتفعيل تفريغ التفعيلات في إعدادات تدريب SFT الخاصة بك:
from trl import SFTConfig
training_args = SFTConfig(..., activation_offloading=True)تقوم آلية نقل التفعيلات (Activation Offloading) في الخلفية بتنفيذ saved_tensors_hooks الخاص بـ PyTorch لاعتراض التفعيلات أثناء المرور الأمامي. وهي تدير بذكاء المصفوفات (Tensors) التي يجب نقلها بناءً على حجمها وسياقها، مع تجنّب نقل مصفوفات الإخراج التي قد يكون نقلها غير فعّال. ولتحسين الأداء، يمكنها، عبر علم (Flag) يكون مفعّلًا افتراضيًا، استخدام تدفقات CUDA (CUDA streams) لتداخل العمليات الحسابية مع عمليات النقل بين المعالج المركزي والوحدة الرسومية (CPU-GPU).
تعبئة التسلسلات إلى مضاعف
تُؤيَّد هذه التقنية حاليًا لمدرّبي SFT وReward.
عند التفعيل، تضمن هذه الخطة أن جميع التسلسلات تُملأ إلى مضاعف للقيمة المحددة.
يمكن أن يحسّن ذلك الكفاءة الحسابية على بعض الأجهزة من خلال محاذاة أطوال التسلسلات مع حدود الذاكرة الملائمة.
from trl import SFTConfig
training_args = SFTConfig(..., pad_to_multiple_of=2048)from trl import RewardConfig
training_args = RewardConfig(..., pad_to_multiple_of=2048)مُخصِّص ذاكرة التخزين المؤقت في PyTorch
في التدرّبات الطويلة، ولا سيما في التعلم المعزز عبر الإنترنت (GRPO، RLOO، Online DPO)، قد يحدث تجزؤ في ذاكرة وحدة معالجة الرسوميات. يُتيح ضبط expandable_segments:True لمُخصِّص ذاكرة PyTorch المُخزَّن مؤقتًا توسيع المقاطع الموجودة بدلاً من ذلك، مما يقلّل الفجوة بين الذاكرة المُخصَّصة والذاكرة المحجوزة:
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
export PYTORCH_ALLOC_CONF=expandable_segments:True # canonical name since PyTorch 2.10مع وضع السبات في vLLM (
vllm_enable_sleep_mode=True)، يقرأ vLLMPYTORCH_CUDA_ALLOC_CONFفقط للالتفاف على هذا الإعداد، لذا لا تضبطPYTORCH_ALLOC_CONFوحدها.
تعطيل تجميع النموذج للتوليد في الأساليب عبر الإنترنت
عند استخدام DeepSpeed ZeRO-3، يتم تقسيم أوزان النموذج على عدة وحدات معالجة رسومية (GPU). تتضمن الأساليب المباشرة توليد إكمالات من النموذج كجزء من عملية التدريب. خلال هذه الخطوة، يتم تجميع أوزان النموذج مؤقتًا على وحدة معالجة رسومية واحدة من أجل التوليد. بالنسبة للنماذج الكبيرة جدًا، قد يؤدي هذا التجميع إلى أخطاء نفاد الذاكرة (OOM)، كما هو موضح في هذه المشكلة: #2250.
إذا واجهت هذه المشكلة، يمكنك تعطيل جمع أوزان النموذج للتوليد من خلال تعيين المعامل التالي:
from trl import GRPOConfig
training_args = GRPOConfig(..., ds3_gather_for_generation=False)from trl.experimental.online_dpo import OnlineDPOConfig
training_args = OnlineDPOConfig(..., ds3_gather_for_generation=False)from trl import RLOOConfig
training_args = RLOOConfig(..., ds3_gather_for_generation=False)تمنع هذه الضبط تجميع أوزان النموذج، مما يتجنب أخطاء نفاد الذاكرة (OOM)، لكنه قد يؤدي إلى انخفاض سرعة التوليد.
وضع السكون في vLLM
عند استخدام vLLM كواجهة خلفية للتوليد في طرق التدريب عبر الإنترنت، يمكنك تفعيل وضع السكون لنقل معاملات vLLM والذاكرة المؤقتة إلى ذاكرة الوصول العشوائي في المعالج المركزي أثناء خطوة التحسين، ثم إعادة تحميلها إلى ذاكرة الفيديو في وحدة المعالجة الرسومية عند الحاجة إليها لمزامنة الأوزان والتوليد.
from trl import GRPOConfig
training_args = GRPOConfig(..., vllm_enable_sleep_mode=True)from trl import RLOOConfig
training_args = RLOOConfig(..., vllm_enable_sleep_mode=True)يساعد نقل أوزان vLLM وذاكرة التخزين المؤقت إلى خارج وحدة معالجة الرسوميات في الحفاظ على انخفاض استهلاك ذاكرة وحدة معالجة الرسوميات، وهو ما قد يكون مفيداً بشكل خاص عند تدريب نماذج كبيرة أو عند استخدام موارد وحدات معالجة الرسوميات المحدودة. ومع ذلك، فإن إيقاظ محرك vLLM من وضع السبات يُدخل بعض زمن الاستجابة المرتبط بنقل البيانات بين المضيف ووحدة المعالجة، مما قد يؤثر قليلاً على سرعة التدريب.
التحقق من النقاط
يعمل فحص التدرّج (Gradient checkpointing) على استبدال الحسابات بالذاكرة من خلال عدم تخزين جميع التفعيلات الوسيطة أثناء المسار الأمامي، وإعادة حسابها بدلاً من ذلك أثناء المسار الخلفي.
from trl import SFTConfig
training_args = SFTConfig(..., gradient_checkpointing=True)يتم تفعيل Gradient checkpointing افتراضيًا في جميع المدربين لتحسين استخدام الذاكرة. يمكنك تعطيله عن طريق تعيين
gradient_checkpointing=Falseعند الحاجة.
التحقق من نقاط التفعيل الانتقائي
باستخدام SFTTrainer، يمكنك حفظ مخرجات الانتباه أثناء المرور الأمامي بدلاً من إعادة حسابها في المرور الخلفي. يستعيد هذا معظم بطء نقاط التفتيش في السياقات الطويلة، مقابل إضافة متجه واحد بحجم حالة مخفية لكل طبقة. يفرض هذا استخدام نقاط تفتيش غير معاد الدخول.
from trl import SFTConfig
training_args = SFTConfig(
...,
gradient_checkpointing=True,
gradient_checkpointing_kwargs={"selective": True},
)لمعرفة المزيد من تقنيات تحسين الذاكرة، راجع دليل أداء Transformers.
Update on GitHub