# Caixas de ferramentas para depuração de modelos

Esta página lista todas as ferramentas de depuração e de adição de modelos usadas pela biblioteca, bem como as funções utilitárias que ela fornece para isso.

A maioria delas só é útil se você estiver adicionando novos modelos à biblioteca.

## Depuradores de adição de modelos

### Depurador de adição de modelos - gerenciador de contexto para adicionadores de modelos

Este gerenciador de contexto é uma ferramenta para usuários avançados, destinada a quem adiciona modelos. Ele rastreia todas as chamadas de forward dentro do forward de um modelo e registra um trecho de cada entrada e saída em um JSON aninhado. Vale notar que este gerenciador de contexto impõe `torch.no_grad()`.

### Justificativa

Ao portar modelos para o Transformers, mesmo de Python para Python, os desenvolvedores de modelos frequentemente precisam realizar muitas operações manuais, como salvar e carregar tensores, comparar dtypes, etc. Esta pequena ferramenta pode, com sorte, economizar algum tempo.

### Uso

Adicione este gerenciador de contexto da seguinte forma para depurar um modelo:

```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)

```

### Lendo os resultados

O depurador gera dois arquivos a partir da chamada de forward, ambos com o mesmo nome base, mas terminando em `_SUMMARY.json` ou em `_FULL_TENSORS.json`.

O primeiro conterá um resumo dos valores e das formas dos tensores de _entrada_ e _saída_ de cada módulo.

```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
```

O arquivo `_FULL_TENSORS.json` exibirá uma visão completa de todos os tensors, o que é útil para comparar dois arquivos.

```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')"
      },
```

#### Salvando tensores no disco

Alguns criadores de modelos podem se beneficiar do registro dos valores completos dos tensores em disco para suportar, por exemplo, a análise numérica entre implementações.

Defina `use_repr=False` para gravar os tensores no disco usando [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)
```

Ao usar `use_repr=False`, os tensors são gravados no mesmo local em disco dos arquivos `_SUMMARY.json` e `_FULL_TENSORS.json`. A propriedade `value` das entradas no arquivo `_FULL_TENSORS.json` conterá uma referência de caminho relativo para o arquivo `.safetensors` associado. Cada tensor é gravado em seu próprio arquivo como a propriedade `data` do dicionário de estado. Os nomes dos arquivos são construídos usando o `module_path` como prefixo, com alguns possíveis sufixos construídos recursivamente.

* As entradas dos módulos são indicadas por `_inputs` e as saídas por `_outputs`.
* Instâncias de `list` e `tuple`, como `args` ou valores de retorno de funções, terão o sufixo `_{index}`.
* Instâncias de `dict` terão o sufixo `_{key}`.

### Comparando entre implementações

Depois que as passadas de frente de dois modelos forem rastreadas pelo depurador, é possível comparar os arquivos de saída `json`. Veja abaixo: podemos ver pequenas diferenças na camada de projeção de chave dessas duas implementações. As entradas são em grande parte idênticas, mas não exatamente. Examinar as diferenças nos arquivos facilita identificar qual camada está incorreta.

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

### Limitações e escopo[[transformers.model_addition_debugger_context]]

Este recurso funcionará apenas para modelos baseados em torch. Modelos que dependem fortemente de chamadas a kernels externos podem funcionar, mas o trace provavelmente deixará de capturar alguns detalhes. De qualquer forma, qualquer implementação em python que vise imitar outra implementação pode ser rastreada uma vez, em vez de ser executada N vezes com pontos de interrupção.

Se você passar `do_prune_layers=False` para o depurador do seu modelo, TODAS as camadas serão exibidas no `json`. Caso contrário, apenas a primeira e a última camada serão mostradas. Isso é útil quando algumas camadas (geralmente de atenção cruzada) aparecem apenas após N camadas.

#### 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)
```

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

# Depurador de adição de modelos - gerenciador de contexto para adicionadores de modelos
Este gerenciador de contexto é uma ferramenta para usuários avançados, destinada a quem adiciona modelos.

Ele rastreia todas as chamadas de forward dentro do forward de um modelo e registra um trecho de cada entrada e saída em um arquivo JSON aninhado. Se `use_repr=True` (o padrão), o arquivo JSON registrará uma versão `repr()` dos tensors como uma lista de strings. Se `use_repr=False`, os tensors completos serão armazenados em arquivos SafeTensors separados e o arquivo JSON fornecerá um caminho relativo para esse arquivo.

Vale notar que este gerenciador de contexto impõe `torch.no_grad()`.

## Uso

adicione o gerenciador de contexto a um modelo para depurar

```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)
```

## Analisador de testes ignorados

### Verificar testes ignorados - para adicioneiros e mantenedores de modelos

