# 新しいパイプラインの追加

[Pipeline](/docs/transformers/main/ja/main_classes/pipelines#transformers.Pipeline) をサブクラス化し、いくつかのメソッドを実装することで、独自のパイプラインを作成できます。コードを[Hub](https://hf.co)でコミュニティと共有し、Transformers にパイプラインを登録することで、誰でも簡単に素早く利用できるようになります。

このガイドでは、Transformers に新しいパイプラインを追加する手順を説明します。

## 設計上の選択

最低限、[Pipeline](/docs/transformers/main/ja/main_classes/pipelines#transformers.Pipeline)にタスクに適した入力を与えるだけで十分です。パイプラインを設計する際も、ここから始めるべきです。

[Pipeline](/docs/transformers/main/ja/main_classes/pipelines#transformers.Pipeline) が受け入れられる入力タイプを決定します。文字列、生バイト、辞書などが対象です。互換性を高めるため、可能な限り入力を純粋な Python に保つことをお勧めします。次に、[Pipeline](/docs/transformers/main/ja/main_classes/pipelines#transformers.Pipeline) が返す出力を決定します。同様に、扱いやすいため、出力を Python に保つことが最もシンプルで最適な選択肢です。

入力と出力をシンプルに保ち、できれば JSON シリアライズ可能にしておくことで、ユーザーは新しいオブジェクト型を学ぶことなく、[Pipeline](/docs/transformers/main/ja/main_classes/pipelines#transformers.Pipeline)を簡単に実行できるようになります。さらに使いやすさを高めるために、多くの異なる入力タイプをサポートすることも一般的です。例えば、音声ファイルをファイル名、URL、または生バイトとして受け入れるようにすることで、ユーザーは音声データを提供する方法においてより柔軟性を得られます。

## パイプラインの作成

入力と出力が決まったら、[Pipeline](/docs/transformers/main/ja/main_classes/pipelines#transformers.Pipeline)の実装を開始できます。パイプラインはベースの[Pipeline](/docs/transformers/main/ja/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/ja/main_classes/pipelines#transformers.Pipeline) に追加のパラメータを渡すことを可能にします。これは初期化時や、[Pipeline](/docs/transformers/main/ja/main_classes/pipelines#transformers.Pipeline) が呼び出された際に発生し得ます。`_sanitize_parameters` は、`preprocess`、`_forward`、`postprocess` に直接渡される追加のキーワード引数を格納した 3 つの dict を返します。ユーザーが追加のパラメータなしにパイプラインを呼び出した場合は、何も追加しないでください。これにより、関数定義内のデフォルト引数が保持され、常により自然な状態が維持されます。

例えば、`postprocess` に `top_k` パラメータを追加して、最も確率の高い上位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
```

これにより、ユーザーが選択した場合、パイプラインは最も確率の高い上位ラベルを返すことができます。

```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`に登録します。レジストリは以下を定義します:

- `pt_model` によってサポートされる Pytorch モデルクラス
- `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/ja/main_classes/pipelines#transformers.Pipeline) が正常に動作することを保証するためのテストを追加する必要もあるため、時間がかかる場合があります。

### Hubにアップロード

パイプラインのコードをPythonファイルとしてHubに追加します。

例えば、文ペア分類用のカスタムパイプラインは、以下のコードのようになります。

```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/ja/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) で定義されたモデルで実行される必要があります。これは、将来の新しいモデルとの互換性をテストする上で重要です。

[run_pipeline_test](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L186) 関数全体で `ANY` が使用されている点にもお気づきのことと思います。モデルはランダムなため、実際の値を確認することはできません。`ANY` を使用することで、テストがパイプライン型の出力に一致するようになります。

最後に、以下の4つのテストも実装する必要があります。

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)では、これらのパイプラインが意味のある結果を返すことを確認するために、現実的なモデルを使用します。これらのテストは低速であるため、slowとしてマークする必要があります。

