Transformers documentation

Наборы инструментов для отладки моделей

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Наборы инструментов для отладки моделей

На этой странице перечислены все инструменты отладки и добавления моделей, используемые библиотекой, а также вспомогательные функции, которые она предоставляет.

Большинство из них полезны только в том случае, если вы добавляете новые модели в библиотеку.

Отладчики добавления моделей

Отладчик добавления моделей — контекстный менеджер для добавляющих моделей

Этот контекстный менеджер — инструмент для опытных пользователей, предназначенный для добавления моделей. Он отслеживает все вызовы forward внутри forward модели и записывает фрагмент каждого входного и выходного значения в вложенный JSON. Обратите внимание, что этот контекстный менеджер принудительно применяет torch.no_grad().

Обоснование

При переносе моделей в transformers, даже из Python в Python, разработчикам моделей часто приходится выполнять множество ручных операций, связанных с сохранением и загрузкой тензоров, сравнением dtypes и т. д. Этот небольшой инструмент, надеюсь, позволит сэкономить время.

Использование

Добавьте этот контекстный менеджер следующим образом для отладки модели:

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, оба с одинаковым базовым именем, но с окончанием _SUMMARY.json или _FULL_TENSORS.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 отображает полную информацию обо всех тензорах, что удобно для сравнения двух файлов.

      "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.

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. Свойство value записей в файле _FULL_TENSORS.json будет содержать относительный путь к соответствующему файлу .safetensors. Каждый тензор записывается в отдельный файл в качестве свойства data словаря состояния. Имена файлов формируются с использованием module_path в качестве префикса и нескольких возможных суффиксов, которые строятся рекурсивно.

  • Входы модуля обозначаются как _inputs, а выходы — как _outputs.
  • Экземпляры list и tuple, такие как args или значения, возвращаемые функцией, будут дополнены суффиксом _{index}.
  • Экземпляры dict будут дополнены суффиксом _{key}.

Сравнение реализаций

После того как отладчик проследил прямые проходы двух моделей, можно сравнить файлы вывода в формате json. Ниже мы видим небольшие различия между слоями проекции ключей в этих двух реализациях. Входы в основном идентичны, но не совсем. Просмотр различий в файлах помогает точнее определить, какой слой работает некорректно.

download-icon

Ограничения и область применения

Эта функция будет работать только с моделями на базе torch. Модели, сильно зависящие от вызовов внешних ядер, могут работать, но трассировка, вероятно, упустит некоторые детали. В любом случае, любая реализация на Python, нацеленная на имитацию другой реализации, может быть оттрассирована один раз вместо повторного запуска N раз с точками останова.

Если передать do_prune_layers=False в отладчик модели, все слои будут выведены в json. В противном случае будут показаны только первый и последний слои. Это полезно, когда некоторые слои (обычно cross-attention) появляются только после N слоёв.

transformers.model_addition_debugger_context

< >

( modeldebug_path: str | None = Nonedo_prune_layers: bool = Trueuse_repr: bool = True )

Отладчик добавления моделей — контекстный менеджер для добавляющих моделей

Этот менеджер контекста — инструмент для опытных пользователей, предназначенный для добавления моделей.

Он отслеживает все вызовы forward внутри forward модели и записывает фрагмент каждого входного и выходного значения в вложенный JSON-файл. Если use_repr=True (значение по умолчанию), в JSON-файле будет записана версия тензоров, преобразованная с помощью repr(), в виде списка строк. Если use_repr=False, полные тензоры будут сохранены в отдельных файлах SafeTensors, а JSON-файл будет содержать относительный путь к этому файлу.

Обратите внимание, что этот контекстный менеджер принудительно применяет torch.no_grad().

Использование

добавьте контекстный менеджер к модели для отладки

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 кажется несовместимым с особенностями нашей совершенно новой модели. Но как нам быть уверенными, что, добавляя, казалось бы, безобидный skip, мы не ломаем всё остальное?

Эта утилита:

  • сканирует все методы test_modeling_common
  • ищет моменты, когда метод пропускается
  • возвращает сводный json, который можно загрузить как DataFrame/исследовать

Например, test_inputs_embeds пропускается в 39% случаев на момент написания этой утилиты.

download-icon

Использование

Вы можете запустить анализатор пропущенных тестов двумя способами:

Полное сканирование (по умолчанию)

Из корня репозитория transformers сканирует все общие методы тестирования и выводит результаты в файл JSON (по умолчанию: all_tests_scan_result.json).

python utils/scan_skipped_tests.py --output_dir path/to/output
  • --output_dir (необязательный): каталог, в котором будут сохранены результаты в формате JSON. По умолчанию используется текущий каталог.

Пример вывода:

🔬 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).

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

Это можно визуализировать, как показано выше, например, с помощью pandas

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

Сканирование одного тестового метода

Вы можете сосредоточиться на конкретном методе теста с помощью --test_method_name:

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-файл с результатами.

Пример вывода:

$ 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

Модульный детектор моделей

Анализатор сходства кода - для добавляющих модели

Эта утилита анализирует сходство кода между реализациями моделей, чтобы выявить возможности для модулизации. Она сравнивает новый или существующий файл моделирования со всеми моделями в библиотеке, используя метрики сходства на основе эмбеддингов и токенов.

Обоснование

При добавлении новой модели в transformers многие компоненты (слои внимания, MLP, выходные слои и т. д.) могут уже существовать в похожем виде в других моделях. Вместо реализации всего с нуля, разработчики моделей могут определить, какие существующие классы похожи и потенциально могут быть переиспользованы с помощью модульности.

Инструмент вычисляет два показателя сходства:

  • Оценка встраивания: использует семантические встраивания кода (через Qwen/Qwen3-Embedding-4B) для обнаружения функционально схожего кода даже при различном именовании
  • Показатель Жаккара: измеряет пересечение наборов токенов для выявления структурно похожих паттернов кода

Оценка 1.00 означает, что код идентичен.

Использование

Из корня репозитория transformers:

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

Инструмент автоматически загрузит предварительно созданный индекс из Hub (требуется RAM/VRAM для модели эмбеддингов).

Пример вывода:

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 показывает классы, которые присутствуют в обоих результатах top-5, что указывает на высокую уверенность в кандидатах на модулирование.

Создание собственного индекса

Чтобы перестроить индекс из вашей локальной кодовой базы (полезно после добавления новых моделей или при использовании другой модели эмбеддингов):

python utils/modular_model_detector.py --build

Чтобы отправить перестроенный индекс в набор данных на Hub:

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: идентификатор репозитория датасета на Hub для получения/отправки индекса (по умолчанию: hf-internal-testing/transformers_code_embeddings)

Ограничения

Для работы этого инструмента необходимы ресурсы GPU/CPU для запуска модели эмбеддингов (Qwen/Qwen3-Embedding-4B). По умолчанию готовый индекс загружается с Hub, что требует подключения к интернету при первом использовании.

Результаты представляют собой рекомендации, основанные на сходстве кода, и их следует вручную проверить перед модуляцией. Высокие значения сходства не гарантируют полной совместимости.

Update on GitHub