Transformers documentation

مزايا Trainer

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

and get access to the augmented documentation experience

to get started

مزايا Trainer

تُظهر كل وصفة أدناه ميزة محددة من ميزات Trainer: دوال الخسارة المخصصة، والتقييم الموفر للذاكرة، واستراتيجيات إنشاء نقاط التفتيش، والمزيد.

افتح قضية إذا كان هناك ميزة أو سير عمل ترغب في رؤيته هنا.

دالة خسارة مخصصة

مرّر compute_loss_func إلى Trainer لاستبدال دالة الخسارة الافتراضية. تعمل الدالة بعد المرور الأمامي وتعرّف فقط كيفية حساب الخسارة من المخرجات. لتعديل المرور الأمامي نفسه، أنشئ فئة فرعية من compute_loss() بدلاً من ذلك.

يجب أن يكون لتدريج دالة الخسارة المخصصة التوقيع التالي:

import torch.nn.functional as F

def my_loss_fn(outputs, labels, num_items_in_batch):
    logits = outputs["logits"]
    loss = F.cross_entropy(logits, labels, reduction="sum")
    return loss / num_items_in_batch
  • outputs هو المخرجات الخام للنموذج (شكل outputs.logits هو (batch, seq_len, vocab_size)).
  • labels هي معرّفات الرموز التي يستخرجها Trainer من دفعة الإدخال قبل تمريرة الأمامية.
  • num_items_in_batch هو عدد أهداف التنبؤ عبر الدفعة المتراكمة بالكامل. بالنسبة لنماذج اللغة السببية، فإنه يعد التسميات المُزاحة (labels[..., 1:])، لأن إزاحة التسميات تترك الموضع 0 لكل تسلسل دون هدف. راجع مقياس الخسارة للتفاصيل. يتخطى Trainer تطبيع الخسارة التلقائي عند توفير دالة خسارة مخصصة، لذا يجب أن تتولى دالتك عملية التطبيع مباشرة.
trainer = Trainer(
    model=model,
    args=TrainingArguments(...),
    train_dataset=train_dataset,
    compute_loss_func=my_loss_fn,
)
trainer.train()

راجع دليل إنشاء فئات فرعية لمزيد من الأمثلة على تجاوز compute_loss().

التقييم عند البدء

اضبط eval_on_start=True لتنفيذ مسار تقييم كامل قبل خطوة التدريب الأولى. يُظهر تقييم ما قبل التدريب المشكلات في خط أنابيب التقييم مبكراً، خاصةً أثناء التشغيلات الطويلة.

يتطلب eval_on_start وجود eval_strategy صالح (مثل "epoch") ومجموعة بيانات للتقييم.

from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        eval_strategy="epoch",
        eval_on_start=True,
    ),
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    compute_metrics=compute_metrics,
)
trainer.train()

تضيف عملية التقييم الكاملة وقتًا، لذا فهي الأكثر فائدة في التشغيلات الأولى أو بعد تعديل compute_metrics.

تقييمات موفرة للذاكرة

أثناء التقييم، ينفّذ Trainer تمريرةً أمامية على كل دفعة، ثم يدمج المخرجات (logits) في متجه واحد على وحدة معالجة الرسوميات. بعد معالجة مجموعة بيانات التقييم بالكامل، ينقل Trainer المخرجات المدمجة إلى وحدة المعالجة المركزية ويستدعي compute_metrics. بالنسبة للنماذج الكبيرة أو مجموعات التقييم الضخمة، قد تستنفد المخرجات المتراكمة ذاكرة وحدة معالجة الرسوميات حتى عندما يعمل التدريب على نفس العتاد بشكل سليم، لأن التدريب يحتفظ بدفعة واحدة من التفعيلات في كل مرة.

eval_accumulation_steps

انقل التنبؤات المتراكمة من وحدة معالجة الرسوميات (GPU) إلى وحدة المعالجة المركزية (CPU) كل n دفعات. تقلل القيم المنخفضة من ذاكرة وحدة معالجة الرسوميات (GPU) على حساب زيادة تكرار النقل إلى وحدة المعالجة المركزية (CPU).

