# إضافة خط أنابيب جديد

اجعل [Pipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.Pipeline) خاصاً بك من خلال إنشاء فئة فرعية منه وتنفيذ بعض الدوال. شارك الكود مع المجتمع على [Hub](https://hf.co) وسجّل خط الأنابيب مع Transformers بحيث يتمكن الجميع من استخدامه بسرعة وسهولة.

ستأخذك هذه الدليل خطوة بخطوة في عملية إضافة خط أنابيب جديد إلى Transformers.

## اختيارات التصميم

في الحد الأدنى، يكفي أن تزوّد [Pipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.Pipeline) بمدخل مناسب للمهمة. وهذا هو المكان الذي ينبغي أن تبدأ منه عند تصميم خط أنابيبك.

حدد أنواع المدخلات التي يمكن لـ [Pipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.Pipeline) قبولها. فقد تكون نصوصًا، أو بايتات خام، أو قواميس، وما إلى ذلك. حاول إبقاء المدخلات بلغة بايثون الخالصة قدر الإمكان لأنها أكثر توافقًا. ثم، حدد المخرجات التي يجب أن يعيدها [Pipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.Pipeline). مرة أخرى، إبقاء المخرجات بلغة بايثون هو الخيار الأبسط والأفضل لأنه أسهل في التعامل معه.

إن إبقاء المدخلات والمخرجات بسيطة، وقابلة للتسلسل بصيغة JSON في المثالي، يسهّل على المستخدمين تشغيل [Pipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.Pipeline) الخاص بك دون الحاجة إلى تعلّم أنواع كائنات جديدة. كما يُعدّ من الشائع دعم العديد من أنواع المدخلات المختلفة لزيادة سهولة الاستخدام. فعلى سبيل المثال، قبول ملف صوتي سواء من اسم الملف، أو رابط URL، أو بايتات خام يمنح المستخدم مرونة أكبر في طريقة تقديم البيانات الصوتية.

## إنشاء خط أنابيب

بعد تحديد المدخلات والمخرجات، يمكنك البدء في تنفيذ [Pipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.Pipeline). يجب أن يرث خط أنابيبك من الفئة الأساسية [Pipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.Pipeline) وأن يتضمن 4 طرق.

```py
from transformers import Pipeline

class MyPipeline(Pipeline):
    def _sanitize_parameters(self, **kwargs):

    def preprocess(self, inputs, args=2):

    def _forward(self, model_inputs):

    def postprocess(self, model_outputs):
```

1. يقوم `preprocess` باستقبال المدخلات وتحويلها إلى صيغة الإدخال المناسبة للنموذج.

```py
def preprocess(self, inputs, maybe_arg=2):
    model_input = Tensor(inputs["input_ids"])
    return {"model_input": model_input}
```

2. لا ينبغي استدعاء `_forward` مباشرةً. يُفضَّل استخدام `forward` لأنه يتضمن تدابير وقائية تضمن عمل كل شيء بشكل صحيح على الجهاز المتوقع. كل ما يتعلق بالنموذج يجب وضعه في `_forward`، وكل ما عدا ذلك يجب وضعه في `preprocess` أو `postprocess`.

```py
def _forward(self, model_inputs):
    outputs = self.model(**model_inputs)
    return outputs
```

3. `postprocess` يولّد المخرجات النهائية من مخرجات النموذج في `_forward`.

```py
def postprocess(self, model_outputs, top_k=5):
    best_class = model_outputs["logits"].softmax(-1)
    return best_class
```

4. يتيح `_sanitize_parameters` للمستخدمين تمرير معاملات إضافية إلى [Pipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.Pipeline). وقد يحدث ذلك أثناء التهيئة أو عند استدعاء [Pipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.Pipeline). يعيد `_sanitize_parameters` ثلاثة قواميس (dicts) من معاملات الكلمات المفتاحية الإضافية التي تُمرَّر مباشرةً إلى `preprocess` و`_forward` و`postprocess`. لا تضف أي شيء إذا لم يستدعِ المستخدم خط الأنابيب بمعاملات إضافية. وهذا يحافظ على المعاملات الافتراضية في تعريف الدالة، وهو أمر أكثر طبيعية دائمًا.

على سبيل المثال، أضف معامل `top_k` في `postprocess` لإرجاع أكثر 5 فئات احتمالاً. ثم في `_sanitize_parameters`، تحقق مما إذا كان المستخدم قد مرر `top_k` وأضفه إلى `postprocess_kwargs`.

```py
def _sanitize_parameters(self, **kwargs):
    preprocess_kwargs = {}
    if "maybe_arg" in kwargs:
        preprocess_kwargs["maybe_arg"] = kwargs["maybe_arg"]

    postprocess_kwargs = {}
    if "top_k" in kwargs:
        postprocess_kwargs["top_k"] = kwargs["top_k"]
    return preprocess_kwargs, {}, postprocess_kwargs
```

الآن يمكن أن تُرجع خط المعالجة (pipeline) أكثر التسميات احتمالاً إذا اختار المستخدم ذلك.

```py
from transformers import pipeline

pipeline = pipeline("my-task")
# returns 3 most likely labels
pipeline("This is the best meal I've ever had", top_k=3)
# returns 5 most likely labels by default
pipeline("This is the best meal I've ever had")
```

## تسجيل خط أنابيب

سجّل المهمة الجديدة التي يدعمها خط أنابيبك في `PIPELINE_REGISTRY`. يحدد السجل:

- فئة نموذج Pytorch المدعومة مع `pt_model`
- نموذج افتراضي يجب أن يأتي من مراجعة محددة (فرع، أو تجزئة التزامن) حيث يعمل النموذج كما هو متوقع مع `default`
- المدخل المتوقع من نوع `type`

```py
from transformers.pipelines import PIPELINE_REGISTRY
from transformers import AutoModelForSequenceClassification

PIPELINE_REGISTRY.register_pipeline(
    "new-task",
    pipeline_class=MyPipeline,
    pt_model=AutoModelForSequenceClassification,
    default={"pt": ("user/awesome-model", "branch-name")},
    type="text",
)
```

## شارك خط أنابيبك

شارك خط أنابيبك مع المجتمع على [Hub](https://hf.co) أو يمكنك إضافته مباشرة إلى Transformers.

يكون رفع كود خط الأنابيب الخاص بك إلى Hub أسرع لأنه لا يتطلب مراجعة من فريق Transformers. قد يكون إضافة خط الأنابيب إلى Transformers أبطأ لأنه يتطلب مراجعة، كما يجب عليك إضافة اختبارات للتأكد من أن [Pipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.Pipeline) الخاص بك يعمل.

### الرفع إلى المستودع

أضف كود خط الأنابيب الخاص بك إلى Hub في ملف Python.

على سبيل المثال، قد يبدو خط أنابيب مخصص لتصنيف أزواج الجمل كما هو موضح في الكود أدناه.

```py
import numpy as np
from transformers import Pipeline

def softmax(outputs):
    maxes = np.max(outputs, axis=-1, keepdims=True)
    shifted_exp = np.exp(outputs - maxes)
    return shifted_exp / shifted_exp.sum(axis=-1, keepdims=True)

class PairClassificationPipeline(Pipeline):
    def _sanitize_parameters(self, **kwargs):
        preprocess_kwargs = {}
        if "second_text" in kwargs:
            preprocess_kwargs["second_text"] = kwargs["second_text"]
        return preprocess_kwargs, {}, {}

    def preprocess(self, text, second_text=None):
        return self.tokenizer(text, text_pair=second_text, return_tensors=self.framework)

    def _forward(self, model_inputs):
        return self.model(**model_inputs)

    def postprocess(self, model_outputs):
        logits = model_outputs.logits[0].numpy()
        probabilities = softmax(logits)

        best_class = np.argmax(probabilities)
        label = self.model.config.id2label[best_class]
        score = probabilities[best_class].item()
        logits = logits.tolist()
        return {"label": label, "score": score, "logits": logits}
```

احفظ الكود في ملف باسم `pair_classification.py`، واستورده وسجّله كما هو موضح أدناه.

```py
from pair_classification import PairClassificationPipeline
from transformers.pipelines import PIPELINE_REGISTRY
from transformers import AutoModelForSequenceClassification

PIPELINE_REGISTRY.register_pipeline(
    "pair-classification",
    pipeline_class=PairClassificationPipeline,
    pt_model=AutoModelForSequenceClassification,
)
```

تُسجّل الدالة [register_pipeline](https://github.com/huggingface/transformers/blob/9feae5fb0164e89d4998e5776897c16f7330d3df/src/transformers/pipelines/base.py#L1387) تفاصيل خط المعالجة (نوع المهمة، فئة خط المعالجة، الخوادم المدعومة) في ملف `config.json` الخاص بالنماذج.

```json
  "custom_pipelines": {
    "pair-classification": {
      "impl": "pair_classification.PairClassificationPipeline",
      "pt": [
        "AutoModelForSequenceClassification"
      ],
    }
  },
```

استدعِ [push_to_hub()](/docs/transformers/main/ar/main_classes/model#transformers.utils.PushToHubMixin.push_to_hub) لدفع خط المعالجة إلى Hub. يتم نسخ ملف Python الذي يحتوي على الكود إلى Hub، كما يتم حفظ نموذج خط المعالجة ومُجزّئ الرموز ودفعهما إلى Hub. يجب أن يكون خط المعالجة متوفرًا الآن على Hub ضمن نطاقك.

```py
from transformers import pipeline

pipeline = pipeline(task="pair-classification", model="sgugger/finetuned-bert-mrpc")
pipeline.push_to_hub("pair-classification-pipeline")
```

للاستخدام خط الأنابيب، أضف `trust_remote_code=True` عند تحميل خط الأنابيب.

```py
from transformers import pipeline

pipeline = pipeline(task="pair-classification", trust_remote_code=True)
```

### إضافة إلى Transformers

يتطلب إضافة خط أنابيب مخصص إلى Transformers إضافة اختبارات للتأكد من أن كل شيء يعمل كما هو متوقع، وطلب مراجعة من فريق Transformers.

أضف كود خط الأنابيب الخاص بك كوحدة جديدة إلى وحدة [pipelines](https://github.com/huggingface/transformers/tree/main/src/transformers/pipelines) الفرعية، وأضفه إلى قائمة المهام المحددة في [pipelines/__init__.py](https://github.com/huggingface/transformers/blob/main/src/transformers/pipelines/__init__.py).

بعد ذلك، أضف اختبارًا جديدًا للخط الأنابيب في [transformers/tests/pipelines](https://github.com/huggingface/transformers/tree/main/tests/pipelines). يمكنك الاطلاع على الاختبارات الأخرى كمثال على كيفية اختبار خط أنابيبك.

يجب أن تكون الدالة [run_pipeline_test](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L186) عامة جداً وتعمل على النماذج المعرّفة في [model_mapping](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L48). وهذا أمر مهم لاختبار التوافق المستقبلي مع النماذج الجديدة.

ستلاحظ أيضاً استخدام `ANY` في جميع أنحاء دالة [run_pipeline_test](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L186). نظراً لأن النماذج عشوائية، فلا يمكن التحقق من القيم الفعلية. يسمح استخدام `ANY` باختبار مطابقة مخرجات نوع خط المعالجة بدلاً من ذلك.

أخيرًا، يجب عليك أيضًا تنفيذ الاختبارات الأربعة التالية.

1. [test_small_model_pt](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L59)، استخدم نموذجًا صغيرًا لهذه الأنابيب للتأكد من إرجاعها المخرجات الصحيحة. لا يجب أن تكون النتائج ذات معنى. يجب أن تُرجع كل أنبوب النتيجة نفسها.
1. [test_large_model_pt](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_zero_shot_image_classification.py#L187)، استخدم نموذجًا واقعيًا لهذه الأنابيب للتأكد من إرجاعها نتائج ذات معنى. هذه الاختبارات بطيئة ويجب وضع علامة عليها على أنها بطيئة.

