اذهب إلى المحتوى

سنتعرف في هذا المقال على الصنف 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 الشيفرة البرمجية الموجودة في حلقة تدريب أساسية، والتي تتضمن ما يلي:

  1. إجراء خطوة تدريب لحساب الخسارة
  2. حساب التدرجات Gradients باستخدام التابع backward
  3. تحديث الأوزان بناءً على التدرجات
  4. تكرار هذه العملية حتى الوصول إلى عدد محدَّد مسبقًا من دورات التدريب 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 ليكون سهل الاستخدام والوصول، وهو يتميز أيضًا بسهولة التخصيص، إذ يمكننا إنشاء أصناف فرعية للعديد من توابع الصنف وتعديلها لدعم الوظيفة التي نريدها دون الحاجة إلى إعادة كتابة حلقة التدريب بالكامل من الصفر كي تتوافق مع هذه الوظيفة، وتتضمن هذه التوابع ما يلي:

يمكننا مثلًا تخصيص التابع 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.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...