# モデルデバッグツールボックス

このページでは、ライブラリが使用するデバッグおよびモデル追加ツール、およびそれらに付随するユーティリティ関数をすべて一覧で示します。

それらの多くは、ライブラリに新しいモデルを追加する場合にのみ有用です。

## モデル追加デバッガー

### モデル追加デバッガー - モデルアダー用のコンテキストマネージャー

このコンテキストマネージャーは、モデルの追加者向けの高度なツールです。モデルの forward 内のすべての forward 呼び出しを追跡し、各入力と出力のスライスをネストされた JSON に記録します。なお、このコンテキストマネージャーは `torch.no_grad()` を強制します。

### 根拠

Transformers へのモデル移植において、Python から Python への移行であっても、モデルを追加する際は、テンソルの保存と読み込み、dtype の比較など、多くの手動操作が必要になることがよくあります。この小さなツールが、その作業時間を短縮できることを願っています。

### 使用方法

モデルのデバッグには、このコンテキストマネージャーを次のように追加します。

```python
import torch
from PIL import Image
import requests
from transformers import LlavaProcessor, LlavaForConditionalGeneration
from transformers.model_debugging_utils import model_addition_debugger_context
torch.random.manual_seed(673)

# load pretrained model and processor
model_id = "llava-hf/llava-1.5-7b-hf"
processor = LlavaProcessor.from_pretrained(model_id)
model = LlavaForConditionalGeneration.from_pretrained(model_id)

# create random image input
random_image = Image.fromarray(torch.randint(0, 256, (224, 224, 3), dtype=torch.uint8).numpy())

# prompt
prompt = "<image>Describe this image."

# process inputs
inputs = processor(text=prompt, images=random_image, return_tensors="pt")

# call forward method (not .generate!)
with model_addition_debugger_context(
    model,
    debug_path="optional_path_to_your_directory",
    do_prune_layers=False # This will output ALL the layers of a model.
):
    output = model.forward(**inputs)

```

### 結果の読み取り

デバッガは forward 呼び出しから2つのファイルを生成します。どちらも同じベース名を持ち、末尾が `_SUMMARY.json` または `_FULL_TENSORS.json` になります。

最初の1つには、各モジュールの_入力_および_出力_テンソルの値と形状の概要が含まれます。

```json
{
  "module_path": "MolmoForConditionalGeneration",
  "inputs": {
    "args": [],
    "kwargs": {
      "input_ids": {
        "shape": "torch.Size([1, 589])",
        "dtype": "torch.int64"
      },
      "attention_mask": {
        "shape": "torch.Size([1, 589])",
        "dtype": "torch.int64"
      },
      "pixel_values": {
        "shape": "torch.Size([1, 5, 576, 588])",
        "dtype": "torch.float32",
        "mean": "tensor(-8.9514e-01, device='cuda:0')",
        "std": "tensor(9.2586e-01, device='cuda:0')",
        "min": "tensor(-1.7923e+00, device='cuda:0')",
        "max": "tensor(1.8899e+00, device='cuda:0')"
    }
  },
  "children": [
    {
      "module_path": "MolmoForConditionalGeneration.language_model.model.embed_tokens",
      "inputs": {
        "args": [
          {
            "shape": "torch.Size([1, 589])",
            "dtype": "torch.int64"
          }
        ]
      },
      "outputs": {
        "shape": "torch.Size([1, 589, 3584])",
        "dtype": "torch.float32",
        "mean": "tensor(6.5460e-06, device='cuda:0')",
        "std": "tensor(2.3807e-02, device='cuda:0')",
        "min": "tensor(-3.3398e-01, device='cuda:0')",
        "max": "tensor(3.9453e-01, device='cuda:0')"
      }
    },
    {
      "module_path": "MolmoForConditionalGeneration.vision_tower",
      "inputs": {
        "args": [
          {
            "shape": "torch.Size([5, 1, 576, 588])",
            "dtype": "torch.float32",
            "mean": "tensor(-8.9514e-01, device='cuda:0')",
            "std": "tensor(9.2586e-01, device='cuda:0')",
            "min": "tensor(-1.7923e+00, device='cuda:0')",
            "max": "tensor(1.8899e+00, device='cuda:0')"
          }
        ],
        "kwargs": {
          "output_hidden_states": "True"
        }
      },
      "children": [
        { ... and so on
```

