# مزايا Trainer

تُظهر كل وصفة أدناه ميزة محددة من ميزات [Trainer](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer): دوال الخسارة المخصصة، والتقييم الموفر للذاكرة، واستراتيجيات إنشاء نقاط التفتيش، والمزيد.

> [!TIP]
> افتح [قضية](https://github.com/huggingface/transformers/issues/new/choose) إذا كان هناك ميزة أو سير عمل ترغب في رؤيته هنا.

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

مرّر [compute_loss_func](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer.compute_loss_func) إلى [Trainer](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer) لاستبدال دالة الخسارة الافتراضية. تعمل الدالة *بعد* المرور الأمامي وتعرّف فقط كيفية حساب الخسارة من المخرجات. لتعديل المرور الأمامي نفسه، [أنشئ فئة فرعية](./trainer_customize#compute-loss) من [compute_loss()](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer.compute_loss) بدلاً من ذلك.

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

```py
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](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer) من دفعة الإدخال قبل تمريرة الأمامية.
- `num_items_in_batch` هو عدد أهداف التنبؤ عبر الدفعة المتراكمة بالكامل. بالنسبة لنماذج اللغة السببية، فإنه يعد التسميات المُزاحة (`labels[..., 1:]`)، لأن إزاحة التسميات تترك الموضع 0 لكل تسلسل دون هدف. راجع [مقياس الخسارة](./grad_accumulation#loss-scaling) للتفاصيل. يتخطى [Trainer](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer) تطبيع الخسارة التلقائي عند توفير دالة خسارة مخصصة، لذا يجب أن تتولى دالتك عملية التطبيع مباشرة.

```py
trainer = Trainer(
    model=model,
    args=TrainingArguments(...),
    train_dataset=train_dataset,
    compute_loss_func=my_loss_fn,
)
trainer.train()
```

> [!NOTE]
> راجع [دليل إنشاء فئات فرعية](./trainer_customize#compute-loss) لمزيد من الأمثلة على تجاوز [compute_loss()](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer.compute_loss).

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

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

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

```py
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](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer) تمريرةً أمامية على كل دفعة، ثم يدمج المخرجات (logits) في متجه واحد على وحدة معالجة الرسوميات. بعد معالجة مجموعة بيانات التقييم بالكامل، ينقل [Trainer](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer) المخرجات المدمجة إلى وحدة المعالجة المركزية ويستدعي `compute_metrics`. بالنسبة للنماذج الكبيرة أو مجموعات التقييم الضخمة، قد تستنفد المخرجات المتراكمة ذاكرة وحدة معالجة الرسوميات حتى عندما يعمل التدريب على نفس العتاد بشكل سليم، لأن التدريب يحتفظ بدفعة واحدة من التفعيلات في كل مرة.

### eval_accumulation_steps

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

```py
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` مصفوفة أصغر حجمًا لتفريغها.

```py
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](/docs/transformers/main/ar/main_classes/trainer#transformers.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 دفعات في الذاكرة بينما يتدرّب المعالج الرسومي على الدفعة الحالية.

```py
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](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer) هذه الأطوال من مدخل النموذج الأول في كل عنصر من عناصر مجموعة البيانات. ويعمل هذا أيضًا عندما تُرجع مجموعات البيانات متعددة الوسائط المعتمدة على المعالج كائنات [BatchFeature](/docs/transformers/main/ar/main_classes/feature_extractor#transformers.BatchFeature)، لأنها حاويات ميزات تشبه الخرائط.

```py
from transformers import TrainingArguments

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

إذا كان [Dataset](https://huggingface.co/docs/datasets/main/en/package_reference/main_classes#datasets.Dataset) يحتوي بالفعل على عمود طول محسوب مسبقًا، فإن [Trainer](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer) يستخدم ذلك العمود بدلاً من ذلك. اسم العمود الافتراضي هو `length`. اضبط `length_column_name` إذا كان مجموعة البيانات الخاصة بك تستخدم اسمًا آخر. تتطلب هذه الاستراتيجية مجموعة بيانات بطول معروف، وتُتجاهل في حالة [IterableDataset](https://huggingface.co/docs/datasets/main/en/package_reference/main_classes#datasets.IterableDataset).

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

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

اضبط `train_sampling_strategy="batch_rebalance"` في [TrainingArguments](/docs/transformers/main/ar/main_classes/trainer#transformers.TrainingArguments) لتقليل كلا التأثيرين. ففي كل خطوة من خطوات المُحسِّن:

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

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

```py
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](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer) مجموعة البيانات كاملة مرة واحدة عند بدء التدريب لحساب هذه الأطوال. لتخطي هذا الفحص، احسب الأطوال مسبقاً في عمود ضمن مجموعة البيانات (على سبيل المثال، أثناء المعالجة المسبقة) ومرر اسمه عبر `length_column_name` (افتراضياً `"length"`).

