# Adăugarea unui nou pipeline Fă-ți propriul [`Pipeline`] creând o subclasă a acestuia și implementând câteva metode. Partajează codul cu comunitatea pe [Hub](https://hf.co) și înregistrează pipeline-ul în Transformers astfel încât toată lumea să îl poată folosi rapid și ușor. Acest ghid te va ghida prin procesul de adăugare a unui nou pipeline în Transformers. ## Alegeri de design La minimum, trebuie doar să oferi [`Pipeline`] un input potrivit pentru un task. Acesta este și punctul de la care ar trebui să începi atunci când îți proiectezi pipeline-ul. Decide ce tipuri de input poate accepta [`Pipeline`]. Pot fi string-uri, raw bytes, dicționare și așa mai departe. Încearcă să păstrezi input-urile în Python pur acolo unde este posibil deoarece este mai compatibil. Apoi, decide ce output ar trebui să returneze [`Pipeline`]. Din nou, păstrarea output-ului în Python este opțiunea cea mai simplă și cea mai bună deoarece este mai ușor de lucrat cu el. Păstrarea input-urilor și output-urilor simple și, ideal, serializabile în JSON, le face mai ușor utilizatorilor să ruleze [`Pipeline`]-ul tău fără a fi nevoie să învețe tipuri noi de obiecte. De asemenea, este obișnuit să suporți multe tipuri diferite de input pentru o ușurință de utilizare și mai mare. De exemplu, faptul că un fișier audio poate fi acceptat dintr-un nume de fișier, un URL sau raw bytes îi oferă utilizatorului mai multă flexibilitate în modul în care furnizează datele audio. ## Crearea unui pipeline După ce ai decis un input și un output, poți începe să implementezi [`Pipeline`]. Pipeline-ul tău ar trebui să moștenească din clasa de bază [`Pipeline`] și să includă 4 metode. ```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` preia input-urile și le transformă în formatul de input potrivit pentru model. ```py def preprocess(self, inputs, maybe_arg=2): model_input = Tensor(inputs["input_ids"]) return {"model_input": model_input} ``` 2. `_forward` nu ar trebui apelată direct. `forward` este metoda preferată deoarece include mecanisme de protecție pentru a se asigura că totul funcționează corect pe device-ul așteptat. Orice este legat de model aparține în `_forward`, iar tot restul aparține fie în `preprocess`, fie în `postprocess`. ```py def _forward(self, model_inputs): outputs = self.model(**model_inputs) return outputs ``` 3. `postprocess` generează output-ul final din output-ul modelului din `_forward`. ```py def postprocess(self, model_outputs, top_k=5): best_class = model_outputs["logits"].softmax(-1) return best_class ``` 4. `_sanitize_parameters` le permite utilizatorilor să transmită parametri suplimentari către [`Pipeline`]. Acest lucru poate avea loc în timpul inițializării sau atunci când [`Pipeline`] este apelat. `_sanitize_parameters` returnează 3 dicts de argumente keyword suplimentare care sunt transmise direct către `preprocess`, `_forward` și `postprocess`. Nu adăuga nimic dacă un utilizator nu a apelat pipeline-ul cu parametri suplimentari. Acest lucru păstrează argumentele implicite în definiția funcției, ceea ce este întotdeauna mai natural. De exemplu, adaugă un parametru `top_k` în `postprocess` pentru a returna primele 5 cele mai probabile clase. Apoi, în `_sanitize_parameters`, verifică dacă utilizatorul a transmis `top_k` și adaugă-l la `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 ``` Acum pipeline-ul poate returna cele mai probabile etichete dacă un utilizator alege acest lucru. ```py from transformers import pipeline pipeline = pipeline("my-task") # returnează cele mai probabile 3 etichete pipeline("This is the best meal I've ever had", top_k=3) # returnează implicit cele mai probabile 5 etichete pipeline("This is the best meal I've ever had") ``` ## Înregistrarea unui pipeline Înregistrează noul task pe care îl suportă pipeline-ul tău în `PIPELINE_REGISTRY`. Registry-ul definește: - Clasa de model Pytorch suportată cu `pt_model` - un model implicit care ar trebui să provină dintr-o anumită revizie (branch sau commit hash) unde modelul funcționează conform așteptărilor, cu `default` - input-ul așteptat cu `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", ) ``` ## Partajarea pipeline-ului tău Partajează pipeline-ul tău cu comunitatea pe [Hub](https://hf.co) sau îl poți adăuga direct în Transformers. Este mai rapid să încarci codul pipeline-ului tău pe Hub deoarece nu necesită o revizuire din partea echipei Transformers. Adăugarea pipeline-ului în Transformers poate fi mai lentă deoarece necesită o revizuire și trebuie să adaugi teste pentru a te asigura că [`Pipeline`]-ul tău funcționează. ### Încărcarea pe Hub Adaugă codul pipeline-ului tău pe Hub într-un fișier Python. De exemplu, un pipeline personalizat pentru clasificarea perechilor de propoziții ar putea arăta ca în codul de mai jos. ```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} ``` Salvează codul într-un fișier numit `pair_classification.py` și importă-l și înregistrează-l așa cum se arată mai jos. ```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, ) ``` Funcția [register_pipeline](https://github.com/huggingface/transformers/blob/9feae5fb0164e89d4998e5776897c16f7330d3df/src/transformers/pipelines/base.py#L1387) înregistrează detaliile pipeline-ului (tipul de task, clasa de pipeline, backend-urile suportate) în fișierul `config.json` al unui model. ```json "custom_pipelines": { "pair-classification": { "impl": "pair_classification.PairClassificationPipeline", "pt": [ "AutoModelForSequenceClassification" ], } }, ``` Apelează [`~Pipeline.push_to_hub`] pentru a face push pipeline-ului către Hub. Fișierul Python care conține codul este copiat pe Hub, iar modelul și tokenizer-ul pipeline-ului sunt, de asemenea, salvate și trimise (push) către Hub. Pipeline-ul tău ar trebui să fie acum disponibil pe Hub în namespace-ul tău. ```py from transformers import pipeline pipeline = pipeline(task="pair-classification", model="sgugger/finetuned-bert-mrpc") pipeline.push_to_hub("pair-classification-pipeline") ``` Pentru a folosi pipeline-ul, adaugă `trust_remote_code=True` atunci când încarci pipeline-ul. ```py from transformers import pipeline pipeline = pipeline(task="pair-classification", trust_remote_code=True) ``` ### Adăugarea în Transformers Adăugarea unui pipeline personalizat în Transformers necesită adăugarea de teste pentru a te asigura că totul funcționează conform așteptărilor și solicitarea unei revizuiri din partea echipei Transformers. Adaugă codul pipeline-ului tău ca un nou modul în submodulul [pipelines](https://github.com/huggingface/transformers/tree/main/src/transformers/pipelines) și adaugă-l la lista de task-uri definite în [pipelines/__init__.py](https://github.com/huggingface/transformers/blob/main/src/transformers/pipelines/__init__.py). Apoi, adaugă un nou test pentru pipeline în [transformers/tests/pipelines](https://github.com/huggingface/transformers/tree/main/tests/pipelines). Poți să te uiți la celelalte teste pentru exemple despre cum să-ți testezi pipeline-ul. Funcția [run_pipeline_test](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L186) ar trebui să fie foarte generică și să ruleze pe modelele definite în [model_mapping](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L48). Acest lucru este important pentru testarea compatibilității viitoare cu modele noi. Vei observa, de asemenea, că `ANY` este folosit pe tot parcursul funcției [run_pipeline_test](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L186). Modelele sunt aleatorii, așa că nu poți verifica valorile efective. Folosirea lui `ANY` permite în schimb testului să se potrivească cu output-ul de tipul pipeline-ului. În cele din urmă, ar trebui să implementezi și următoarele 4 teste. 1. [test_small_model_pt](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L59), folosește un model mic pentru aceste pipeline-uri pentru a te asigura că returnează output-urile corecte. Rezultatele nu trebuie să aibă sens. Fiecare pipeline ar trebui să returneze același rezultat. 1. [test_large_model_pt](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_zero_shot_image_classification.py#L187), folosește un model realist pentru aceste pipeline-uri pentru a te asigura că returnează rezultate semnificative. Aceste teste sunt lente și ar trebui marcate ca fiind lente (slow).