سنتعرف في هذا المقال على الصنف Trainer في مكتبة المحولات Transformers ضمن منصة Hugging Face، ونوضح طريقة الاستفادة منه في تدريب النماذج اللغوية الكبيرة، كما سنتعرف أيضًا على أصناف عديدة تفيدنا في تحسين وتسريع عملية التدريب.
ما هو الصنف Trainer
الصنف Trainer هو أداة تُسهّل تدريب النماذج المبنية باستخدام باي تورش PyTorch في مكتبة المحولات Transformers. فبدلًا من أن نضطر لكتابة الشيفرة الخاصة بتدريب النموذج من البداية، يتيح لنا هذا الصنف تمرير العناصر الأساسية مثل النموذج Model، والمُرمِّز Tokenizer، ومجموعة البيانات Dataset، ودالة التقييم Evaluation Function، ومعاملات التدريب الفائقة Hyperparameters، والبدء بعدها بالتدريب بسرعة دون الحاجة للتعامل مع الكثير من التفاصيل والإعدادات يدويًا، كما أن الصنف Trainer قابل للتخصيص وبإمكاننا تعديل إعداداته بما يوافق احتياجاتنا.
توفر مكتبة Transformers أيضًا الصنف Seq2SeqTrainer الذي يساعدنا في مهام تتطلب تحويل سلسلة نصية إلى سلسلة نصية أخرى مثل الترجمة أو التلخيص. يوجد أيضًا الصنف SFTTrainer من مكتبة TRL التي تغلِّف الصنف Trainer وهي مُحسَّنة لتدريب النماذج اللغوية مثل Llama-2 و Mistral باستخدام تقنيات الانحدار التلقائي Autoregressive التي تُمكِّن النموذج اللغوي من توليد النصوص بناءً على تسلسل الكلمات السابقة، مما يُحسن أداءه، ويدعم الصنف SFTTrainer أيضًا ميزات أخرى مثل Sequence Packing و LoRA وQuantization و DeepSpeed للتوسّع بكفاءة إلى أيّ حجم نموذج نحتاجه، مما يجعله مثاليًا لتدريب النماذج اللغوية المتقدمة.
ملاحظة: يُستحسن الاطلاع على توثيق Trainer لمعرفة المزيد حول الأصناف المختلفة ومتى نستخدم كل منها، فالصنف Trainer هو الخيار الأكثر تنوعًا ويناسب مجموعة واسعة من المهام، والصنف Seq2SeqTrainer مناسب لمهام تتطلب حويل تسلسل نصي إلى تسلسل نصي آخر كالترجمة والتلخيص، أما الصنف SFTTrainer فهو مناسب لتدريب النماذج اللغوية المتقدمة.
قبل البدء باستخدام الصنف Trainer، لنتأكد من تثبيت مكتبة Accelerate المفيدة لتفعيل وتشغيل تدريب نماذج باي تورش PyTorch في البيئات الموزعة بسرعة من خلال الأمر التالي:
pip install accelerate # للترقية pip install accelerate --upgrade
سنوفر في الفقرات التالية نظرة عامة على الصنف Trainer وطريقة استخدامه في مكتبة المحوّلات Transformers.
الاستخدام الأساسي للصنف Trainer
يتضمن الصنف Trainer الشيفرة البرمجية الموجودة في حلقة تدريب أساسية، والتي تتضمن ما يلي:
- إجراء خطوة تدريب لحساب الخسارة
-
حساب التدرجات Gradients باستخدام التابع
backward
- تحديث الأوزان بناءً على التدرجات
- تكرار هذه العملية حتى الوصول إلى عدد محدَّد مسبقًا من دورات التدريب Epochs
يجرّد الصنف Trainer هذه الشيفرة حتى لا نضطر إلى القلق بشأن كتابة حلقة تدريب يدويًا في كل مرة، أو إذا كنا مبتدئين في استخدام إطار عمل PyTorch وإجراء عملية التدريب من خلاله، فما علينا سوى توفير المكوّنات الأساسية المطلوبة للتدريب كالنموذج ومجموعة البيانات، وسيتولى الصنف Trainer التعامل مع الأمور الأخرى نيابة عنا.
في حال أردنا تحديد خيارات التدريب فيمكننا العثور عليها في الصنف TrainingArguments. لنحدّد مثلًا مكان حفظ النموذج في المعامل output_dir
ودفع النموذج إلى مستودع Hub بعد التدريب باستخدام المعامل push_to_hub=True
كما يلي:
from transformers import TrainingArguments training_args = TrainingArguments( output_dir="your-model", learning_rate=2e-5, per_device_train_batch_size=16, per_device_eval_batch_size=16, num_train_epochs=2, weight_decay=0.01, eval_strategy="epoch", save_strategy="epoch", load_best_model_at_end=True, push_to_hub=True, )
بعد إنشاء training_args
علينا تمريره للصنف Trainer إلى جانب النموذج، ومجموعة البيانات، والمُعالِج المسبق لمجموعة البيانات إذ يمكن أن يكون هذا المُعالِج مرمِّزًا أو مستخرج ميزات أو معالج صور حسب نوع بياناتنا، كذلك علينا تمرير مجمِّع بيانات ودالة لحساب المقاييس التي نريد تتبعها أثناء التدريب، ثم نستدعي التابع train()
لبدء التدريب كما يلي:
from transformers import Trainer trainer = Trainer( model=model, args=training_args, train_dataset=dataset["train"], eval_dataset=dataset["test"], tokenizer=tokenizer, data_collator=data_collator, compute_metrics=compute_metrics, ) trainer.train()
نقاط التحقق Checkpoints
يحفظ الصنف Trainer نقاط التحقق Checkpoints الخاصة بنموذجنا في المجلد المحدد في المعامل output_dir
الخاص بالصنف TrainingArguments، حيث سنجد نقاط التحقق محفوظة في المجلد الفرعي checkpoint-000
وتقابل الأرقام في النهاية خطوة التدريب، ويُعَد حفظ نقاط التحقق مفيدًا لاستئناف التدريب لاحقًا.
# الاستئناف من نقطة التحقق الأخيرة trainer.train(resume_from_checkpoint=True) # الاستئناف من نقطة تحقق مُحدَّدة محفوظة في مجلد الخرج trainer.train(resume_from_checkpoint="your-model/checkpoint-1000")
يمكننا حفظ نقاط التحقق الخاصة بنموذجنا، ولكن حالة المُحسِّن لن تُحفَظ افتراضيًا في مستودع Hub، فكي نحفظها يجب علينا ضبط المعامل push_to_hub=True
في الصنف TrainingArguments لإيداعها Commit ودفعها إلى المستودع.
فيما يلي بعض الخيارات الأخرى التي يمكننا استخدامها لتحديد كيفية حفظ نقاط التحقق وإعدادها من خلال المعامل hub_strategy
.
-
يدفع الخيار
hub_strategy="checkpoint"
أحدث نقطة تحقق إلى مجلد فرعي باسمlast-checkpoint
، والذي يمكننا استئناف التدريب منه -
يدفع الخيار
hub_strategy="all_checkpoints"
جميع نقاط التحقق إلى المجلد المحدَّد في المعاملoutput_dir
، حيث سنرى نقطة تحقق واحدة لكل مجلد في مستودع النموذج
عند استئناف التدريب من نقطة تحقق محفوظة سابقًا، يحاول الصنف Trainer أن يحتفظ بنفس حالة الأرقام العشوائية RNG التي كانت في وقت الحفظ، سواء في Python أو NumPy أو PyTorch. ولكن بسبب بعض الإعدادات الافتراضية في باي تورش PyTorch، قد لا تكون الأرقام العشوائية هي نفسها عند استئناف التدريب. فإذا كنا نرغب في جعل كل شيء يحدث بنفس الطريقة تمامًا في كل مرة، يمكن تعديل بعض الإعدادات لجعل التدريب ينفذ دومًا بنفس الطريقة، لكن يجب أن نضع بالحسبان أن هذا قد يجعل التدريب أبطأ قليلاً، ويمكن الرجوع إلى دليل التحكم في العشوائية في PyTorch لمطالعة هذه الإعدادات التي يتوجب تفعيلها لتحقيق ذلك.
تخصيص الصنف Trainer
صُمِّم الصنف Trainer ليكون سهل الاستخدام والوصول، وهو يتميز أيضًا بسهولة التخصيص، إذ يمكننا إنشاء أصناف فرعية للعديد من توابع الصنف وتعديلها لدعم الوظيفة التي نريدها دون الحاجة إلى إعادة كتابة حلقة التدريب بالكامل من الصفر كي تتوافق مع هذه الوظيفة، وتتضمن هذه التوابع ما يلي:
-
ينشئ التابع
get_train_dataloader()
صنف DataLoader للتدريب -
ينشئ التابع
get_eval_dataloader()
صنف DataLoader للتقييم -
ينشئ التابع
get_test_dataloader()
صنف DataLoader للاختبار -
يسجّل التابع
log()
معلومات حول الكائنات المختلفة التي تراقب التدريب -
يستخدم التابع
create_optimizer_and_scheduler()
لإعداد المحسّن optimizer ومُجَدوِل معدل التعلم learning rate scheduler، ويمكن التخصيص أيضًا باستخدام التابعينcreate_optimizer()
وcreate_scheduler()
-
يحسب التابع
compute_loss()
الخسارة على دفعة من دخل التدريب -
يجري التابع
training_step()
خطوة التدريب -
يجري التابع
prediction_step()
خطوة التنبؤ والاختبار -
يقيّم التابع
evaluate()
النموذج ويعيد مقاييس التقييم -
يجري التابع
predict()
تنبؤات على مجموعة الاختبار باستخدام المقاييس إذا كانت التسميات Labels متاحة
يمكننا مثلًا تخصيص التابع compute_loss()
لاستخدام خسارة موزونة weighted loss كما يلي:
from torch import nn from transformers import Trainer class CustomTrainer(Trainer): def compute_loss(self, model, inputs, return_outputs=False): labels = inputs.pop("labels") # تمرير أمامي outputs = model(**inputs) logits = outputs.get("logits") # حساب الخسارة المخصَّصة لثلاثة تسميات توضيحية بأوزان مختلفة loss_fct = nn.CrossEntropyLoss(weight=torch.tensor([1.0, 2.0, 3.0], device=model.device)) loss = loss_fct(logits.view(-1, self.model.config.num_labels), labels.view(-1)) return (loss, outputs) if return_outputs else loss
دوال رد النداء Callbacks
يوجد خيار آخر لتخصيص الصنف Trainer وهو استخدام دوال رد النداء Callbacks، لا تُغيّر هذه الدوال في حلقة التدريب نفسها، بل تراقب حالة الحلقة وتنفذ بعض الإجراءات مثل التوقف المبكر عن التنفيذ، أو تسجيل النتائج استنادًا إلى الحالة الحالية، وبالتالي لا يمكن استخدام دالة رد نداء لتنفيذ شيءٍ مخصص كتعريف دالة خسارة مخصَّصة باستخدامها، بل يجب في هذه الحالة إنشاء صنف فرعي وتعديل التابع compute_loss()
ضمنه.
على سبيل المثال، يمكننا إضافة دالة رد نداء للتوقف المبكر بعد 10 خطوات في حلقة التدريب على النحو التالي:
from transformers import TrainerCallback class EarlyStoppingCallback(TrainerCallback): def __init__(self, num_steps=10): self.num_steps = num_steps def on_step_end(self, args, state, control, **kwargs): if state.global_step >= self.num_steps: return {"should_training_stop": True} else: return {}
ثم نمرّرها إلى المعامل callback
الخاص بالصنف Trainer كما يلي:
from transformers import Trainer trainer = Trainer( model=model, args=training_args, train_dataset=dataset["train"], eval_dataset=dataset["test"], tokenizer=tokenizer, data_collator=data_collator, compute_metrics=compute_metrics, callback=[EarlyStoppingCallback()], )
التسجيل Logging
يمكننا من خلال ضبط مستوى التسجيل Logging التحكم في كمية وتفاصيل المعلومات المسجلة أثناء تنفيذ الشيفرات البرمجية، وهذا يساعدنا في تتبع الأداء واكتشاف الأخطاء بشكل فعال حسب الحاجة.
يُضبَط الصنف Trainer على المستوى logging.INFO
افتراضيًا والذي يبلّغ عن الأخطاء والتحذيرات والمعلومات الأساسية الأخرى، وتُضبَط نسخة الصنف Trainer في البيئات الموزعة على المستوى logging.WARNING
الذي يبلّغ عن الأخطاء والتحذيرات فقط. يمكننا تغيير مستوى التسجيل باستخدام المعاملات log_level
و log_level_replica
في الصنف TrainingArguments.
كما يمكن ضبط إعداد مستوى السجل لكل جهاز من خلال استخدام المعامل log_on_each_node
لتحديد استخدام مستوى السجل على كل جهاز أو على الجهاز الرئيسي فقط إذا كنا نعمل في بيئة تحتوي على أجهزة متعددة.
ملاحظة1: من المفيد مطالعة توثيق واجهة برمجة التطبيقات الخاصة بالتسجيل Logging للحصول على مزيد من المعلومات حول مستويات التسجيل المختلفة ودور كل منها.
ملاحظة2: يحدّد الصنف Trainer مستوى السجل بطريقة منفصلة لكل جهاز في التابع Trainer.__init__()
المسؤول عن تهيئة كائن التدريب، لذا قد نرغب في التفكير في ضبط مستوى السجل مبكرًا في حال استخدمنا دوال مكتبة المحوّلات Transformers الأخرى قبل إنشاء الكائن.
يمكن مثلًا ضبط الشيفرة البرمجية الرئيسية لاستخدام مستوى السجل نفسه وفقًا لكل جهاز كما يلي:
logger = logging.getLogger(__name__) logging.basicConfig( format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", datefmt="%m/%d/%Y %H:%M:%S", handlers=[logging.StreamHandler(sys.stdout)], ) log_level = training_args.get_process_log_level() logger.setLevel(log_level) datasets.utils.logging.set_verbosity(log_level) transformers.utils.logging.set_verbosity(log_level) trainer = Trainer(...)
استخدمنا مجموعات مختلفة من المعاملات log_level
و log_level_replica
لضبط ما يُسجَّل على كل جهاز، حيث إذا كان لدينا جهاز واحد، فنستخدم ما يلي:
my_app.py ... --log_level warning --log_level_replica error
ونضيف المعامل log_on_each_node 0
للبيئات متعددة الأجهزة كما يلي:
my_app.py ... --log_level warning --log_level_replica error --log_on_each_node 0 # الضبط للإبلاغ عن الأخطاء فقط my_app.py ... --log_level error --log_level_replica error --log_on_each_node 0
تقنية NEFTune
تقنية NEFTune هي طريقة لتحسين أداء النموذج أثناء التدريب عن طريق إضافة ضجيج Noise إلى البيانات المستخدمة لتدريب النموذج. وما نعنيه بالضجيج هنا إضافة بعض التغييرات العشوائية إلى البيانات للمساعدة في تحسين قدرة النموذج على التعميم وعدم حفظ التفاصيل الزائدة التي قد تؤدي إلى مشكلات في الأداء، فعند استخدام NEFTune، يجري تعديل طبقة التضمين أي التمثيل الرياضي للبيانات داخل النموذج بإضافة الضجيج إليها، مما يساعد في تدريب النموذج بمرونة أكبر.
يمكننا تفعيل هذه التقنية في الصنف Trainer من خلال ضبط المعامل neftune_noise_alpha
داخل الصنف TrainingArguments، فهذا المعامل يحدد مقدار الضجيج الذي سيُضاف إلى طبقة التضمين أثناء التدريب كما في المثال التالي:
from transformers import TrainingArguments, Trainer training_args = TrainingArguments(..., neftune_noise_alpha=0.1) trainer = Trainer(..., args=training_args)
بعد الانتهاء من التدريب، تُعطَّل تقنية NEFTune لاستعادة الطبقة الأصلية للتضمين بدون أي تعديلات عشوائية وتجنب أيّ سلوك غير متوقّع.
استراتيجية التدريب GaLore
إسقاط التدرج منخفض الرتبة Gradient Low-Rank Projection -أو GaLore اختصارًا- هي استراتيجية تدريب منخفضة الرتبة وتتميز بكفاءة في استخدام الذاكرة وتسمح بالتعلم الكامل للمعاملات، ولكنها أكثر كفاءة في استخدام الذاكرة من طرق التكيف منخفضة الرتبة التقليدية مثل LoRA.
توفر هذه الاستراتيجية أداءً جيدًا باستخدامها ذاكرة أقل، مما يجعلها خيارًا ممتازًا للاستخدام في تدريب النماذج الكبيرة، قبل البدء باستخدام GaLore، علينا التأكد من تثبيت المستودع الرسمي الخاص بها باستخدام الأمر التالي:
pip install galore-torch
نحتاج بعد ذلك إلى تحديد كيفية تحسين النموذج بشكل دقيق وإضافة بعض الخيارات التي تحدد طريقة التحسين وأيضًا تحديد الوحدات المستهدفة التي نريد تعديلها، حيث نضيف الخيارات ["galore_adamw", "galore_adafactor", "galore_adamw_8bit"]
في المعامل optim
مع المعامل optim_target_modules
الذي يمكن أن يكون قائمة من السلاسل النصية أو التعابير النمطية Regex أو مسارًا كاملًا مطابقًا لأسماء وحدات النموذج المستهدفة التي نريد تكييفها أثناء عملية التدريب.
فيما يلي مثال لسكربت لتدريب نموذج باستخدام مكتبة GaLore، لكن علينا التأكّد من استخدام الأمر التالي أولًا قبل تشغيل السكربت
pip install trl datasets
وفيما يلي السكربت المطلوب:
import torch import datasets import trl from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM train_dataset = datasets.load_dataset('imdb', split='train') args = TrainingArguments( output_dir="./test-galore", max_steps=100, per_device_train_batch_size=2, optim="galore_adamw", optim_target_modules=["attn", "mlp"] ) model_id = "google/gemma-2b" config = AutoConfig.from_pretrained(model_id) tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_config(config).to(0) trainer = trl.SFTTrainer( model=model, args=args, train_dataset=train_dataset, dataset_text_field='text', max_seq_length=512, ) trainer.train()
يمكننا تمرير الوسطاء الإضافية التي تدعمها GaLore من خلال تمرير المعامل optim_args
كما يلي:
import torch import datasets import trl from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM train_dataset = datasets.load_dataset('imdb', split='train') args = TrainingArguments( output_dir="./test-galore", max_steps=100, per_device_train_batch_size=2, optim="galore_adamw", optim_target_modules=["attn", "mlp"], optim_args="rank=64, update_proj_gap=100, scale=0.10", ) model_id = "google/gemma-2b" config = AutoConfig.from_pretrained(model_id) tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_config(config).to(0) trainer = trl.SFTTrainer( model=model, args=args, train_dataset=train_dataset, dataset_text_field='text', max_seq_length=512, ) trainer.train()
يمكن مطالعة المزيد عن هذه طريقة GaLore في المستودع الأصلي.
يمكننا حاليًا تدريب الطبقات الخطية فقط باستخدام طريقة GaLore التي تستخدم طريقة التفكك منخفض الرتبة Low-Rank Decomposition، بينما ستظل الطبقات المتبقية تًدرّب وتُحسَّن بالطريقة التقليدية. وسنلاحظ أن عملية التحضير لبدء التدريب تستغرق بعض الوقت مثلًا 3 دقائق لنموذج 2B على NVIDIA A100 ولكن يجب أن يعمل التدريب بسلاسة بعد ذلك.
يمكننا أيضًا إجراء تحسين على مستوى الطبقة من خلال إضافة الكلمة layerwise
إلى نهاية اسم المحسِّن كما يلي:
import torch import datasets import trl from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM train_dataset = datasets.load_dataset('imdb', split='train') args = TrainingArguments( output_dir="./test-galore", max_steps=100, per_device_train_batch_size=2, optim="galore_adamw_layerwise", optim_target_modules=["attn", "mlp"] ) model_id = "google/gemma-2b" config = AutoConfig.from_pretrained(model_id) tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_config(config).to(0) trainer = trl.SFTTrainer( model=model, args=args, train_dataset=train_dataset, dataset_text_field='text', max_seq_length=512, ) trainer.train()
نلاحظ أن التحسين على مستوى الطبقة Layer-wise Optimization تجريبي بعض الشيء ولا يدعم توزيع البيانات Distributed Data Parallel أو DDP اختصارًا، وبالتالي عند استخدام هذا النوع من التحسين فقد تتمكن من تشغيل التدريب على وحدة معالجة رسومية GPU واحدة فقط.
محسّن LOMO
محسّن LOMO هو أداة تُستخدم لتحسين النماذج اللغوية الكبيرة عندما تكون الموارد محدودة، وهو يساعد على تقليل استخدام الذاكرة أثناء التدريب. يُعد AdaLomo نوعًا من محسنات LOMO، وهو يعتمد على تقنية التعلم التكيفي Adaptive Learning لتحديث المعاملات بكفاءة، مما يعزز الأداء مع الحفاظ على استهلاك منخفض للذاكرة.
يعمل محسّن LOMO عن طريق دمج حساب التدرج وتحديث المعاملات في خطوة واحدة، مما يساعد على تسريع عملية التدريب وتقليل الحاجة إلى الذاكرة. المحسنات المتاحة في LOMO هي lomo
و adalomo
.
ملاحظة: يُوصَى باستخدام محسّن AdaLomo
بدون تفعيل خيار حساب تدرجات النموذج grad_norm
للحصول على أداء أفضل وإنتاجية أعلى.
نثبّت أولًا LOMO من مستودع Pypi باستخدام الأمر التالي:
pip install lomo-optim
أو نثبّته من المصدر باستخدام الأمر التالي:
pip install git+https://github.com/OpenLMLab/LOMO.git.
فيما يلي سكربت بسيط يوضح كيفية صقل نموذج google/gemma-2b مع مجموعة بيانات IMDB بدقة كاملة:
import torch import datasets from transformers import TrainingArguments, AutoTokenizer, AutoModelForCausalLM import trl train_dataset = datasets.load_dataset('imdb', split='train') args = TrainingArguments( output_dir="./test-lomo", max_steps=1000, per_device_train_batch_size=4, optim="adalomo", gradient_checkpointing=True, logging_strategy="steps", logging_steps=1, learning_rate=2e-6, save_strategy="no", run_name="lomo-imdb", ) model_id = "google/gemma-2b" tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_pretrained(model_id, low_cpu_mem_usage=True).to(0) trainer = trl.SFTTrainer( model=model, args=args, train_dataset=train_dataset, dataset_text_field='text', max_seq_length=1024, ) trainer.train()
مكتبة Accelerate والصنف Trainer
يعتمد الصنف Trainer على مكتبة Accelerate، والتي هي مكتبة لتدريب نماذج PyTorch بسهولة في البيئات الموزعة مع دعم التكاملات Integrations مثل FullyShardedDataParallel -أو FSDP اختصارًا- و DeepSpeed.
ملاحظة: يمكن مطالعة المزيد حول استراتيجيات تجزئة FSDP أو FSDP Sharding وتفريغ وحدة المعالجة المركزية CPU Offloading وغير ذلك باستخدام الصنف Trainer في دليل FSDP.
يمكننا استخدام مكتبة Accelerate مع الصنف Trainer من خلال تشغيل أمر accelerate.config
لإعداد التدريب لبيئة التدريب الخاصة بنا، حيث ينشئ هذا الأمر ملف config_file.yaml
الذي سيُستخدَم عند تشغيل سكربت التدريب. فيما يلي مثلًا بعض عمليات الضبط النموذجية التي يمكننا إعدادها:
عند استخدام DistributedDataParallel:
compute_environment: LOCAL_MACHINE distributed_type: MULTI_GPU downcast_bf16: 'no' gpu_ids: all machine_rank: 0 # تغيير الرتبة حسب الجهاز main_process_ip: 192.168.20.1 main_process_port: 9898 main_training_function: main mixed_precision: fp16 num_machines: 2 num_processes: 8 rdzv_backend: static same_network: true tpu_env: [] tpu_use_cluster: false tpu_use_sudo: false use_cpu: false
عند استخدام FSDP:
compute_environment: LOCAL_MACHINE distributed_type: FSDP downcast_bf16: 'no' fsdp_config: fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP fsdp_backward_prefetch_policy: BACKWARD_PRE fsdp_forward_prefetch: true fsdp_offload_params: false fsdp_sharding_strategy: 1 fsdp_state_dict_type: FULL_STATE_DICT fsdp_sync_module_states: true fsdp_transformer_layer_cls_to_wrap: BertLayer fsdp_use_orig_params: true machine_rank: 0 main_training_function: main mixed_precision: bf16 num_machines: 1 num_processes: 2 rdzv_backend: static same_network: true tpu_env: [] tpu_use_cluster: false tpu_use_sudo: false use_cpu: false
عند استخدام DeepSpeed:
compute_environment: LOCAL_MACHINE deepspeed_config: deepspeed_config_file: /home/user/configs/ds_zero3_config.json zero3_init_flag: true distributed_type: DEEPSPEED downcast_bf16: 'no' machine_rank: 0 main_training_function: main num_machines: 1 num_processes: 4 rdzv_backend: static same_network: true tpu_env: [] tpu_use_cluster: false tpu_use_sudo: false use_cpu: false
عند استخدام DeepSpeed مع إضافة Accelerate:
compute_environment: LOCAL_MACHINE deepspeed_config: gradient_accumulation_steps: 1 gradient_clipping: 0.7 offload_optimizer_device: cpu offload_param_device: cpu zero3_init_flag: true zero_stage: 2 distributed_type: DEEPSPEED downcast_bf16: 'no' machine_rank: 0 main_training_function: main mixed_precision: bf16 num_machines: 1 num_processes: 4 rdzv_backend: static same_network: true tpu_env: [] tpu_use_cluster: false tpu_use_sudo: false use_cpu: false
يُعَد أمر accelerate_launch
الطريقة الموصَى بها لتشغيل سكربت التدريب على نظام موزع باستخدام مكتبة Accelerate والصنف Trainer مع المعاملات المُحدَّدة في الملف config_file.yaml
الذي يُحفَظ في مجلد ذاكرة التخزين المؤقت للمكتبة Accelerate ويُحمَّل تلقائيًا عند تشغيل أمر accelerate_launch
.
يمكننا مثلًا تشغيل سكربت التدريب run_glue.py
مع ضبط FSDP كما يلي:
accelerate launch \ ./examples/pytorch/text-classification/run_glue.py \ --model_name_or_path google-bert/bert-base-cased \ --task_name $TASK_NAME \ --do_train \ --do_eval \ --max_seq_length 128 \ --per_device_train_batch_size 16 \ --learning_rate 5e-5 \ --num_train_epochs 3 \ --output_dir /tmp/$TASK_NAME/ \ --overwrite_output_dir
ويمكن تحديد المعاملات من الملف config_file.yaml
في سطر الأوامر كما يلي:
accelerate launch --num_processes=2 \ --use_fsdp \ --mixed_precision=bf16 \ --fsdp_auto_wrap_policy=TRANSFORMER_BASED_WRAP \ --fsdp_transformer_layer_cls_to_wrap="BertLayer" \ --fsdp_sharding_strategy=1 \ --fsdp_state_dict_type=FULL_STATE_DICT \ ./examples/pytorch/text-classification/run_glue.py --model_name_or_path google-bert/bert-base-cased \ --task_name $TASK_NAME \ --do_train \ --do_eval \ --max_seq_length 128 \ --per_device_train_batch_size 16 \ --learning_rate 5e-5 \ --num_train_epochs 3 \ --output_dir /tmp/$TASK_NAME/ \ --overwrite_output_dir
ويمكن مطالعة المقال الخاص بتشغيل سكربتات Accelerate على منصة Huggingface لمعرفة المزيد حول أمر accelerate_launch
وعمليات الضبط المخصَّصة.
الخاتمة
وصلنا لختام مقالنا الذي وضحنا فيه استخدام صنف التدريب Trainer من مكتبة Transformers وتعرفنا على طريقة استخدامه وإعداد البيانات والنماذج ومعاملات التدريب التي سيستخدمها، كما ناقشنا أهم المزايا التي يقدمها هذا الصنف والتي تجعله خيارًا مثاليًا لتسريع تدريب النماذج وتحسين أدائها. ننصحكم بتجربة التقنيات التي شرحناها في هذا المقال والاستفادة منها في تحسين مشاريع الذكاء الاصطناعي.
ترجمة -وبتصرّف- للقسم Trainer من توثيقات Hugging Face.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.