# تتبع المخرجات الوسيطة للنموذج

كانت طريقة `forward()` في كل نموذج تحلّ يدويًا أعلام `None` مثل `output_attentions` من القيم الافتراضية في الإعدادات، وتجمع أوزان الانتباه وحالات المخفية لكل طبقة في مجموعات (tuples)، وتحوّل فئات `ModelOutput` إلى مجموعات عادية عندما تكون `return_dict=False`. يستبدل مزينا (decorators) كل هذه الأكواد الروتينية.

- `@capture_outputs` يحلّ أعلام المخرجات، ويجمع القيم الوسيطة، ويتعامل مع تحويل `return_dict`.
- يحلّ `@merge_with_config_defaults` قيمة `use_cache` من الإعدادات. يُستحسن حذفه في النماذج التي لا تستخدم التخزين المؤقت، مثل [CLIPModel](/docs/transformers/main/ar/model_doc/clip#transformers.CLIPModel).

ستصادف هذه الزخارف (decorators) في الغالب عند دمج نموذج جديد. راجع [إضافة نموذج إلى 🤗 Transformers](./modular_transformers) للحصول على دليل خطوة بخطوة.

## إعلان الوحدات الفرعية التي يجب التقاطها

طبّق `@capture_outputs` على طريقة `forward()` للنموذج الأساسي. فهي تُلحق خطافات أمامية (forward hooks) التي:

- اعتراض المخرجات من فئات الوحدات الفرعية المحددة أثناء المرور الأمامي، دون أن تحتاج تلك الوحدات الفرعية إلى معرفة أنها قيد المراقبة.
- اجمع أوزان الانتباه والحالات المخفية لكل طبقة في مجموعات (توبلز).
- أدخل القيم المجموعة في كلاس البيانات `ModelOutput` المُعاد.
- قم بتحويل dataclass إلى tuple عادي عند `return_dict=False`.
- حلّ `output_attentions` و`output_hidden_states` من kwargs أو من `self.config` عندما تكون `None`.

## تعيين حقول المخرجات إلى الوحدات الفرعية

يتعيّن على `@capture_outputs` معرفة أي وحدة فرعية تنتج أي مخرَج. عرّف قاموسًا على مستوى الفئة باسم `_can_record_outputs` في الفئة الفرعية من `PreTrainedModel`. كل مفتاح هو اسم حقل مخرَج (`"hidden_states"`، `"attentions"`، `"cross_attentions"`)، وكل قيمة هي فئة وحدة، أو سلسلة نصية باسم الفئة، أو مثيل من `OutputRecorder`، أو قائمة من تلك العناصر لتسجيل عدة أنواع من الوحدات تحت مفتاح واحد.

## التحكم الدقيق باستخدام OutputRecorder

يقبل `OutputRecorder` معامل `target_class` (وهو فئة فرعية من `nn.Module` تُجمع مخرجاتها) ومعامل اختياري `index` لاختيار العنصر المطلوب من مجموعة المخرجات الخاصة بالوحدة. مرّر `layer_name` لتثبيت الخطافات (hooks) فقط على الوحدات التي تحمل اسم سمة محدد. استخدم `layer_name` عندما تتشارك طبقتان نفس الفئة، على سبيل المثال الانتباه الذاتي مقابل الانتباه المتقاطع.

يُظهر المثال أدناه كلا المزيّنين (decorators) في التطبيق العملي مع مستويات مختلفة من التحكم في المخرجات. راجع [LlamaModel](https://github.com/huggingface/transformers/blob/main/src/transformers/models/llama/modeling_llama.py) كمرجع من العالم الحقيقي.

```python
from ...processing_utils import Unpack
from ...utils import TransformersKwargs
from ...utils.generic import merge_with_config_defaults
from ...utils.output_capturing import capture_outputs, OutputRecorder

class MyPreTrainedModel(PreTrainedModel):
    _can_record_outputs = {
        # Capture hidden_states: hook fires after each MyDecoderBlock forward,
        # grabbing its first output (index 0 by default).
        "hidden_states": MyDecoderBlock,

        # Capture self-attention weights: hook fires after each MyAttention
        # forward, grabbing its second output (index=1 by default).
        "attentions": MyAttention,

        # Capture cross-attention weights: same class, different submodule.
        # layer_name targets the attribute `self.crossattention` inside the block.
        # Captures second output as requested (index=1)
        "cross_attentions": OutputRecorder(
            MyAttention, layer_name="crossattention", index=1
        ),
    }

# Now in base model's forward we need the decorators and `Unpack` `kwargs`
class MyModel(MyPreTrainedModel):

    @merge_with_config_defaults # ← resolves use_cache
    @capture_outputs            # ← handles output collection + return_dict
    def forward(
        self,
        input_ids: torch.LongTensor | None = None,
        past_key_values: Cache = None,
        **kwargs: Unpack[TransformersKwargs],
    ) -> BaseModelOutputWithPast:

        # No manual collection needed. Just run your layers normally.
        hidden_states = self.embed_tokens(input_ids)
        for layer in self.layers:
            hidden_states = layer(hidden_states, **kwargs)

        # Return the primary outputs. The decorator will fill in
        # hidden_states/attentions/cross_attentions automatically.
        return BaseModelOutputWithPast(
            last_hidden_state=hidden_states,
            past_key_values=past_key_values
        )
```

## فئات طبقة التصحيح

يعتمد تتبع المخرجات على أن يشير `_can_record_outputs` إلى *الفئات الدقيقة* التي تُنشئها طبقات النموذج. إذا استبدلت تنفيذ طبقة بنواة انتباه مخصصة، أو طبقة خبير مُكمّاة، أو متغير معماري، فيجب أن تبقى تلك المؤشرات متزامنة. يوفر [واجهة برمجة التطبيقات للإصلاح](./monkey_patching) سجلًا عامًا نظيفًا للحفاظ على اتساق `_can_record_outputs`.

يقوم `register_patch_mapping` بربط أسماء الفئات الأصلية بفئات فرعية بديلة من `nn.Module`. يمكن أن تكون المفاتيح أسماء فئات دقيقة أو أنماطًا منتظمة. الأولوية للمطابقات الدقيقة. تُختبر الأنماط باستخدام `re.search()`، لذا فإن الأنماط غير المثبتة تتطابق في أي مكان ضمن اسم الفئة. يؤدي تسجيل المفتاح نفسه مرتين إلى رفع `ValueError` ما لم تقم بتمرير `overwrite=True`.

احذف العناصر باستخدام `unregister_patch_mapping`.

```python
from transformers.monkey_patching import register_patch_mapping, unregister_patch_mapping

# Exact name – replaces only Qwen2MoeExperts
register_patch_mapping({"Qwen2MoeExperts": SequentialExperts})

# Regex – replaces every class whose name ends in "Attention"
register_patch_mapping({".*Attention$": FusedAttention})

# Anchored version – only matches Llama2Attention, Llama3Attention, …
register_patch_mapping({"^Llama\\d+Attention$": CustomLlamaAttention})

# Same way, custom keys can be removed from the registry by passing the name that was registered
unregister_patch_mapping(["Qwen2MoeExperts", ".*Attention$"])
```

بمجرد تسجيل الخرائط، يتجوّل `patch_output_recorders` في كل وحدة فرعية ويحدّث كل `OutputRecorder.target_class` إلى البديل المسجّل.

> [!TIP]
> تستدعي طريقة [from_pretrained()](/docs/transformers/main/ar/main_classes/model#transformers.PreTrainedModel.from_pretrained) الدالة `patch_output_recorders` تلقائيًا. لا تحتاج إلى استدعائها بنفسك إلا عند بناء نموذج مباشرةً.

```python
from transformers.monkey_patching import patch_output_recorders
# Built manually, outside from_pretrained
model = Qwen2MoeModel(config)

# Without this, _can_record_outputs still points at the original Qwen2MoeExperts class
# and hooks will never fire on CustomExperts instances.
patch_output_recorders(model)
```

