Transformers documentation

模型调试工具箱

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,模型添加者通常也需要执行大量手动操作,例如保存和加载张量、比较 dtype 等。这个小工具希望能节省一些时间。

用法

按以下方式添加此上下文管理器以调试模型:

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)

读取结果

调试器会根据前向调用生成两个文件,两者具有相同的基础名称,但分别以 _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 文件相同的磁盘位置。_FULL_TENSORS.json 文件中条目的 value 属性将包含指向关联 .safetensors 文件的相对路径引用。每个张量都会作为状态字典的 data 属性写入其独立的文件。文件名以 module_path 作为前缀,并附加若干通过递归方式构建的后缀来生成。

  • 模块的输入以 _inputs 表示,输出以 _outputs 表示。
  • list 和 tuple 实例(例如 args 或函数返回值)会在末尾添加 _{index}。
  • dict 实例将附加后缀 _{key}。

比较不同实现

当调试器追踪完两个模型的前向传播后,可以比较 json 输出文件。见下文:我们可以看到这两个实现的键投影层存在细微差异。输入基本相同,但并不完全一致。查看文件差异有助于精确定位出错的层。

download-icon

局限性与范围

此功能仅适用于基于 torch 的模型。严重依赖外部内核调用的模型可能可以运行,但 trace 很可能会遗漏一些内容。无论如何,任何旨在模拟另一实现的 Python 实现都可以被 trace 一次,而无需通过断点重新运行 N 次。

如果向模型调试器传入 do_prune_layers=False,则所有层都会输出到 json 中。否则,仅显示第一层和最后一层。当某些层(通常是交叉注意力层)仅在 N 层之后出现时,此功能非常有用。

transformers.model_addition_debugger_context

< >

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

模型添加调试器 - 用于模型添加器的上下文管理器

此上下文管理器是面向模型添加者的进阶用户工具。

它会跟踪模型前向传播中的所有前向调用,并将每个输入和输出的切片记录到一个嵌套的 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 似乎与我们全新模型的独特特性格格不入。但如何确保我们添加的看似无害的跳过操作不会破坏一切呢?

此实用工具:

  • 扫描所有 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)来检测功能相似的代码,即使命名不同
  • Jaccard 分数:通过衡量 token 集合的重叠度来识别结构相似的代码模式

得分为 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 字段显示了同时出现在前 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 数据集仓库 ID(默认值:hf-internal-testing/transformers_code_embeddings)

局限性

此工具需要 GPU/CPU 资源来运行嵌入模型(Qwen/Qwen3-Embedding-4B)。默认情况下,预构建的索引会从 Hub 下载,首次使用时需要互联网连接。

结果是基于代码相似度的建议,在模块化之前应进行人工审查。高相似度分数并不保证完全兼容。

Update on GitHub