`_FULL_TENSORS.json` ファイルには、すべてのテンソルの詳細が表示されるため、2つのファイルを比較する際に便利です。

```json
      "pixel_values": {
        "shape": "torch.Size([1, 5, 576, 588])",
        "dtype": "torch.float32",
        "value": [
          "tensor([[[[-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          ...,",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00]],",
          "",
          "         [[-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          ...,",
          "          [-1.4857e+00, -1.4820e+00, -1.2100e+00,  ..., -6.0979e-01, -5.9650e-01, -3.8527e-01],",
          "          [-1.6755e+00, -1.7221e+00, -1.4518e+00,  ..., -7.5577e-01, -7.4658e-01, -5.5592e-01],",
          "          [-7.9957e-01, -8.2162e-01, -5.7014e-01,  ..., -1.3689e+00, -1.3169e+00, -1.0678e+00]],",
          "",
          "         [[-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          ...,",
          "          [-3.0322e-01, -5.0645e-01, -5.8436e-01,  ..., -6.2439e-01, -7.9160e-01, -8.1188e-01],",
          "          [-4.4921e-01, -6.5653e-01, -7.2656e-01,  ..., -3.4702e-01, -5.2146e-01, -5.1326e-01],",
          "          [-3.4702e-01, -5.3647e-01, -5.4170e-01,  ..., -1.0915e+00, -1.1968e+00, -1.0252e+00]],",
          "",
          "         [[-1.1207e+00, -1.2718e+00, -1.0678e+00,  ..., 1.2013e-01, -1.3126e-01, -1.7197e-01],",
          "          [-6.9738e-01, -9.1166e-01, -8.5454e-01,  ..., -5.5050e-02, -2.8134e-01, -4.2793e-01],",
          "          [-3.4702e-01, -5.5148e-01, -5.8436e-01,  ..., 1.9312e-01, -8.6235e-02, -2.1463e-01],",
          "          ...,",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00]],",
          "",
          "         [[-1.0039e+00, -9.5669e-01, -6.5546e-01,  ..., -1.4711e+00, -1.4219e+00, -1.1389e+00],",
          "          [-1.0039e+00, -9.5669e-01, -6.5546e-01,  ..., -1.7193e+00, -1.6771e+00, -1.4091e+00],",
          "          [-1.6317e+00, -1.6020e+00, -1.2669e+00,  ..., -1.2667e+00, -1.2268e+00, -8.9720e-01],",
          "          ...,",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
          "          [-1.7923e+00, -1.7521e+00, -1.4802e+00,  ..., -1.7923e+00, -1.7521e+00, -1.4802e+00]]]], device='cuda:0')"
        ],
        "mean": "tensor(-8.9514e-01, device='cuda:0')",
        "std": "tensor(9.2586e-01, device='cuda:0')",
        "min": "tensor(-1.7923e+00, device='cuda:0')",
        "max": "tensor(1.8899e+00, device='cuda:0')"
      },
```

#### テンソルをディスクに保存する

一部のモデルアドダーは、実装間の数値解析などをサポートするために、完全なテンソル値をディスクにログ出力することから恩恵を受ける場合があります。