from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        eval_strategy="epoch",
        eval_accumulation_steps=16,   # move predictions to CPU every 16 batches
    ),
    eval_dataset=eval_dataset,
    compute_metrics=compute_metrics,
)
trainer.train()

preprocess_logits_for_metrics

تُستدعى مرة واحدة لكل دفعة تقييم على وحدة معالجة الرسوميات، مباشرةً بعد مسار الأمامي وقبل تراكم القيم اللوجيتية. تستبدل القيمة المُعادة القيم اللوجيتية في eval_pred.predictions. يؤدي تنفيذ الحساب على مستوى الدفعة إلى تقليل حجم المصفوفات لكل دفعة، مما يوفر لـeval_accumulation_steps مصفوفة أصغر حجمًا لتفريغها.

import evaluate
from transformers import Trainer, TrainingArguments

metric = evaluate.load("accuracy")

def preprocess_logits_for_metrics(logits, labels):
    if isinstance(logits, tuple):
        logits = logits[0]
    return logits.argmax(dim=-1)

def compute_metrics(eval_preds):
    preds, labels = eval_preds
    labels = labels[:, 1:].reshape(-1)
    preds = preds[:, :-1].reshape(-1)
    return metric.compute(predictions=preds, references=labels)

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        eval_strategy="epoch",
        eval_accumulation_steps=16,
    ),
    eval_dataset=eval_dataset,
    compute_metrics=compute_metrics,
    preprocess_logits_for_metrics=preprocess_logits_for_metrics,
)
trainer.train()

أداء مُحمِّل البيانات

بشكل افتراضي، ينشئ Trainer مُحمِّل بيانات (dataloader) بقيمة dataloader_num_workers=0. يتم تحميل البيانات في العملية الرئيسية بينما يكون المعالج الرسومي (GPU) في وضع الخمول، مما يظهر على شكل انخفاض في معدل استخدام المعالج الرسومي بين الدفعات (batches).

يتطلب كل من dataloader_persistent_workers وdataloader_prefetch_factor أن يكون dataloader_num_workers > 0.

  • يحافظ dataloader_persistent_workers على عمليات العامل الفرعية نشطة بين الحقب لتجنب إعادة التهيئة من الصفر، وذلك على حساب استهلاك ذاكرة أعلى.
  • يتحكم dataloader_prefetch_factor في عدد الدفعات التي يجهّزها كل عامل مسبقًا. عند استخدام dataloader_prefetch_factor=2 وnum_workers=4، تبقى حتى 8 دفعات في الذاكرة بينما يتدرّب المعالج الرسومي على الدفعة الحالية.
from transformers import TrainingArguments

args = TrainingArguments(
    output_dir="out",
    dataloader_num_workers=4,            # spawn 4 worker subprocesses
    dataloader_persistent_workers=True,  # keep them alive between epochs
    dataloader_prefetch_factor=2,        # each worker preloads 2 batches ahead
)

تجميع العينات حسب الطول

استخدم train_sampling_strategy="group_by_length" لتجميع الأمثلة ذات الأطوال المتشابهة في دفعات واحدة وتقليل عملية الحشو. عند عدم تقديم أطوال محسوبة مسبقًا، يستنتج Trainer هذه الأطوال من مدخل النموذج الأول في كل عنصر من عناصر مجموعة البيانات. ويعمل هذا أيضًا عندما تُرجع مجموعات البيانات متعددة الوسائط المعتمدة على المعالجات كائنات BatchFeature، لأنها حاويات ميزات تشبه المخططات.

from transformers import TrainingArguments

training_args = TrainingArguments(
    output_dir="qwen3-vl-finetuned",
    train_sampling_strategy="group_by_length",
)

إذا كان Dataset يحتوي بالفعل على عمود طول محسوب مسبقًا، فإن Trainer يستخدم ذلك العمود بدلاً من ذلك. اسم العمود الافتراضي هو length. اضبط length_column_name إذا كان مجموعة البيانات الخاصة بك تستخدم اسمًا آخر. تتطلب هذه الاستراتيجية مجموعة بيانات بطول معروف، وتُتجاهل في حالة IterableDataset.