Este pequeno utilitário é uma ferramenta para usuários avançados, destinada a quem adiciona e mantém modelos. Ele lista todos os métodos de teste existentes em `test_modeling_common.py`, herdados por todas as classes de testador de modelos, e varre o repositório para medir quantos testes estão sendo ignorados e para quais modelos.

### Justificativa

Ao portar modelos para o Transformers, os testes falham como deveriam, e às vezes `test_modeling_common` parece irreconciliável com as peculiaridades do nosso modelo recém-criado. Mas como podemos ter certeza de que não estamos quebrando tudo ao adicionar um skip aparentemente inofensivo?

Este utilitário:

- varre todos os métodos de test_modeling_common
- procura por momentos em que um método é ignorado
- retorna um resumo em json que você pode carregar como um DataFrame/inspecionar

**Por exemplo, test_inputs_embeds é ignorado em uma proporção impressionante de 39% no momento em que esta utilidade foi escrita.**

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

### Uso

Você pode executar o analisador de testes ignorados de duas maneiras:

#### Varredura completa (padrão)

A partir da raiz do repositório `transformers`, varre todos os métodos de teste comuns e exporta os resultados para um arquivo JSON (padrão: `all_tests_scan_result.json`).

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

- `--output_dir` (opcional): Diretório onde os resultados em JSON serão salvos. O padrão é o diretório atual.

**Exemplo de saída:**

```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

```

E ele gerará o arquivo `all_tests_scan_result.json` que você pode inspecionar. O JSON é indexado pelo nome do método, e cada entrada segue este esquema, indicando também a origem (de `common` ou de `GenerationMixin`.)

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

O que você pode visualizar acima, por exemplo, com `pandas`

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

```

### Escaneie um único método de teste

Você pode focar em um método de teste específico usando `--test_method_name`:

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

- `--test_method_name`: Nome do método de teste a ser verificado (ex.: `test_inputs_embeds`).
- `--output_dir` (opcional): Diretório onde o resultado em JSON será salvo.

**Exemplo de saída:**

```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

```

## Detector de modelo modular

### Analisador de similaridade de código - para adicioneiros de modelos

Esta utilidade analisa as similaridades de código entre implementações de modelos para identificar oportunidades de modularização. Ela compara um arquivo de modelagem novo ou existente com todos os modelos da biblioteca, utilizando métricas de similaridade baseadas em embeddings e em tokens.

### Justificativa

Ao adicionar um novo modelo ao Transformers, muitos componentes (camadas de atenção, MLPs, saídas, etc.) podem já existir em forma semelhante em outros modelos. Em vez de implementar tudo do zero, os criadores de modelos podem identificar quais classes existentes são semelhantes e potencialmente reutilizáveis por meio da modularização.

A ferramenta calcula duas pontuações de similaridade:

- **Pontuação de incorporação**: usa incorporações de código semântico (via `Qwen/Qwen3-Embedding-4B`) para detectar código funcionalmente semelhante, mesmo com nomes diferentes
- **Pontuação de Jaccard**: mede a sobreposição de conjuntos de tokens para identificar padrões de código estruturalmente semelhantes

Uma pontuação de 1.00 significa que o código é idêntico.

### Uso

A partir da raiz do repositório `transformers`:

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

A ferramenta baixará automaticamente o índice pré-compilado do Hub (requer RAM/VRAM para o modelo de embedding).

**Exemplo de saída:**

```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:
```

O campo `intersection` exibe as classes que aparecem em ambos os resultados do top-5, indicando alta confiança para os candidatos à modularização.

### Criando um índice personalizado

Para reconstruir o índice a partir do seu código local (útil após adicionar novos modelos ou usar um modelo de incorporação diferente):

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

Para enviar o índice recriado para um conjunto de dados do Hub:

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

### Opções

- `--modeling-file`: Caminho para o arquivo de modelagem a ser analisado
- `--build`: Constrói o índice de similaridade de código a partir de todos os arquivos de modelagem em `src/transformers/models/`
- `--push-new-index`: após a compilação, envia o índice para um dataset do Hub (requer `--build`)
- `--hub-dataset`: ID do repositório de dataset no Hub para puxar/enviar o índice (padrão: `hf-internal-testing/transformers_code_embeddings`)

### Limitações

Esta ferramenta requer recursos de GPU/CPU para executar o modelo de embedding (`Qwen/Qwen3-Embedding-4B`). O índice pré-construído é baixado do Hub por padrão, o que exige uma conexão com a internet no primeiro uso.

Os resultados são sugestões baseadas na similaridade do código e devem ser revisados manualmente antes da modularização. Pontuações de similaridade elevadas não garantem compatibilidade perfeita.

