# إضافة نموذج باستخدام محولات معيارية

يقلل Modular transformers من الكود المطلوب لإضافة نموذج من خلال السماح بالاستيراد والإرث، على عكس سياسة [النموذج الواحد، الملف الواحد](https://huggingface.co/blog/transformers-design-philosophy). بدلاً من تكرار مكوّنات النموذج عبر الملفات، أضف ملف *modular* إلى مجلد نموذجك وارث من الفئات الموجودة.

يولّد المحوّل ملفات مستقلة من الملف المعياري. يحصل المستخدمون على واجهة الملف الواحد نفسها التي يعرفونها مسبقًا.

> [!NOTE]
> لا يُقصد بـ Modular transformers أن يحل محل [كود النمذجة القديم](./add_new_model). إذا لم يكن نموذجك مبنياً على نموذج قائم مسبقاً، أضف ملف `modeling.py` يدوياً. وينطبق الأمر نفسه على ملفات الإعداد أو الترميز أو المعالجة التي لا يمكنها الوراثة بشكل نظيف من ملف مشابه.
>
> لا يوجد ترتيب صحيح واحد أيضاً. بعض المساهمين يكتبون الملف المعياري أولاً ثم يولّدون منه. بينما يبدأ آخرون بكتابة `modeling.py` يدوياً ثم يعيدون هيكلة الملف المعياري لاحقاً. كلا النهجين يعملان.

## تنفيذ ملف معياري

ابدأ بالبحث عن نموذج في Transformers مشابه لنموذجك. من نقاط البداية الجيدة [Mistral](./model_doc/mistral) و[Qwen2](./model_doc/qwen2) و[Cohere](./model_doc/cohere) و[Cohere2](./model_doc/cohere2) و[Llama](./model_doc/llama). يوضح الجدول أدناه المكوّنات الشائعة والنماذج التي يمكنك الوراثة منها.

| مكوّن | النموذج |
|---|---|
| مزيج الخبراء | Mixtral أو Qwen2-MoE |
| تضمين دوّار متناوب (و/أو جزئي) | GLM، Phi |
| نماذج فضاء الحالة | Jamba, Bamba, Zamba, Mamba2 |
| حالات المخفي المتكررة | Gemma2 |
| أنماط الانتباه النافذي المتحرك/الانتباه الكامل لكل طبقة | Gemma2، Cohere2 |
| قص QKV | Olmo |
| تطبيع QK | Olmo2، Cohere |
| دمج QKV (غير موصى به) | Phi3 |

> [!TIP]
> استخدم أداة [modular-detector-v2](https://huggingface.co/spaces/Molbap/modular-detector-v2) للعثور على تنفيذهات موجودة يمكن الوراثة منها. الصق مقتطفًا من الكود وستُرجع الأداة أكثر الطرق تشابهًا الموجودة مسبقًا في Transformers، مما يتيح لك تحديد أفضل فئة أم قبل أن تبدأ في الكتابة.

لا تعدّل نموذجًا قائمًا فقط لجعل الوراثة تعمل لنموذجك الجديد. إذا كان إعادة تسمية فئة الوالد أو إنشاء فئة فرعية منها أمرًا غير مريح، فقم بنسخ الكود ذي الصلة مباشرةً بدلاً من ذلك.

أنشئ `src/transformers/models/<name>/modular_<name>.py`، حيث يتطابق `<name>` مع اسم مجلد النموذج بصيغة snake_case. تستعرض هذه القسم كيفية تنفيذ [Olmo2](./model_doc/olmo2) انطلاقاً من [Olmo](./model_doc/olmo) باستخدام النهج المعياري (راجع الملف الأصلي [modular_olmo2.py](https://github.com/huggingface/transformers/blob/main/src/transformers/models/olmo2/modular_olmo2.py)).

### إعداد

يوجد نقطتان يختلف فيهما [Olmo2Config](/docs/transformers/main/ar/model_doc/olmo2#transformers.Olmo2Config) عن [OlmoConfig](/docs/transformers/main/ar/model_doc/olmo#transformers.OlmoConfig).

1. يوجد حجة جديدة، `rms_norm_eps`.
2. لم يعد يُستخدم الحجة `clip_qkv`.

أعلن عن الحُجج الجديدة كإشارات نوع على مستوى الفئة مع قيمة افتراضية. أما بالنسبة للحُجج المُزالة، فعيّن `AttributeError()` لكبح الخاصية الموروثة في الملف المُولَّد (انظر [إزالة الخصائص](#removing-attributes)).

```diff
- @auto_docstring(checkpoint="allenai/OLMo-7B-hf")
+ @auto_docstring(checkpoint="allenai/Olmo2-7B-1124-hf")
+ @strict
- class OlmoConfig(PreTrainedConfig):
+ class Olmo2Config(OlmoConfig):
      ...
-     model_type = "olmo"
+     model_type = "olmo2"
      ...
+     rms_norm_eps: float = 1e-5
-     clip_qkv: float | None = None
+     clip_qkv = AttributeError()
```

يولّد `@auto_docstring` توثيقًا قياسيًا للحجج تلقائيًا (انظر دليل [@auto_docstring](./auto_docstring)). يرفض `@strict` كلمات المعلمات غير المعروفة عند وقت الإنشاء، مما يكشف عن الأخطاء الإملائية والحجج القديمة مبكرًا. أضف كلاهما إلى كل فئة إعدادات لأن الزخارف لا تُورَّث من الفئة الأم. اذكرها صراحةً حتى لو كانت فئة الإعدادات الأم تحتوي عليها بالفعل.

لضبط سمة مشتقة أو معالجة منطق التوافق العكسي، استخدم `__post_init__` بدلاً من `__init__`. على سبيل المثال، يحسب Cohere2 قيمة `head_dim` ويستنتج `layer_types` عند التهيئة.

```py
def __post_init__(self, **kwargs):
    if self.num_key_value_heads is None:
        self.num_key_value_heads = self.num_attention_heads
    self.head_dim = self.hidden_size // self.num_attention_heads
    super().__post_init__(**kwargs)
```

بالنسبة إلى النماذج التي تدعم توازي الموترات أو توازي خط الأنابيب، عرّف `base_model_tp_plan` و`base_model_pp_plan` كقاموس على مستوى الفئة في الإعداد. يحدد كلا القاموسين كيفية تقسيم النموذج عبر الأجهزة. راجع الإعدادات الموجودة مثل [Olmo2](https://github.com/huggingface/transformers/blob/main/src/transformers/models/olmo2/modular_olmo2.py) أو [Cohere2](https://github.com/huggingface/transformers/blob/main/src/transformers/models/cohere2/modular_cohere2.py) كمثال.

```py
class MyNewModelConfig(PreTrainedConfig):
    model_type = "my_new_model"

    # Tensor parallelism: maps layer name patterns to sharding strategies.
    # Use "colwise" / "rowwise" for standard sharding, or the "gather_output" /
    # "split_input" variants when an extra op (e.g. a QK norm) prevents fusing.
    base_model_tp_plan = {
        "layers.*.self_attn.q_proj": "colwise",
        "layers.*.self_attn.k_proj": "colwise",
        "layers.*.self_attn.v_proj": "colwise",
        "layers.*.self_attn.o_proj": "rowwise",
        "layers.*.mlp.gate_proj": "colwise",
        "layers.*.mlp.up_proj": "colwise",
        "layers.*.mlp.down_proj": "rowwise",
    }

    # Pipeline parallelism: maps submodule names to their (input, output) tensor names.
    base_model_pp_plan = {
        "embed_tokens": (["input_ids"], ["inputs_embeds"]),
        "layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
        "norm": (["hidden_states"], ["hidden_states"]),
    }
```

### الطبيعي

لنسخ فئة الوالد دون إجراء أي تغييرات، ورث باستخدام `pass`. يقوم أداة فحص الكود بنسخ محتوى فئة الوالد وإعادة تسمية جميع المراجع لتتطابق مع النموذج الجديد.

```py
from ..olmo.modeling_olmo import OlmoRotaryEmbedding

class Olmo2RotaryEmbedding(OlmoRotaryEmbedding):
    pass
```

لتغيير سلوك معيّن، ورّث وطبّق فقط ما يختلف. `Olmo2RMSNorm` يختلف عن `LlamaRMSNorm` في سطر واحد. يتم الضرب *قبل* إعادة التحويل إلى نوع بيانات الإدخال، وليس بعده.

```diff
  from ..llama.modeling_llama import LlamaRMSNorm

  class Olmo2RMSNorm(LlamaRMSNorm):
      def forward(self, hidden_states):
          input_dtype = hidden_states.dtype
          hidden_states = hidden_states.to(torch.float32)
          variance = hidden_states.pow(2).mean(-1, keepdim=True)
          hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
-         return self.weight * hidden_states.to(input_dtype)
+         return (self.weight * hidden_states).to(input_dtype)
```

### الانتباه

انتباه Olmo2 مطابق لانتباه Olmo باستثناء أنه يطبّق `RMSNorm` على الاستعلامات والمفاتيح، ويحذف قصّ qkv. ينسخ `super().__init__(...)` جسم الوالد ويضيف سطري المعيار الجديدين. يُعاد تعريف `forward` بالكامل لأن الاستعلامات والمفاتيح تمر الآن عبر المعايير قبل الإسقاط. كما يجلب أداة الفحص أي دوال مستوردة إلى الملف المولّد، بما في ذلك `apply_rotary_pos_emb` و`eager_attention_forward` وتبعياتهما.

```diff
  class Olmo2Attention(OlmoAttention):
      def __init__(self, config: Olmo2Config, layer_idx: int | None = None):
          super().__init__(config, layer_idx=layer_idx)
+         self.q_norm = Olmo2RMSNorm(config.num_attention_heads * self.head_dim, config.rms_norm_eps)
+         self.k_norm = Olmo2RMSNorm(config.num_key_value_heads * self.head_dim, config.rms_norm_eps)

      def forward(self, ...):
          ...
-         query_states = self.q_proj(hidden_states)
-         key_states = self.k_proj(hidden_states)
+         query_states = self.q_norm(self.q_proj(hidden_states))
+         key_states = self.k_norm(self.k_proj(hidden_states))
          value_states = self.v_proj(hidden_states)

-         if self.config.clip_qkv is not None:
-             query_states.clamp_(min=-self.config.clip_qkv, max=self.config.clip_qkv)
-             key_states.clamp_(min=-self.config.clip_qkv, max=self.config.clip_qkv)
-             value_states.clamp_(min=-self.config.clip_qkv, max=self.config.clip_qkv)
-
          ...
```

### DecoderLayer

بعد `super().__init__(...)`، استبدل سمات norm بمهام `Olmo2RMSNorm` وأعد إسناد `self.self_attn` إلى فئة `Olmo2Attention` الجديدة. يزيل `del self.input_layernorm` إسناد `input_layernorm` الخاص بالفئة الأم، لأن Olmo2 يطبّق norm *بعد* الانتباه وليس قبله. راجع [إزالة السمات](#removing-attributes) لمعرفة التفاصيل حول ما يزيله `del` وما لا يزيله.

يتم إعادة كتابة `forward` لتعكس موضع تطبيع ما بعد الانتباه. لا تكون إعادة كتابة `forward` ضرورية إلا عند إعادة تسمية خاصية، وليس عند تغيير نوعها فقط.

```diff
  class Olmo2DecoderLayer(OlmoDecoderLayer):
      def __init__(self, config: Olmo2Config, layer_idx: int):
          super().__init__(config, layer_idx=layer_idx)
-         self.self_attn = OlmoAttention(config=config, layer_idx=layer_idx)
-         self.input_layernorm = OlmoLayerNorm(config.hidden_size)
-         self.post_attention_layernorm = OlmoLayerNorm(config.hidden_size)
+         self.self_attn = Olmo2Attention(config=config, layer_idx=layer_idx)
+         del self.input_layernorm
+         self.post_attention_layernorm = Olmo2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
+         self.post_feedforward_layernorm = Olmo2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)

      def forward(self, ...):
          residual = hidden_states
-         hidden_states = self.input_layernorm(hidden_states)
          # Self Attention
          hidden_states, _ = self.self_attn(...)
-         hidden_states = residual + hidden_states
+         hidden_states = self.post_attention_layernorm(hidden_states)
+         hidden_states = residual + hidden_states

          # Fully Connected
          residual = hidden_states
-         hidden_states = self.post_attention_layernorm(hidden_states)
          hidden_states = self.mlp(hidden_states)
-         hidden_states = residual + hidden_states
+         hidden_states = self.post_feedforward_layernorm(hidden_states)
+         hidden_states = residual + hidden_states
          return hidden_states
```

### النموذج

يتغير هنا نوع `self.norm` فقط. طريقة `forward` مطابقة لطريقة الأصل، لذا ينقلها أداة الفحص تلقائيًا.

```diff
  class Olmo2Model(OlmoModel):
      def __init__(self, config: Olmo2Config):
          super().__init__(config)
-         self.layers = nn.ModuleList(
-             [OlmoDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
-         )
-         self.norm = OlmoLayerNorm(config.hidden_size)
+         self.norm = Olmo2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
+         self.layers = nn.ModuleList(
+             [Olmo2DecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
+         )
```

### رأس النموذج

المنطق مطابق تمامًا لـ [OlmoForCausalLM](/docs/transformers/main/ar/model_doc/olmo#transformers.OlmoForCausalLM)، لذا لا حاجة إلى أي تغييرات.

```py
from ..olmo.modeling_olmo import OlmoForCausalLM

class Olmo2ForCausalLM(OlmoForCausalLM):
    pass
```

### فئات أخرى

يحتوي [modeling_olmo2.py](https://github.com/huggingface/transformers/blob/main/src/transformers/models/olmo2/modeling_olmo2.py) الذي أنشأه أداة الفحص أيضًا على فئات (`Olmo2MLP`، `Olmo2RotaryEmbedding`، `Olmo2PreTrainedModel`) لم تُعرَّف صراحةً في `modular_olmo2.py`.

يستورد أداة فحص الكود أي فئة تعتمد عليها فئة موروثة، ما لم تعيد تعريفها صراحةً. تتبع الدوال المستوردة مثل `apply_rotary_pos_emb` القاعدة نفسها.

على سبيل المثال، يحتوي `OlmoDecoderLayer` على `self.mlp = OlmoMLP(config)`. لم يُعرَّف `Olmo2MLP` أبداً في الملف المعياري، لذا يقوم أداة الفحص بإنشائه تلقائياً، بما يعادل استخدام `pass`.

```py
from ..olmo.modeling_olmo import OlmoMLP

class Olmo2MLP(OlmoMLP):
    pass
```

إذا كنت تريد أن يرث `Olmo2MLP` من نموذج مختلف بدلاً من ذلك، فكن صريحاً.

```py
# switch to Mistral definition
from ..mistral.modeling_mistral import MistralMLP

class Olmo2MLP(MistralMLP):
    pass
```

### إنهاء الملف

يجب أن يُعلن كل ملفٍ معياري عن `logger` وقائمة `__all__` على مستوى الوحدة.

```py
logger = logging.get_logger(__name__)

__all__ = [
    "Olmo2Config",
    "Olmo2ForCausalLM",
    "Olmo2Model",
    "Olmo2PreTrainedModel",
]
```

يجب أن تُدرج `__all__` كل فئة عامة في الملف. يعتمد المحوّل والاستيرادات اللاحقة على ذلك. أي فئة غير مدرجة في `__all__` لن يتم تصديرها بشكل صحيح.

## إنشاء ملفات النمذجة

يولّد السكربت `modular_model_converter.py` ملفات مستقلة مثل `modeling.py` و`configuration.py` وملفات أخرى من ملفك المعياري. ولكل فئة موروثة، ينسخ جسم الفئة الأم إلى الفئة الابنة، ويعيد تسمية جميع المراجع لتتطابق مع النموذج الجديد، ويستورد أي دوال مساعدة أو فئات تعتمد عليها تلك الفئات الأم.

لا تحتوي ملفات المخرجات على أي استيرادات بين النماذج ولا على أي توريث من مديريات نماذج أخرى. يقوم المُفحِّص (linter) بتسوية التوريث إلى مستوى واحد. إذا كان `Olmo2Attention` يرث من `OlmoAttention`، فإن `Olmo2Attention` المُولَّد يكون مكتفياً ذاتياً بالكامل. لكن إذا كان `OlmoAttention` نفسه يرث من شيء آخر، فإن المُفحِّص لا يُضمِّن ذلك الجد الأعلى.

شغّل الأمر أدناه لتوليد الملفات من ملف معياري.

```bash
python utils/modular_model_converter.py your_model
```

لا تعدّل الملفات المولّدة مباشرةً، لأن أي تغييرات ستُستبدل في المرة التالية عند التشغيل.

## أنماط الملفات المعيارية

توثّق الأقسام أدناه أنماط الاستخدام الشائعة، مثل إزالة السمات أو تجاوز الدوال المُزيَّنة، عند العمل مع ملفٍ مُعَدَّل.

### إزالة السمات

يعتمد حذف السمة الموروثة على ما إذا كنت تعمل مع فئة إعدادات أو مع فئة فرعية من `nn.Module`.

بالنسبة لفئة الإعدادات، قم بتعيين `AttributeError()` إلى الخاصية على مستوى الفئة.

```py
class MyNewConfig(ParentConfig):
    removed_attr = AttributeError()
```

يقوم مُصحح الأكواد بإزالة إعلان الخاصية من ملف الإعدادات المُولَّد بالكامل. تستخدم فئات الإعدادات تخطيطًا بنمط dataclass دون `__init__`، لذا فإن إسناد `AttributeError()` على مستوى الفئة هو النهج الصحيح.

بالنسبة لفئة فرعية من `nn.Module`، استخدم `del self.attribute` بعد `super().__init__(...)`.

```py
class MyNewModel(ParentModel):
    def __init__(self, config: MyNewConfig):
        super().__init__(config)
        del self.attribute
```

`del self.attribute` يزيل فقط سطر إسناد `self.attribute = ...` من جسم الوالد المنسوخ. ولا يزيل أي أسطر أخرى تشير إلى `self.attribute`. إذا كانت طريقة `forward` لدى الوالد أو طرق أخرى تشير أيضًا إلى الخاصية، فعليك تجاوز تلك الطرق أيضًا.

```py
class DummyModel(nn.Module):
    def __init__(self, config: DummyConfig):
        super().__init__()
        self.attribute = config.attribute
        if self.attribute:
            # do more stuff with `self.attribute` here
            ...

class MyNewDummyModel(DummyModel):
    def __init__(self, config: MyNewDummyConfig):
        super().__init__(config)
        del self.attribute
        # 'self.attribute = config.attribute' is removed, but the 'if self.attribute:' block remains.
        # Override forward() or any other method that references self.attribute.
```

### العمل مع `super()`

يُخبر `super().__init__(config)` المحوّل بنسخ جسم العنصر الأب إلى العنصر الابن. هناك نمطان يتيحان لك تجاوز هذا السلوك.

- استدعِ الفئة الأم المحددة مباشرةً عندما تحتاج إلى أن يستدعي المخرَج المولَّد الفئة الجدّ (`nn.Module.__init__`) بدلاً من الفئة الأم المعيارية.
- استخدم `**super_kwargs` لتوريث التوقيع الكامل لطريقة الوالد مع إضافة وصف مخصص أو استبدال مُزيّن.

#### استدعاء فئة الجد مباشرة

كن صريحًا بشأن الفئة التي تستدعيها عندما تحتاج إلى `super()` لاستهداف فئة الوالد المولّدة بدلاً من فئة الوالد المعيارية. يستدعي المثال أدناه `nn.Module.__init__(self)` مباشرةً. `DummyModule` هي نفسها `nn.Module`، لذا يكتب المحوّل ذلك على شكل `super().__init__()` في `MyNewDummyModule` المولّدة.

```py
class MyNewDummyModule(DummyModule):                   |     class MyNewDummyModule(nn.Module):
                                                       |
  def __init__(self):                                  |       def __init__(self):
    nn.Module.__init__(self)                           |         super().__init__()
    self.foo = config.foo                              |         self.foo = config.foo
    ...                                                |         ...
```

#### super_kwargs

استخدم `**super_kwargs` لتوريث التوقيع الكامل لطريقة الأصل مع إضافة وصف مخصص أو استبدال مُزيِّن. في التوقيع المُعاد تعريفه، يُخبر هذا المُفحِّص (linter) بتوسيع جميع معاملات الأصل في المخرجات المُولَّدة.

أكثر الاستخدامات شيوعاً هو إضافة وصف خاص بالنموذج، مثل توثيق معامل `labels`، دون إعادة كتابة التوقيع الكامل.

```py
# modular_gemma.py
class GemmaForCausalLM(LlamaForCausalLM):
    def forward(**super_kwargs):
        r"""
        Example:

        ```python
        >>> from transformers import AutoTokenizer, GemmaForCausalLM
        >>> model = GemmaForCausalLM.from_pretrained("google/gemma-7b")
        ...
        ```"""
        return super().forward(**super_kwargs)
```

يتميز `GemmaForCausalLM.forward` المولّد بتوقيع `LlamaForCausalLM` الكامل دون الحاجة إلى أي نسخ يدوي.

`**super_kwargs` اختصار لحالات نادرة. إذا كنت تغيّر السلوك، فاطبع التوقيع الكامل بدلاً من ذلك.

### حذف الطرق غير المستخدمة

احذف طريقةً تابعةً للأب عن طريق تجاوزها ببيان `raise AttributeError("")`. يقوم المُفحِّص (linter) بإزالة الطريقة من الملف المُولَّد.

```py
class GemmaTokenizer(LlamaTokenizer):
    ...

    def get_spm_processor(self):
        raise AttributeError("Not needed for Gemma")

    def unk_token_length(self):
        raise AttributeError("Not needed for Gemma")
```

### تجاوز الطرق المزينة

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

يظهر مُزيّنَين (decorators) في جميع أنحاء المكتبة، أحدهما لـ[التقاط المخرجات الوسيطة للنموذج](./model_output_tracing) والآخر لـ[توليد سلاسل التوثيق تلقائيًا](./auto_docstring).

في المثال أدناه، تتجاوز فئة فرعية طريقة أم مسجّلة دون إضافة مُزيّن خاص بها. ينتقل مُزيّن الفئة الأم إليها.

```py
class NewModel(DummyModel):       |   class NewModel(nn.Module):
  ...                             |     ...
                                  |
  def forward(...):               |     @decorator(...)
    ...                           |     def forward(...):
                                  |       ...
```

إذا أضفت مُزيِّنًا جديدًا، فإن مُزيِّنك يحل محل مُزيِّن العنصر الأب.

```py
class NewModel(DummyModel):       |   class NewModel(nn.Module):
  ...                             |     ...
                                  |
  @my_new_decorator(...)          |     @my_new_decorator(...)
  def forward(...):               |     def forward(...):
    ...                           |       ...
```

### تسمية خاصة

يعيد أداة فحص الأكواد تسمية كل شيء تلقائياً عند الوراثة من فئة. استخدم بادئة اسم الفئة نفسها عبر جميع الفئات في الملف نفسه.

تجنّب خلط البادئات كما في المثال أدناه. `MyModelIncredibleMLP` يخالف قواعد التسمية، ولن يعرف أداة فحص الأكواد ما إذا كان يجب استخدام `MyModelIncredible` أو `MyModel` عند إعادة تسمية التبعيات من الرتبة الأعلى.

```py
class MyModelIncredibleMLP(LlamaMLP):
    ...

class MyModelDecoderLayer(LlamaDecoderLayer):
    ...
```

بما أنه لا توجد [اعتمادات ضمنية](#other-classes)، يمكنك إعادة تسمية فئة واحدة محليًا. أعد تعريف كل ذكر آخر لتلك الفئة صراحةً باستخدام نمط الاسم الجديد. وإلا، سيضيف أداة فحص الكود فئة `MyModelMLP` غير مرغوب فيها إلى جانب `MyModelIncredibleMLP`.

يرفع أداة فحص الأكواد تحذيراً عندما يكتشف بادئة غير محددة.

```text
We detected multiple prefix names when inheriting from transformers.models.llama.modeling_llama: ('Emu3Text', 'Emu3'). We will only use the most used 'Emu3' prefix when grabbing args and dependencies. Make sure to subclass the intermediate classes with the prefix you want (if different from 'Emu3') or use a single prefix in all the modular (best).
```

تكون البادئات الغامضة أكثر شيوعاً في النماذج متعددة الوسائط التي تتضمن أسماء الفئات مؤهلاً للوسائط مثل `Text`. لمنح اعتمادية بادئة محددة، أعد تسميتها صراحةً باستخدام `pass`.

```py
class Emu3TextMLP(LlamaMLP):
    pass
```

### سلاسل توثيق الإعداد

لا يدعم أداة فحص الأكواد (linter) بعد وراثة جزئية لتعليقات التوثيق (docstring). عند إضافة أو إزالة سمات الإعداد (config attributes)، أضف تعليق التوثيق الكامل مباشرةً في الملف المعياري (modular file) تحت تعريف الفئة (class).

## تحويل نقاط التفتيش

بمجرد أن تولّد ملفات النمذجة الخاصة بك، تحقّق من أن الأوزان الفعلية تُحمَّل بشكل صحيح. اكتب سكربت تحويل لترجمة صيغة نقطة التفتيش الأصلية إلى صيغة متوافقة مع Transformers، ثم احفظها على Hub.

### اكتب سكربت تحويل

أضف ملف `convert_<model>_to_hf.py` إلى `src/transformers/models/<model>/`. يقوم هذا السكربت بتحميل الأوزان من المصدر الأصلي، وإعادة تسمية المفاتيح وإعادة تشكيلها لتتطابق مع أسماء المعاملات في وحدة عملك، ثم يحفظ النتيجة باستخدام [save_pretrained()](/docs/transformers/main/ar/main_classes/model#transformers.PreTrainedModel.save_pretrained).

> [!TIP]
> ابحث عن سكربت موجود لتسخيره وتكييفه. تتضمن النماذج الموجودة تحت `src/transformers/models/` سكربت `convert_*_to_hf.py` يمكنك استخدامه كنقطة انطلاق.

بعد تشغيل السكربت، حمّل نقطة التفتيش المحفوظة باستخدام [from_pretrained()](/docs/transformers/main/ar/main_classes/model#transformers.PreTrainedModel.from_pretrained) وتأكد من أن كل الأوزان المتوقعة تم تحميلها بشكل صحيح. مفاتيح نقطة التفتيش غير المستخدمة تشير إلى عدم تطابق في الأسماء، لذا اطبعها لاكتشاف المشكلات مبكراً.

```py
model = YourModelForTask.from_pretrained("path/to/output/")
```

تحقق من تطابق الأبعاد والأسماء عند التكرار على المفاتيح. عادةً ما تعني عدم تطابق الأبعاد أن هناك خطأً في أحد المعاملات في إعداداتك، أو أن البنية المعمارية تختلف عن الأصلية، أو أن أحد الأوزان يحتاج إلى تبديل (Transposition).

```py
for key, tensor in original_state_dict.items():
    hf_tensor = hf_model.state_dict().get(mapped_key)
    assert hf_tensor.shape == tensor.shape, (
        f"Shape mismatch for {key}: expected {tensor.shape}, got {hf_tensor.shape}"
    )
```

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

بمجرد تحميل نقطة التفتيش بنجاح، قم بدفعها إلى Hub باستخدام [push_to_hub()](/docs/transformers/main/ar/main_classes/model#transformers.utils.PushToHubMixin.push_to_hub). راجع دليل [مشاركة النموذج](./model_sharing) لمزيد من التفاصيل.

```py
model.push_to_hub("username/your-model-name")
```

### خريطة التحويل وقت التشغيل

أضِف خرائط وقت التشغيل إلى `src/transformers/conversion_mapping.py` عندما لا تتطابق الأوزان المنشورة مع تخطيط المعاملات الخاص بوحدة التحكم. تشمل الحالات الشائعة الأوزان المدمجة المخزنة بشكل منفصل، ومصفوفات خبراء MoE التي تحتاج إلى تجميع. تتيح هذه الخريطة لـ [from_pretrained()](/docs/transformers/main/ar/main_classes/model#transformers.PreTrainedModel.from_pretrained) تحميل نقطة التفتيش من Hub دون الحاجة إلى خطوة تصدير منفصلة.

راجع دليل [تحميل الأوزان الديناميكي](./weightconverter) لمعرفة كيفية كتابة قواعد `WeightRenaming` و[WeightConverter](/docs/transformers/main/ar/internal/modeling_utils#transformers.WeightConverter) وتسجيلها لنوع النموذج `model_type` الخاص بك.

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

- [قواعد بنية النموذج](./modeling_rules) هي قواعد ثابتة تُفرض على جميع ملفات `modeling_*.py` و`modular_*.py` و`configuration_*.py`. نفّذ `make typing` للتحقق منها قبل فتح طلب دمج.
- يتناول [إضافة مكونات معالجة الرؤية](./add_vision_processing_components) خطوات إضافة معالج صور ومعالج فيديو ومعالج لنمط متعدد الوسائط.
- يُبيّن [توليد توثيق الدوال تلقائيًا](./auto_docstring) كيفية استخدام `@auto_docstring` حتى لا تضطر إلى كتابة توثيق المعاملات يدويًا لواجهات برمجة التطبيقات المشتركة بين النماذج.
- يتناول [كتابة اختبارات النموذج](./testing) كيفية كتابة اختبارات التكامل لنموذجك الجديد وتشغيله محليًا.
- يشرح [فحوصات طلبات الدمج](./pr_checks) فحوصات CI التي يجب أن يجتازها طلب الدمج الخاص بك قبل أن يُدمج، وكيفية إعادة إنتاجها وإصلاحها محليًا.