عينة إعادة التوازن الدُفعي

في مجموعات البيانات ذات الأطوال المتغيرة، يؤدي عدم التوازن داخل الدفعة الدقيقة (micro-batch) وعبر الأجهزة إلى إهدار الوقت في عملية الحشو (padding) وإلى خمول الأجهزة عند خطوات مزامنة التدرجات.

اضبط train_sampling_strategy="batch_rebalance" في TrainingArguments لتقليل كلا التأثيرين. ففي كل خطوة من خطوات المُحسِّن:

  1. يُرتّب عينات الدفعة حسب طولها.
  2. يقسّم الدفعة المُرتّبة على الأجهزة بحيث يكون تكلفة الرموز المُكمّلة في كل دفعة فرعية متوازنة. فالدفعات الفرعية التي تحتوي على عينات طويلة تحصل على عدد أقل من العينات، بينما تحصل الدفعات الفرعية التي تحتوي على عينات قصيرة على عدد أكبر.

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

from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        train_sampling_strategy="batch_rebalance",  # balance padding cost across devices
        per_device_train_batch_size=8,              # average samples per micro-batch
        length_column_name="length",                # optional: dataset column with precomputed lengths
    ),
    train_dataset=train_dataset,
)
trainer.train()

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

يحتاج مُولّد العينات إلى معرفة طول كل عينة من أجل فرز الدُفعات وتوازنها. افتراضياً، يفحص Trainer مجموعة البيانات كاملة مرة واحدة عند بدء التدريب لحساب هذه الأطوال. لتخطي هذا الفحص، احسب الأطوال مسبقاً في عمود ضمن مجموعة البيانات (على سبيل المثال، أثناء المعالجة المسبقة) ومرر اسمه عبر length_column_name (افتراضياً "length").

NEFTune

يضيف NEFTune ضوضاء عشوائية إلى تمثيلات الرموز أثناء المرور الأمامي. تعمل هذه الضوضاء كعوامل تنظيم ويمكنها تحسين الأداء في الضبط الدقيق للتعليمات.

فعّل NEFTune عن طريق تعيين neftune_noise_alpha في TrainingArguments. تتراوح قيم alpha النموذجية عادةً بين 5 و15.

from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        num_train_epochs=3,
        neftune_noise_alpha=5,
    ),
    train_dataset=train_dataset,
)
trainer.train()

لا يؤثر NEFTune على التدريب فحسب، بل يُستعاد طبقة التضمين الأصلية بعد انتهاء التدريب.

التسجيل

تحكّم في توقيت ومكان كتابة Trainer لسجلات التدوين باستخدام logging_strategy وlogging_steps وreport_to.

  • يسجّل logging_strategy="steps" كل logging_steps() تحديثات المُحسِّن. استخدم "epoch" بدلاً من ذلك لتسجيل عند نهاية كل حقبة.
  • report_to يوجّه السجلات إلى متتبع تجارب مثل Trackio.
from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        logging_strategy="steps",
        logging_steps=50,               # write a log entry every 50 optimizer updates
        report_to="trackio",            # stream to Trackio (or "wandb", "tensorboard", …)
        run_name="model-experiment-v1", # display name in the tracker
    ),
    train_dataset=train_dataset,
)
trainer.train()

التحقق من النقاط

يحفظ Trainer نقطة تفتيش كل save_steps() تحديث للمحسّن، ويحتفظ بجميعها (أو بأحدث ~TrainingArguments.save_total_limit).

يحافظ save_strategy="best" على نقطة التفتيش الأفضل واحدة فقط وفقاً لمقياس معين. يتم حفظ نقطة تفتيش جديدة فقط عندما يتحسن المقياس المُتتبَّع، مما يوفر مساحة القرص ويتجنب تراكم نقاط التفتيش القديمة.

