# كتابة اختبارات النموذج

تستخدم مجموعة اختبارات Transformers بنية مبنية على مزيج (mixin) لتوليد أكثر من 100 اختبار تلقائيًا من الحد الأدنى من الكود. تكتب كمية صغيرة من الكود الخاص بالنموذج، ويتولى المزيج (mixins) مهام الحفظ/التحميل، والتوليد، والخطوط الأنابيب (pipelines)، والتدريب، والتوازي على مستوى الموترات (tensor parallelism).

شغّل اختبارات نموذجك باستخدام الأوامر التالية.

```bash
# run your model's tests
pytest tests/models/mymodel/test_modeling_mymodel.py -v

# run a specific test
pytest tests/models/mymodel/test_modeling_mymodel.py::MyModelTest::test_model

# run tests matching a keyword pattern (useful to run all integration tests)
pytest tests/models/mymodel/ -k integration -v

# include slow integration tests
RUN_SLOW=1 pytest tests/models/mymodel/ -v
```

تشغّل منظومة Hugging Face CI اختبارات النماذج دون `@slow` مع كل طلب سحب، بينما تُنفَّذ الاختبارات البطيئة وفق جدول ليلي (راجع [فحوصات طلبات السحب](./pr_checks) لمعرفة ما تتحقق منه منظومة CI).

## اختر فئة اختبار أساسية

تغطي ثلاث فئات أساسية أكثر عائلات النماذج شيوعاً. اختر الفئة التي تتوافق مع نمط نموذجك.

| الفئة الأساسية | يُستخدم | مزيج |
|---|---|---|
| `CausalLMModelTest` | نماذج اللغة السببية | `ModelTesterMixin`, `GenerationTesterMixin`, `PipelineTesterMixin`, `TrainingTesterMixin`, `TensorParallelTesterMixin` |
| `VLMModelTest` | نماذج الرؤية واللغة | `ModelTesterMixin`, `GenerationTesterMixin`, `PipelineTesterMixin` |
| `ALMModelTest` | نماذج اللغة والصوت | `ModelTesterMixin`, `GenerationTesterMixin`, `PipelineTesterMixin` |

يتشارك `VLMModelTest` و`ALMModelTest` في الوالد المشترك `MultiModalModelTest` الذي يُضمّن الإعدادات الفرعية داخل إعداد علوي مركّب، ويضع رموز المحلّلات الخاصة بالأنماط في `input_ids` إلى جانب ميزات النمط الخام (الصوت أو الرؤية). لا يستخدم `CausalLMModelTest` الوالد متعدد الأنماط. بل يُبنى على المزيجات الثلاث المشتركة ويضيف `TrainingTesterMixin` و`TensorParallelTesterMixin` لتغطية التدريب والتوازي على مستوى المصفوفات.

