# マルチモーダルプロセッサ

プロセッサーは、トークナイザーと、画像プロセッサー、動画プロセッサー、特徴量抽出器などの1つ以上のモダリティプロセッサーを組み合わせます。単一の`__call__`メソッドを公開し、各入力を適切なコンポーネントにルーティングして、出力を1つの辞書にマージします。

一部のマルチモーダルモデルでは、テキストと画像、動画、またはオーディオが交互に配置されます。これらのモデルでは、[ProcessorMixin](/docs/transformers/main/ja/main_classes/processors#transformers.ProcessorMixin)を使用して、`<image>`、`<video>`、`<audio>`などのプレースホルダトークンを、モデルが期待するトークンパターンに置き換えることができます。

## 新しいプロセッサの追加

`src/transformers/models/<model>/processing_<my_model_name>.py` を作成し、`ProcessorMixin` をサブクラス化することで、プロセッサークラスを定義します。デフォルト値を持つ `TypedDict` オブジェクトを定義し、それを `cls.valid_processor_kwargs` に割り当てることを忘れないでください。

```python
from ...processing_utils import ProcessorMixin, ProcessingKwargs, Unpack

class MyModelProcessorKwargs(ProcessingKwargs, total=False):
    images_kwargs: MyModelImageProcessorKwargs
    _defaults = {
        "text_kwargs": {"padding": True},
        "images_kwargs": {"do_convert_rgb": True},
    }

class MyModelProcessor(ProcessorMixin):
    valid_processor_kwargs = MyModelProcessorKwargs

    def __init__(self, image_processor, tokenizer, chat_template=None, **kwargs):
        self.image_token = tokenizer.image_token
        self.image_token_id = tokenizer.image_token_id
        super().__init__(
            image_processor=image_processor,
            tokenizer=tokenizer,
            chat_template=chat_template,
            **kwargs,
        )
```

必要に応じて`replace_<modality>_token`を実装してください。このメソッドは、サブプロセッサからの完全な出力辞書と、現在の入力のインデックスを受け取り、その入力に対応する展開された置換文字列を返します。置換文字列とは、モデルが入力シーケンスに期待する内容そのものです。

モデルがプレースホルダーの繰り返しを一切使用しない場合（`image_token` が定義されていない場合）、このメソッドをオーバーライドする必要はありません。`self.image_token` を設定せずにしておくと、ベースクラスは置換を完全にスキップします。

```python
def replace_image_token(self, image_inputs: dict, image_idx: int) -> str:
    num_crops = image_inputs["num_crops"][image_idx]
    return f"{self.boi_token}{self.image_token * self.num_image_tokens * num_crops}{self.eoi_token}"
```

必要に応じて、`prepare_inputs_layout` メソッドと `validate_inputs` メソッドをオーバーライドできます。これは、処理を開始する前に特定の入力構造が必要となる場合（画像をネストされたリストとして並べ替えるなど）、または共通のチェックに加えてモデル固有の検証を行う場合に使用します。

```python
def prepare_inputs_layout(self, images=None, text=None, videos=None, audio=None, **kwargs):
    # Call `super()` to apply common preparation steps first 
    images, text, videos, audio = super().prepare_inputs_layout(images, text, videos, audio)
    if images is not None:
        images = make_nested_list_of_images(images)
    return images, text, videos, audio

def validate_inputs(self, images=None, text=None, videos=None, audio=None, **kwargs):
    super().validate_inputs(images=images, text=text, **kwargs)
    if text is not None and images is not None:
        n_tokens = [s.count(self.image_token) for s in text]
        n_images = [len(img_list) for img_list in images]
        if n_tokens != n_images:
            raise ValueError(
                f"Number of {self.image_token} tokens in text {n_tokens} does not match "
                f"number of images {n_images}."
            )
```

> [!TIP]
> 参考として、[Gemma4Processor](/docs/transformers/main/ja/model_doc/gemma4#transformers.Gemma4Processor) と [Qwen2VLProcessor](/docs/transformers/main/ja/model_doc/qwen2_vl#transformers.Qwen2VLProcessor) をご覧ください。

## テスト

すべてのマルチモーダルプロセッサには、`ProcessorTesterMixin`を継承するテストクラスが必要です。このミックスインは、トークナイズ、画像処理、バッチ処理、およびラウンドトリップエンコーディングをカバーする標準的なテストスイートを提供します。

```python
# tests/models/my_model_name/test_processor_<my_model_name>.py

from transformers.testing_utils import require_vision
from transformers.utils import is_vision_available
from ...test_processing_common import ProcessorTesterMixin

if is_vision_available():
    from transformers import MyModelProcessor

@require_vision
class MyModelProcessorTest(ProcessorTesterMixin, unittest.TestCase):
    processor_class = MyModelProcessor

    def get_processor(self):
        return MyModelProcessor.from_pretrained("hf-internal-testing/my-model-test")
```