from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        eval_strategy="epoch",
        save_strategy="best",
        metric_for_best_model="perplexity",   # save when eval perplexity improves
        greater_is_better=False,              # lower perplexity is better
        load_best_model_at_end=True,          # load the best weights after training finishes
    ),
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    compute_metrics=compute_metrics,          # must return {"perplexity": ...}
)
trainer.train()

استئناف التدريب

مرّر resume_from_checkpoint=True إلى train() إذا كان التدريب قد انقطع وتودّ استئنافه دون فقدان التقدم. سيستأنف التدريب من أحدث نقطة تفتيش في output_dir.

trainer.train(resume_from_checkpoint=True)

حدد مسار نقطة التفتيش (checkpoint) لاستئناف التدريب من نقطة محددة.

trainer.train(resume_from_checkpoint="out/checkpoint-1000")

عند الاستئناف، يستعيد Trainer حالة المُحسِّن (optimizer) وحالة المجدول (scheduler) وحالة مولّد الأرقام العشوائية (RNG).

يتطلب استئناف نقطة التفتيش وجود ملفات حالة المُحسِّن والمُجدوِل في مجلد نقطة التفتيش. إذا كانت هذه الملفات مفقودة (على سبيل المثال، عند save_only_model=True)، فإن المُحسِّن يبدأ من الصفر.

التحقق الفوري

عند استخدام نقاط التفتيش الدورية (save_strategy=“steps” أو “epoch”)، تفقد أي تقدم في التدريب يقع بين آخر نقطة تفتيش محفوظة وانقطاع العملية. في العناقيد المشتركة التي تتضمن أعباء عمل قابلة للمقاطعة مثل Kueue، يمكن إنهاء المهام في أي وقت، مما قد يعني أن هذه الفجوة تستهلك ساعات من الحوسبة دون فائدة.

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

فعّله عن طريق تعيين enable_jit_checkpoint=True في TrainingArguments.

from transformers import TrainingArguments

training_args = TrainingArguments(
    output_dir="your-model",
    enable_jit_checkpoint=True,
)

عند استلام إشارة SIGTERM، ينتظر Trainer انتهاء خطوة التدريب الحالية، ثم يحفظ نقطة تفتيش (checkpoint) ويوقف التدريب بسلاسة. يتم إنشاء ملف إشارة (checkpoint-is-incomplete.txt) عند بدء عملية الحفظ، ويُحذف بمجرد اكتمال كتابة نقطة التفتيش بالكامل. إذا ما زالت مجلد نقطة التفتيش يحتوي على هذا الملف، فقد انقطعت عملية الحفظ قبل اكتمالها. لا يتحقق Trainer من وجوده تلقائياً، لذا افحصه بنفسك قبل استئناف التدريب.

استأنف من نقطة التفتيش JIT بنفس الطريقة التي تستأنف بها أي نقطة تفتيش أخرى.

trainer.train(resume_from_checkpoint=True)

يجب أن تضبط مُنسِّقك (orchestrator) للسماح بزمن كافٍ لإكمال نقطة التفتيش (checkpoint). فترة الإيقاف السليم الافتراضية في Kubernetes هي 30 ثانية فقط، وهي عادةً غير كافية للنماذج الأكبر.

Kubernetes
Slurm

اضبط terminationGracePeriodSeconds في مواصفات Pod أو Job الخاصة بك. يختلف الموقع الدقيق لهذا الحقل حسب المدرب (Kubeflow Training Operator، Ray، إلخ).

spec:
  template:
    spec:
      terminationGracePeriodSeconds: 300

احسب فترة السماح المطلوبة على أنها أطول مدة زمنية ممكنة لخطوة التدريب الواحدة، بالإضافة إلى وقت حفظ نقطة التفتيش، بالإضافة إلى تأخير kill_wait الذي مدته 3 ثوانٍ قبل بدء حفظ نقطة التفتيش. على سبيل المثال، إذا استغرقت خطوة التدريب حتى دقيقتين، واستغرق حفظ نقطة التفتيش دقيقتين، فعيّن وقت سماح لا يقل عن 243 ثانية.

Update on GitHub