بالنسبة إلى البنى المعمارية التي لا تنتمي إلى أيٍّ من الأنماط الثلاثة (المُشفِّر فقط، المُشفِّر-المُفكِّك، إلخ)، قم ببناء بنية الاختبار مباشرةً من [نمط الصنفين](#modeltester-and-modeltest) و[مزيجات الاختبار](#test-mixins) الموضّحة أدناه.

## CausalLMModelTest

`CausalLMModelTest` هي الفئة الأساسية الموصى بها لاختبار نماذج اللغة السببية. ترث من خمسة [مزيج اختبارات](#test-mixins) وتولّد الاختبارات تلقائيًا للحفظ/التحميل، والتوليد، والخطوط الأنابيب، والتدريب، والتوازي على مستوى الموترات.

```py
import unittest

from transformers.testing_utils import require_torch
from transformers import is_torch_available

from ...causal_lm_tester import CausalLMModelTest, CausalLMModelTester

if is_torch_available():
    from transformers import MyModel

class MyModelTester(CausalLMModelTester):
    if is_torch_available():
        base_model_class = MyModel

@require_torch
class MyModelTest(CausalLMModelTest, unittest.TestCase):
    model_tester_class = MyModelTester
```

توفر هاتان الصنفان تغطية اختبارية كاملة لـ `MyModel` وجميع أصناف رؤوسه (`MyModelForCausalLM`، `MyModelForSequenceClassification`، إلخ). راجع [tests/models/llama/test_modeling_llama.py](https://github.com/huggingface/transformers/blob/main/tests/models/llama/test_modeling_llama.py) للحصول على مثال حقيقي.

يتطلب `CausalLMModelTester` فقط `base_model_class`. يقوم المُختبِر بإزالة لاحقة `Model` للحصول على الاسم الأساسي (حيث تصبح `LlamaModel` إلى `Llama`)، ثم يضيف لواحق مثل `Config` أو `ForCausalLM` لاكتشاف الفئات ذات الصلة. إذا لم تكن الفئة موجودة في الوحدة، تبقى الخاصية `None` ويتخطى المُختبِر الاختبارات المقابلة.

### التجاوز عن القيم الافتراضية في CausalLMTester

إذا لم يتبع نموذجك التسمية القياسية، أو كنت بحاجة إلى تخصيص السلوك، فقم بتجاوز السمات على المُختبِر أو فئة الاختبار.

```py
class MyModelTester(CausalLMModelTester):
    if is_torch_available():
        base_model_class = MyModel
        # override if the class name doesn't follow the convention
        causal_lm_class = MyCustomCausalLM

@require_torch
class MyModelTest(CausalLMModelTest, unittest.TestCase):
    model_tester_class = MyModelTester
    # disable embedding resize tests
    test_resize_embeddings = False
```

بالنسبة إلى النماذج التي تتطلب معلمات مُخصّصة لمُنشئ الاختبار، تجاوز `__init__` واستدعِ `super().__init__(parent=parent)` قبل تعيين السمات الإضافية. راجع [tests/models/youtu/test_modeling_youtu.py](https://github.com/huggingface/transformers/blob/main/tests/models/youtu/test_modeling_youtu.py) كمثال حقيقي.

```py
class YoutuModelTester(CausalLMModelTester):
    if is_torch_available():
        base_model_class = YoutuModel

    def __init__(self, parent, kv_lora_rank=16, q_lora_rank=32):
        super().__init__(parent=parent)
        self.kv_lora_rank = kv_lora_rank
        self.q_lora_rank = q_lora_rank
```

## VLMModelTest

`VLMModelTest` هي الفئة الأساسية لنماذج الرؤية واللغة. ترث من ثلاثة امتزاجات (`ModelTesterMixin`، `GenerationTesterMixin`، `PipelineTesterMixin`) وتضبط `_is_composite = True` للتعامل مع عدة نماذج فرعية.

```py
import unittest

from transformers.testing_utils import require_torch
from transformers import is_torch_available

from ...vlm_tester import VLMModelTest, VLMModelTester

if is_torch_available():
    from transformers import (
        MyVLMConfig,
        MyVLMModel,
        MyVLMTextConfig,
        MyVLMVisionConfig,
        MyVLMForConditionalGeneration,
    )

class MyVLMTester(VLMModelTester):
    if is_torch_available():
        base_model_class = MyVLMModel
        config_class = MyVLMConfig
        text_config_class = MyVLMTextConfig
        vision_config_class = MyVLMVisionConfig
        conditional_generation_class = MyVLMForConditionalGeneration

@require_torch
class MyVLMTest(VLMModelTest, unittest.TestCase):
    model_tester_class = MyVLMTester
```

### تجاوز القيم الافتراضية في VLMModelTester

عندما يحتاج نموذج VLM إلى معلمات رؤية مخصصة أو قيم إعدادات غير افتراضية، قم بتجاوز `__init__`. اضبط القيم الافتراضية باستخدام `setdefault` قبل استدعاء `super().__init__(parent, **kwargs)`. يُظهر المثال أدناه بعض القيم الافتراضية الأولى من [tests/models/qianfan_ocr/test_modeling_qianfan_ocr.py](https://github.com/huggingface/transformers/blob/main/tests/models/qianfan_ocr/test_modeling_qianfan_ocr.py).

```py
class QianfanOCRVisionText2TextModelTester(VLMModelTester):
    base_model_class = QianfanOCRModel
    config_class = QianfanOCRConfig
    text_config_class = Qwen3Config
    vision_config_class = QianfanOCRVisionConfig
    conditional_generation_class = QianfanOCRForConditionalGeneration

    def __init__(self, parent, **kwargs):
        kwargs.setdefault("image_token_id", 1)
        kwargs.setdefault("image_size", 32)
        kwargs.setdefault("patch_size", 4)
        kwargs.setdefault("num_channels", 3)
        # ... more defaults
        super().__init__(parent, **kwargs)
```

تختلف اختبارات VLM عن `CausalLMModelTest` في عدة نقاط.

- يجب عليك تعيين `config_class` و`text_config_class` و`vision_config_class` و`conditional_generation_class` على المُختبِر.
- لا يتضمن `VLMModelTest` أيًا من `TrainingTesterMixin` أو `TensorParallelTesterMixin`.
- يقبل `__init__` الخاص بالمختبر معاملات الرؤية (`image_size`، `patch_size`، `num_channels`، `num_image_tokens`) من `**kwargs` و`setdefault()`.
- `ConfigTester` يستخدم `has_text_modality=False` لأن الإعداد العلوي هو إعداد مركّب وليس إعداد نموذج نصي.

## ALMModelTest

`ALMModelTest` هي الفئة الأساسية لنماذج الصوت واللغة (ALMs) مثل Qwen2Audio وAudioFlamingo3 وGraniteSpeech. وهي تعكس نمط نماذج الرؤية واللغة (VLM) مع الفئة الأم `MultiModalModelTest` نفسها واكتشاف تلقائي لفئات الرؤوس. يتم استبدال آلية جانب الرؤية بخصائص صوتية، وتكوين فرعي للصوت، واستراتيجية لتوزيع رموز الصوت.

```py
class MyALMTester(ALMModelTester):
    config_class = MyALMConfig
    text_config_class = MyALMTextConfig
    audio_config_class = MyALMAudioConfig
    conditional_generation_class = MyALMForConditionalGeneration
    audio_mask_key = "feature_attention_mask"

class MyALMTest(ALMModelTest, unittest.TestCase):
    model_tester_class = MyALMTester
```

### تجاوز القيم الافتراضية في ALMModelTester

يُعيّن `__init__` الخاصّ بالاختبار الافتراضيات المحددة لـ ALM (`feat_seq_length=128`، `num_mel_bins=80`، `audio_token_id=0`). تجاوزها باستخدام `setdefault` قبل استدعاء `super().__init__(parent, **kwargs)`.

يُخبر سِمَتان من سِمات الفئة المُختبِرَ كيف يُسمّي نموذجك الأشياء.

- `audio_mask_key`: اسم معامل الكلمة المفتاحية الذي يتوقعه النموذج الخاص بك للقناع الصوتي (`"feature_attention_mask"`، `"input_features_mask"`، إلخ). اتركه `None` إذا كان نموذجك لا يستهلك قناعًا صوتيًا منفصلًا.
- `audio_config_key`: اسم الخاصية التي يستخدمها الإعداد الرئيسي لتضمين إعداد الصوت الفرعي. القيمة الافتراضية هي `"audio_config"` لكن نماذج مثل GraniteSpeech تستخدم `"encoder_config"`.

```py
class Qwen2AudioModelTester(ALMModelTester):
    def __init__(self, parent, **kwargs):
        kwargs.setdefault("feat_seq_length", 60)
        kwargs.setdefault("max_source_positions", kwargs["feat_seq_length"] // 2)
        super().__init__(parent, **kwargs)
```

يتطلب `ALMModelTester` منك تجاوز خطاف واحد، وهو `get_audio_embeds_mask(audio_mask)`، كما يعرض خطافات اختيارية إضافية للتخصيص.

- `get_audio_embeds_mask(audio_mask)`: تُرجع قناع مواضع تضمينات الصوت لكل دفعة بعد عملية تقليل العينات في المُشفِّر. يستخدم المُختبِر مجموع هذا القناع على مستوى الصفوف لتحديد عدد عناصر `audio_token_id` التي يجب إدراجها في `input_ids`، لذا يجب أن يتطابق هذا العدد مع ما يُخرجه مُشفِّرك.
- `create_audio_features()`: تُرجع متجه ميزات الصوت. الشكل الافتراضي هو `[batch_size, num_mel_bins, feat_seq_length]`. تجاوز هذا الدالة إذا كان نموذجك، مثل GraniteSpeech، يتوقع ميزات ذات أولوية زمنية (`[batch_size, feat_seq_length, num_mel_bins]`).
- `create_audio_mask()`: تُرجع قناع الانتباه على مستوى الصوت. يقوم الإعداد الافتراضي ببناء منطقة صالحة متصلة عشوائياً لكل صف في الدفعة. استبدله بقناع حتمي بطول كامل إذا كانت اختباراتك تقارن بين استدعائين لـ `prepare_config_and_inputs_for_common()`، أو إذا كان مُرمِّز الصوت لديك يُحوَّل إلى واجهة خلفية ترفض الأقنعة غير الفارغة.
- `place_audio_tokens(input_ids, config, num_audio_tokens)`: يضع رموز المحلّلات الصوتية بشكل متتالي بعد `BOS`. لا تُعدّل هذا الدالة إلا إذا كان نموذجك يتطلب تخطيطًا مختلفًا.
- `get_audio_feature_key()`: تُرجع مفتاح قاموس المدخلات الخاص بسمات الصوت (افتراضيًا `"input_features"`).

بالإضافة إلى اختبارات الوسائط المتعددة الموروثة، يضيف `ALMModelTest` الاختبار `test_mismatching_num_audio_tokens`. يتحقق هذا الاختبار من أن النموذج يرمي `ValueError` واضحاً عندما لا يتطابق عدد ميزات الصوت مع عدد رموز الوكيل الصوتية في `input_ids`، ويتأكد من أن الموجّه الذي يحتوي على مقاطع صوتية متعددة يمرر بنجاح.

## اكتب اختبارات لمعماريات أخرى

للمعماريات غير القياسية مثل معماريات المُشفِّر فقط، أو المُشفِّر-المُفكِّك، أو الصوتية، أو غيرها، قم ببناء بنية الاختبار مباشرةً من نمط الصنفين ومزيجات الاختبار (test mixins) الموضحة أدناه.

### ModelTester و ModelTest

يتبع كل ملف اختبار للنموذج نفس البنية.

1. `ModelTester` (فئة عادية) تنشئ إعدادات صغيرة ومدخلات وهمية للاختبار، كما يمكنها استضافة اختبارات انحدار صغيرة خاصة بالنموذج.
2. `ModelTest` (المشتق من `unittest.TestCase` مع مزيج من الخصائص) يرث الاختبارات المولّدة تلقائيًا وينفّذها على كل متغيّر من نماذج النموذج.

يستدعي `ModelTest` الدالة `prepare_config_and_inputs_for_common()` على المُختبِر (tester) للحصول على مجموعة مرتبة من نوع `(config, inputs_dict)`. وتعتمد جميع الإضافات (mixins) على `prepare_config_and_inputs_for_common()` للحصول على بيانات الاختبار.

### اختبار المزيج

اختر الإضافات التي يحتاجها نموذجك.

| مزيج | ملف المصدر | ما يختبره |
|---|---|---|
| `ModelTesterMixin` | `tests/test_modeling_common.py` | الحفظ/التحميل، نقطة التفتيش للتدرّج، توقيع الدالة الأمامية، السمات الشائعة |
| `GenerationTesterMixin` | `tests/generation/test_utils.py` | الطمع، العينة، البحث الحزمي، فك الترميز المساعد |
| `PipelineTesterMixin` | `tests/test_pipeline_mixin.py` | اختبار واحد لكل مهمة خط أنابيب |
| `TrainingTesterMixin` | `tests/test_training_mixin.py` | الانحياز على دفعة صغيرة |
| `TensorParallelTesterMixin` | `tests/test_tensor_parallel_mixin.py` | التوازي الموزّع للتّنسورات |

### كتابة اختبار للنموذج

راجع [tests/models/modernbert/test_modeling_modernbert.py](https://github.com/huggingface/transformers/blob/main/tests/models/modernbert/test_modeling_modernbert.py) للحصول على مثال عملي كامل. الخطوات الأساسية مبيّنة أدناه.

1. تقوم فئة `ModelTester` ببناء إعدادات صغيرة ومدخلات وهمية. حافظ على الأبعاد صغيرة حتى تنتهي الاختبارات خلال ثوانٍ على المعالج المركزي. استخدم أدوات المصفوفات الثلاثة أدناه لبناء المدخلات.

    - `ids_tensor(shape, vocab_size)`: مصفوفة أعداد صحيحة عشوائية ضمن `[0, vocab_size)`. تُستخدم مع `input_ids` و`token_type_ids` ومصفوفات التسميات.
    - `random_attention_mask(shape)`: مصفوفة ثنائية (تتكون من أصفار وواحدات) يكون فيها الرمز الأول دائماً 1. يُستخدم لـ `attention_mask`.
    - `floats_tensor(shape, scale=1.0)`: مصفوفة عشوائية من الأعداد العشرية. تُستخدم للمدخلات المستمرة مثل `pixel_values` أو `inputs_embeds`.

    يجب على المُختبِر تنفيذ `get_config()` و`prepare_config_and_inputs()` و`prepare_config_and_inputs_for_common()`. أضف دوال `create_and_check_*` لكل رأس مهمة (النموذج الأساسي، تصنيف التسلسل، تصنيف الرموز، إلخ).

2. ورث من المزيجات (mixins) التي يحتاجها نموذجك، وعرّف `all_model_classes` و`pipeline_model_mapping`، وحدد `setUp()`. اكتب دوال `test_*` تفوّض المهمة إلى دوال `create_and_check_*` الخاصة بمختبر الاختبارات.

3. لكل رأس مهمة، أضف طريقة `create_and_check_*` على المُختبِر تُنشئ النموذج، وتُنفّذ تمريرة أمامية، وتتحقق من أشكال المخرجات. ثم أضف طريقة `test_*` مقابلة على فئة الاختبار.

### تنظيم الملفات

توجد ملفات الاختبار في `tests/models/mymodel/` وفقاً للهيكل الموضح أدناه.

```text
tests/models/mymodel/
├── __init__.py
├── test_modeling_mymodel.py            # model tests (required)
├── test_tokenization_mymodel.py        # tokenizer tests (if custom tokenizer)
├── test_image_processing_mymodel.py    # image processor tests (if vision model)
├── test_feature_extraction_mymodel.py  # feature extractor tests (if audio/speech model)
└── test_processing_mymodel.py          # processor tests (if multimodal)
```

تتبع اختبارات المُجزِّئ (Tokenizer) النمط نفسه. ورِّث `TokenizerTesterMixin` من `tests/test_tokenization_common.py`، واضبط بعض السمات، لتحصل على اختبارات مُولَّدة تلقائيًا. راجع [tests/models/llama/test_tokenization_llama.py](https://github.com/huggingface/transformers/blob/main/tests/models/llama/test_tokenization_llama.py) كمثال.

## اختبارات الإعداد

يتحقق `ConfigTester` من أن فئة الإعدادات تتعامل مع التسلسل، والحفظ/التحميل، والخصائص القياسية بشكل صحيح. تتضمن `CausalLMModelTest` و`VLMModelTest` اختبارات الإعدادات تلقائيًا. بالنسبة للمسار العام باستخدام `ModelTester` و`ModelTest`، عرّف مُختبِر الإعدادات يدويًا في `setUp()`.

```py
from tests.test_configuration_common import ConfigTester

def setUp(self):
    self.config_tester = ConfigTester(self, config_class=MyModelConfig, hidden_size=32)

def test_config(self):
    self.config_tester.run_common_tests()
```

`run_common_tests()` ينفّذ عدة فحوصات.

- يتحقق من وجود خصائص شائعة مثل `hidden_size` و`num_attention_heads` و`num_hidden_layers` (و`vocab_size` إذا كان `has_text_modality=True`).
- يختبر تسلسل JSON باستخدام `to_json_string()` و`to_json_file()`.
- تُعيد `save_pretrained()` و`from_pretrained()` إلى الحالة الأصلية.
- يتحقق من اتساق `id2label` و`label2id`.
- ينشئ تكوينًا دون أي حُجج للتحقق من التهيئة الافتراضية.
- يُعيّن معاملات مشتركة مثل `output_hidden_states` ويتأكد من تخزينها بشكل صحيح.

مرّر `has_text_modality=False` للنماذج البصرية فقط التي تفتقر إلى `vocab_size`، ومرّر `**kwargs` إضافية لتجاوز الإعدادات الافتراضية.

```py
self.config_tester = ConfigTester(
    self, config_class=MyVisionConfig, has_text_modality=False, hidden_size=64
)
```

## اختبارات التكامل والنماذج الصغيرة

تستخدم اختبارات المزيج (Mixin tests) إعدادات صغيرة بأوزان عشوائية للتحقق من سلوك النموذج بسرعة. أما اختبارات التكامل (Integration tests) فتشغّل الاستدلال (inference) باستخدام أوزان مُسبقة التدريب الفعلية للتحقق من صحة المخرجات. النماذج الصغيرة على Hub صغيرة الحجم بما يكفي لاختبارات CI السريعة، لكنها مُنظّمة على غرار نقاط التفتيش (checkpoints) الفعلية.

### كتابة اختبارات التكامل

ضع اختبارات التكامل في فئة اختبار منفصلة، وعلّمها بـ `@slow`، وأدرج `MemoryCleanupMixin`. يقوم كل اختبار بتنزيل أوزان حقيقية، وتشغيل الاستدلال، والتحقق من المخرجات مقابل القيم المتوقعة. يحرر المزيج الذاكرة التي يستهلكها كل اختبار، وينفّذ طرق الاختبار تحت `torch.no_grad()` — راجع [إطلاق الذاكرة بين الاختبارات](#releasing-memory-between-tests) لمعرفة ما يفعله وكيفية الاستثناء منه.

```py
import torch
from transformers import AutoTokenizer
from transformers.testing_utils import MemoryCleanupMixin, require_torch, slow, torch_device

class MyModelIntegrationTest(MemoryCleanupMixin, unittest.TestCase):
    @slow
    @require_torch
    def test_inference(self):
        model = MyModelForCausalLM.from_pretrained("myorg/mymodel-base").to(torch_device)
        tokenizer = AutoTokenizer.from_pretrained("myorg/mymodel-base")
        inputs = tokenizer("Hello, world", return_tensors="pt").to(torch_device)

        outputs = model(**inputs)

        # check against expected values
        expected_slice = torch.tensor([[-0.1234, 0.5678, -0.9012]])
        torch.testing.assert_close(outputs.logits[0, :1, :3], expected_slice, atol=1e-4, rtol=1e-4)
```

علّم أي اختبار بـ `@slow` إذا كان يقوم بتنزيل الأوزان، أو تحميل مجموعة بيانات كبيرة، أو يستغرق أكثر من بضع ثوانٍ. يتخطى [اختبار CI الخاص بطلب السحب](./pr_checks) الاختبارات البطيئة، لكن الجدولة الليلية تشغّلها.

#### إفراج عن الذاكرة بين الاختبارات

تحمّل اختبارات التكامل نقاط تفتيش حقيقية، لذا فإن اختباراً يحتفظ بمراجع إلى نموذج يمكن أن يستهلك كل الذاكرة المتاحة لأي عملية تُنفَّذ بعده. يتولى `MemoryCleanupMixin`، الموجود في `tests/test_memory_cleanup_mixin.py`، معالجة ذلك على مستوى الفئة بأكملها:

- يُنفّذ `cleanup(torch_device, gc_collect=True)` قبل وبعد كل اختبار حتى لا تنتقل أي بقايا.
- يحذف السمات التي أضافها الاختبار على `self` (بما في ذلك كاشات `@cached_property`) وعلى الفئة (على سبيل المثال `cls.model = ...` في `setUpClass`). يحافظ Pytest على بقاء كائنات الاختبار حية طوال الجلسة، لذا لا يمكن لـ`gc.collect()` تحرير الكائنات التي لا تزال هذه المراجع تحتفظ بها.
- تشغّل طرق الاختبار تحت `torch.no_grad()` حتى لا تحتفظ عملية المرور الأمامي بالتفعيلات.

تضبط الفئات التي تُدرّب أو تستدعي `backward()` قيمة `run_under_no_grad = False`. أما الفئة التي تجمع بين الأمرين فتضع `@with_grad` أو `@with_no_grad` على طرق الاختبار الفردية بدلاً من ذلك.

تُحفظ السمات المُعيَّنة في جسم الفئة، بينما تُهمل كل ما يُضاف لاحقًا. إذا تجاوزت `setUp`، فاستدعِ `super().setUp()`: إذ يلتقط المزيج (mixin) سمات الكائن هناك، وسيُصدر خطأً في حال عدم استدعائه.

> [!TIP]
> يجمع `MemoryCleanupTestCase` بين المكوّن المختلط (mixin) و`TestCasePlus`، وذلك للاختبارات التي ترغب أيضًا في إزالة المجلدات المؤقتة تلقائيًا.

لاكتشاف اختبار تسرّب الذاكرة، اضبط `TRANSFORMERS_TEST_MEMORY_LEAK_MIB` على ميزانية محددة بوحدة ميغابايت؛ وسيتم الإبلاغ عن أي اختبار يترك تخصيصًا أكبر من ذلك على الجهاز مع ذكر ذروة استهلاكه. أضف `TRANSFORMERS_TEST_MEMORY_LEAK_MODE=error` لتحويل التحذير إلى فشل. هذا الفحص معطّل افتراضيًا، وينبغي تفعيله عند البحث عن بقايا تخصيصات. كما أن عملية التفكيك المعتادة في الميكسين (mixin) تشغّل `gc.collect`، مما قد يؤدي إلى مسح التخصيص الذي ترغب في فحصه أثناء إعادة إنتاج التسريب.

#### اختبارات تكامل التوليد

استخدم `do_sample=False` في اختبارات التوليد حتى تكون المخرجات حتمية عبر التكرارات والأجهزة. بالنسبة لنماذج مزيج الخبراء، استدعِ أيضاً `model.set_experts_implementation("eager")` قبل التوليد لفرض مسار ثابت لتوجيه الخبراء. بدونه، قد تُغيّر الفروق العددية الصغيرة في الموجّه الخبير الذي يتولى معالجة الرمز، مما يغيّر المخرجات.

```py
@slow
@require_torch
def test_generate(self):
    model = MyModelForCausalLM.from_pretrained("myorg/mymodel-base").to(torch_device)
    tokenizer = AutoTokenizer.from_pretrained("myorg/mymodel-base")
    inputs = tokenizer("Hello, world", return_tensors="pt").to(torch_device)

    # model.set_experts_implementation("eager")  # uncomment for MoE models
    generated_ids = model.generate(**inputs, max_new_tokens=20, do_sample=False)
    output = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)
    self.assertEqual(output, ["Hello, world! This is the expected continuation..."])
```

#### التوقعات الخاصة بالمعدات

تُنفّذ اختبارات CI الخاصة بـ Transformers الاختبارات البطيئة على بطاقة NVIDIA A10. قد تختلف النتائج العددية قليلاً بين أجيال وحدات معالجة الرسوميات (GPU)، لذا تستخدم اختبارات التكامل فئة [Expectations](https://github.com/huggingface/transformers/blob/main/src/transformers/testing_utils.py#L3247) لتسجيل القيم المتوقعة لكل جهاز. تختار `Expectations` التطابق الأنسب للأجهزة الحالية بناءً على مفاتيح SM من نوع `(device_type, (major, minor))`، وتلجأ إلى قيمة افتراضية عند عدم وجود تطابق.

شغّل `torch.cuda.get_device_capability()` لطباعة إصدار SM المحلي لديك (مثل `(8, 6)` لبطاقة A10، أو `(9, 0)` لبطاقة H100).

```py
from transformers.testing_utils import Expectations

expected_texts = Expectations(
    {
        ("cuda", (8, 6)): ["Hello, world! This is the A10 continuation..."],
        ("cuda", (9, 0)): ["Hello, world! This is the H100 continuation..."],
    }
).get_expectation()

self.assertEqual(output, expected_texts)
```

### إنشاء نماذج صغيرة

توجد النماذج الصغيرة ذات الأوزان العشوائية على Hub ضمن منظمة [hf-internal-testing](https://huggingface.co/hf-internal-testing). تعتمد اختبارات Pipeline على النماذج الصغيرة عندما تحتاج إلى نقطة تفتيش مستضافة على Hub دون الاهتمام بجودة المخرجات. كما تُحمّل اختبارات الدخان السريعة النماذج الصغيرة للتحقق من أشكال المرور الأمامي دون تنزيل نقاط التفتيش الكبيرة.

تُعدّ النماذج الصغيرة الملاذ الأخير لاختبارات التكامل. لا تستخدمها إلا عندما يتجاوز أصغر نقطة تفتيش (checkpoint) المتاحة حوالي 24 غيغابايت من ذاكرة الفيديو (VRAM). استخدم الأوزان المُسبقة التدريب الأصلية، كلما أمكن ذلك، للكشف عن الانحسارات العددية الحقيقية.

ينشئ السكربت `utils/create_dummy_models.py` نماذج صغيرة من `ModelTester.get_config()`. يستخرج السكربت المعاملات الفائقة الصغيرة من مُختبِرك، ويبني نموذجًا بأوزان عشوائية، ثم يرفع النتيجة إلى Hub.

أنشئ نماذج صغيرة محليًا.

```bash
python utils/create_dummy_models.py output_dir -m your_model_type
```

ارفعها إلى Hub.

```bash
python utils/create_dummy_models.py output_dir -m your_model_type --upload --organization hf-internal-testing
```

يستخدم كل نموذج الاسم `hf-internal-testing/tiny-random-{ModelClassName}` ويُسجَّل في `tests/utils/tiny_model_summary.json`. يقوم سير عمل CI (`.github/workflows/check_tiny_models.yml`) بإعادة توليد النماذج الصغيرة يوميًا.

## تحكّم في ما يتم اختباره

تتحكم الأعلام المنطقية على `ModelTesterMixin` في الاختبارات المولَّدة تلقائيًا. يمكنك تجاوز أي علم في فئة الاختبار الخاصة بك لتفعيل أو تعطيل فحوصات محددة.

```py
class MyModelTest(CausalLMModelTest, unittest.TestCase):
    model_tester_class = MyModelTester
    test_resize_embeddings = False
    test_all_params_have_gradient = False  # when not all parameters are activated in every forward pass
```

| علم | افتراضي | ما يتحكم به |
|---|---|---|
| `test_resize_embeddings` | `True` | تغيير حجم طبقة التضمين |
| `test_resize_position_embeddings` | `False` | تغيير حجم تضمين الموقع |
| `test_mismatched_shapes` | `True` | معالجة الأشكال غير المتطابقة للمدخلات/المخرجات |
| `test_missing_keys` | `True` | تحذيرات مفاتيح مفقودة عند التحميل |
| `test_torch_exportable` | `True` | التوافق مع `torch.export` |
| `test_all_params_have_gradient` | `True` | تستقبل جميع المعاملات التدرجات (اضبط `False` عندما لا يتم تفعيل جميع المعاملات في كل تمريرة أمامية، كما هو الحال مع خبراء MoE) |
| `is_encoder_decoder` | `False` | اختبارات محددة لمعمارية المُشفِّر-المُفكِّك |
| `has_attentions` | `True` | اختبارات مخرجات الانتباه |
| `_is_composite` | `False` | معالجة النماذج المركبة/المتعددة الوسائط |
| `model_split_percents` | `[0.5, 0.7, 0.9]` | نسب التقسيم لاختبارات توازي النموذج |

## الخطوات التالية

- تصفّح وثائق [pytest](https://docs.pytest.org/en/latest/getting-started.html) لمزيد من المعلومات حول اختيار الاختبارات، والتثبيتات، والتسجيل، والمزيد.