## NEFTune

يضيف [NEFTune](https://hf.co/papers/2310.05914) ضوضاء عشوائية إلى تمثيلات الرموز أثناء المرور الأمامي. تعمل هذه الضوضاء كعوامل تنظيم ويمكنها تحسين الأداء في الضبط الدقيق للتعليمات.

فعّل NEFTune عن طريق تعيين `neftune_noise_alpha` في [TrainingArguments](/docs/transformers/main/ar/main_classes/trainer#transformers.TrainingArguments). تتراوح قيم alpha النموذجية عادةً بين 5 و15.

```py
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](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer) لسجلات التدوين باستخدام `logging_strategy` و`logging_steps` و`report_to`.

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

```py
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](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer) نقطة تفتيش كل `save_steps()` تحديث للمحسّن، ويحتفظ بجميعها (أو بأحدث `~TrainingArguments.save_total_limit`).

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

```py
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()](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer.train) إذا كان التدريب قد انقطع وتودّ استئنافه دون فقدان التقدم. سيستأنف التدريب من أحدث نقطة تحقق في `output_dir`.

```py
trainer.train(resume_from_checkpoint=True)
```

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

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

عند الاستئناف، يستعيد [Trainer](/docs/transformers/main/ar/main_classes/trainer#transformers.Trainer) حالة المُحسِّن (optimizer) وحالة المجدول (scheduler) وحالة مولّد الأرقام العشوائية (RNG).

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

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

عند استخدام نقاط التفتيش الدورية (save_strategy="steps" أو "epoch")، تفقد أي تقدم في التدريب يقع بين آخر نقطة تفتيش محفوظة وانقطاع العملية. في العناقيد المشتركة التي تتضمن أعباء عمل قابلة للمقاطعة مثل [Kueue](https://kueue.sigs.k8s.io/)، يمكن إنهاء المهام في أي وقت، مما قد يعني أن هذه الفجوة تستهلك ساعات من الحوسبة دون فائدة.

JIT يُغلق التوثيق الفوري (Just-In-Time) هذه الفجوة. عندما يستقبل المُدرِّب إشارة SIGTERM، يحفظ نقطة توثيق في النقطة الدقيقة التي انقطع فيها التدريب، مما يتيح لك استئناف العمل بأقل خسارة ممكنة للتقدم. يعمل هذا التوثيق بالتوازي مع التوثيق الدوري. تحمي الحفظات الدورية من الأعطال وأعطال الأجهزة، بينما تحمي الحفظات الفورية من الاستحواذ (preemption) والإيقاف السليم.

فعّله عن طريق تعيين `enable_jit_checkpoint=True` في [TrainingArguments](/docs/transformers/main/ar/main_classes/trainer#transformers.TrainingArguments).

```py
from transformers import TrainingArguments

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

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

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

```py
trainer.train(resume_from_checkpoint=True)
```

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

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

```yaml
spec:
  template:
    spec:
      terminationGracePeriodSeconds: 300
```

استخدم `--signal=TERM@<seconds>` في سكربت sbatch الخاص بك لإرسال SIGTERM قبل انتهاء مهلة الوقت المحددة للعمل.

```bash
#SBATCH --signal=TERM@300
```

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