`use_repr=False` を設定すると、[SafeTensors](https://huggingface.co/docs/safetensors/en/index) を使用してテンソルをディスクに書き出します。

```python
with model_addition_debugger_context(
    model,
    debug_path="optional_path_to_your_directory",
    do_prune_layers=False,
    use_repr=False,   # Defaults to True
):
    output = model.forward(**inputs)
```

`use_repr=False` を使用する場合、テンソルは `_SUMMARY.json` および `_FULL_TENSORS.json` ファイルと同じディスク上の場所に書き込まれます。`_FULL_TENSORS.json` ファイル内のエントリの `value` プロパティには、関連する `.safetensors` ファイルへの相対パスの参照が含まれます。各テンソルは、状態辞書の `data` プロパティとして、それぞれ個別のファイルに書き込まれます。ファイル名は、`module_path` をプレフィックスとして、再帰的に構築されるいくつかの可能なサフィックスを用いて作成されます。

* モジュールの入力は`_inputs`で、出力は`_outputs`で表されます。
* `list` や `tuple` のインスタンス（`args` や関数の戻り値など）には、`_{index}` が接尾辞として付与されます。
* `dict` のインスタンスには、`_{key}` が接尾辞として付与されます。

### 実装の比較

デバッガによって2つのモデルのフォワードパスがトレースされた後、`json`出力ファイルを比較できます。以下を参照してください。これら2つの実装のキー投影層にわずかな違いが見られます。入力はおおむね同一ですが、完全に一致していません。ファイルの差分を確認することで、どの層に問題があるかを特定しやすくなります。

![download-icon](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/files_difference_debugging.png)

### 制約とスコープ[[transformers.model_addition_debugger_context]]

この機能は、torch ベースのモデルでのみ動作します。外部カーネル呼び出しに大きく依存するモデルは動作する可能性がありますが、トレースによって一部の処理が取りこぼされる可能性があります。いずれにせよ、別の実装を模倣することを目的とした Python 実装であれば、ブレークポイント付きで N 回再実行する代わりに、一度だけトレースできます。

モデルデバッガーに`do_prune_layers=False`を渡すと、すべてのレイヤーが`json`に出力されます。それ以外の場合、最初のレイヤーと最後のレイヤーのみが表示されます。これは、一部のレイヤー（通常はクロスアテンション）がN層目以降にのみ現れる場合に便利です。

#### transformers.model_addition_debugger_context[[transformers.model_addition_debugger_context]]

```python
transformers.model_addition_debugger_context(model, debug_path: str | None = None, do_prune_layers: bool = True, use_repr: bool = True)
```

[ソース](https://github.com/huggingface/transformers/blob/main/src/transformers/model_debugging_utils.py#L391)

# モデル追加デバッガー - モデルアダー用のコンテキストマネージャー
このコンテキストマネージャーは、モデルの追加者向けの高度なツールです。

モデルの forward 内のすべての forward 呼び出しを追跡し、各入力と出力のスライスをネストされた JSON ファイルに記録します。`use_repr=True`（デフォルト）の場合、JSON ファイルにはテンソルの`repr()`化されたバージョンが文字列のリストとして記録されます。`use_repr=False`の場合、完全なテンソルは別の SafeTensors ファイルに保存され、JSON ファイルにはそのファイルへの相対パスが提供されます。

なお、このコンテキストマネージャーは`torch.no_grad()`を強制します。

## 使用方法

デバッグのためにモデルにコンテキストマネージャーを追加します

```python
import torch

from PIL import Image
from transformers import LlavaProcessor, LlavaForConditionalGeneration, model_addition_debugger_context

torch.random.manual_seed(673)

# load pretrained model and processor
model_id = "llava-hf/llava-1.5-7b-hf"
processor = LlavaProcessor.from_pretrained(model_id)
model = LlavaForConditionalGeneration.from_pretrained(model_id)

# create random image input
random_image = Image.fromarray(torch.randint(0, 256, (224, 224, 3), dtype=torch.uint8).numpy())

# prompt
prompt = "<image>Describe this image."

# process inputs
inputs = processor(text=prompt, images=random_image, return_tensors="pt")

# call forward method (not .generate!)
with model_addition_debugger_context(model, debug_path="Your_debug_path", do_prune_layers=False):
    output = model.forward(**inputs)
```

## スキップされたテストの分析

### スキップされたテストのスキャン - モデルの追加者およびメンテナー向け

この小さなユーティリティは、モデルの追加者やメンテナー向けの高度なツールです。`test_modeling_common.py` に存在するすべてのテストメソッドを列挙し、これらはすべてのモデルテスタークラスによって継承されます。さらに、リポジトリをスキャンして、どのモデルで何件のテストがスキップされているかを測定します。

### 根拠

transformers へのモデル移植時に、テストは当然ながら失敗し、時には `test_modeling_common` が、私たちの全く新しいモデルの特殊性と折り合いがつかないように感じられることもあります。しかし、一見無害に見えるスキップを追加することで、すべてを壊していないとどうやって確信できるのでしょうか。

このユーティリティは:

- test_modeling_common のすべてのメソッドをスキャンします
- メソッドがスキップされたタイミングを検索します
- DataFrameとして読み込むことや、内容を確認できるサマリーJSONを返します

**例えば、このユーティリティの作成時点では、test_inputs_embeds は実に 39% の割合でスキップされていました。**

![download-icon](https://huggingface.co/datasets/huggingface/documentation-images/resolve/f7f671f69b88ce4967e19179172c248958d35742/transformers/tests_skipped_visualisation.png)

### 使用方法

スキップされたテストのアナライザーは、2つの方法で実行できます。

#### フルスキャン（デフォルト）

`transformers`リポジトリのルートから、一般的なテストメソッドをすべてスキャンし、結果をJSONファイルに出力します（デフォルト: `all_tests_scan_result.json`）。

```bash
python utils/scan_skipped_tests.py --output_dir path/to/output
```

- `--output_dir`（任意）: JSON 結果を保存するディレクトリ。デフォルトではカレントディレクトリになります。

**出力例:**

```text
🔬 Parsing 331 model test files once each...
📝 Aggregating 224 tests...
  (224/224) test_update_candidate_strategy_with_matches_1es_3d_is_nonecodet_schedule_fa_kwargs
✅ Scan complete.

📄 JSON saved to /home/pablo/git/transformers/all_tests_scan_result.json

```

そして、`all_tests_scan_result.json` というファイルが生成され、その内容を確認できます。この JSON はメソッド名をインデックスとしており、各エントリは以下のスキーマに従っています。また、`common` または `GenerationMixin` のいずれから由来するものかも示されています。

```json
{
  "<method_name>": {
    "origin": "<test suite>"
    "models_ran": ["<model_name>", ...],
    "models_skipped": ["<model_name>", ...],
    "skipped_proportion": <float>,
    "reasons_skipped": ["<model_name>: <reason>",
      ...
    ]
  },
  ...
}
```

例えば`pandas`を用いて、上記のように可視化できます。

```python
df = pd.read_json('all_tests_scan_result.json').T
df.sort_values(by=['skipped_proportion'], ascending=False)

```

### 単一のテストメソッドをスキャンする

`--test_method_name` を使用して、特定のテストメソッドに焦点を当てることもできます:

```bash
python utils/scan_skipped_tests.py --test_method_name test_inputs_embeds --output_dir path/to/output
```

- `--test_method_name`: スキャン対象のテストメソッド名（例: `test_inputs_embeds`）。
- `--output_dir`（任意）: JSON 結果を保存するディレクトリ。

**出力例:**

```bash
$ python utils/scan_skipped_tests.py --test_method_name test_inputs_embeds

🔬 Parsing 331 model test files once each...

== test_inputs_embeds ==

Ran    : 199/323
Skipped : 124/323 (38.4%)
 - aimv2: Aimv2 does not use inputs_embeds
 - align: Inputs_embeds is tested in individual model tests
 - altclip: Inputs_embeds is tested in individual model tests
 - audio_spectrogram_transformer: AST does not use inputs_embeds
 - beit: BEiT does not use inputs_embeds
 - bit: Bit does not use inputs_embeds
 - blip: Blip does not use inputs_embeds
 - blip_2: Inputs_embeds is tested in individual model tests
 - bridgetower:
 - canine: CANINE does not have a get_input_embeddings() method.
 - ...

📄 JSON saved to /home/pablo/git/transformers/scan_test_inputs_embeds.json

```

## モジュール式モデル検出器

### Code similarity analyzer - モデル追加者向け

このユーティリティは、モデル実装間のコード類似性を分析し、モジュール化の機会を特定します。埋め込みベースとトークンベースの類似性指標を用いて、新規または既存のモデリングファイルをライブラリ内のすべてのモデルと比較します。

### 根拠

transformers に新しいモデルを追加する際、多くのコンポーネント（アテンション層、MLP、出力など）が、他のモデルに類似した形で既に存在する可能性があります。すべてをゼロから実装するのではなく、モデルの追加者は、モジュール化を通じて既存のクラスの中で類似しており再利用可能なものを特定できます。

このツールは2つの類似度スコアを計算します:

- **埋め込みスコア**: `Qwen/Qwen3-Embedding-4B` を用いたセマンティックなコード埋め込みにより、命名が異なっても機能的に類似したコードを検出します
- **Jaccard score**: トークン集合の重複を測定し、構造的に類似したコードパターンを特定します

スコアが1.00の場合、コードが完全に一致することを意味します。

### 使用方法

`transformers`リポジトリのルートから:

```bash
python utils/modular_model_detector.py --modeling-file path/to/modeling_file.py
```

このツールは、Hub から事前構築されたインデックスを自動的にダウンロードします（埋め込みモデルに RAM/VRAM が必要です）。

**出力例:**

```text
Loading checkpoint shards: 100%|████████████████████| 2/2 [00:00<00:00, 33.62it/s]
encoding 21 query definitions with Qwen/Qwen3-Embedding-4B (device=cuda, batch=16, max_length=4096)

stuff.py::Beit3ImageTextMatchingOutput:
embedding:
    blip_2::Blip2ImageTextMatchingModelOutput (0.9994)
    chinese_clip::ChineseCLIPOutput (0.9818)
    owlvit::OwlViTOutput (0.9818)
jaccard:
    owlv2::Owlv2Output (0.9667)
    metaclip_2::MetaClip2Output (0.9667)
    altclip::AltCLIPOutput (0.9667)
intersection:
    blip::BlipOutput
    owlvit::OwlViTOutput

stuff.py::Beit3MLP:
embedding:
    efficientloftr::EfficientLoFTRMLP (0.9718)
    seggpt::SegGptMlp (0.9650)
jaccard:
    chinese_clip::ChineseCLIPTextSelfOutput (0.5294)
    bert::BertSelfOutput (0.5294)
intersection:
```

`intersection` フィールドは、上位5件の結果の両方に含まれるクラスを表示し、モジュール化の候補に対する高い信頼性を示しています。

### カスタムインデックスの構築

ローカルコードベースからインデックスを再構築するには（新しいモデルを追加した場合や、別の埋め込みモデルを使用する場合に有用です）:

```bash
python utils/modular_model_detector.py --build
```

再構築したインデックスを Hub のデータセットにプッシュするには:

```bash
python utils/modular_model_detector.py --build --push-new-index --hub-dataset your-org/your-dataset
```

### オプション

- `--modeling-file`: 解析対象のモデリングファイルへのパス
- `--build`: `src/transformers/models/` 内のすべてのモデリングファイルからコード類似性インデックスを構築します。
- `--push-new-index`: ビルド後、インデックスを Hub のデータセットにプッシュします（`--build` が必要です）
- `--hub-dataset`: インデックスの pull/push に使用する Hub データセットリポジトリ ID（デフォルト: `hf-internal-testing/transformers_code_embeddings`）

### 制限事項

このツールは、埋め込みモデル（`Qwen/Qwen3-Embedding-4B`）を実行するために GPU/CPU リソースが必要です。デフォルトでは、事前構築されたインデックスが Hub からダウンロードされるため、初回使用時にはインターネット接続が必要です。

結果はコードの類似性に基づく提案であり、モジュール化の前に手動で確認する必要があります。類似度スコアが高いことは、完全な互換性を保証するものではありません。

