Transformers 文档
模型调试工具箱
并获得增强的文档体验
开始使用
模型调试工具箱
本页面列出了库使用的所有调试和模型添加工具,以及它提供的相关实用函数。
其中大部分只有在您向库中添加新模型时才有用。
模型添加调试器
模型添加调试器 - 模型添加器的上下文管理器
此上下文管理器是为模型添加器设计的,面向高级用户。它会跟踪模型前向传播中的所有前向调用,并在嵌套的 JSON 中记录每个输入和输出的切片。需要注意的是,此上下文管理器会强制执行 torch.no_grad()。
原理
在将模型移植到 transformers 时,即使是从 Python 到 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)
读取结果
调试器会从前向调用生成两个文件,它们具有相同的基本名称,但后缀分别为 _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 输出文件。请看下面:我们可以看到这两个实现的关键投影层之间存在细微的差异。输入大部分相同,但并非完全一致。查看文件差异可以更容易地确定哪个层是错误的。

限制和范围
此功能仅适用于基于 torch 的模型。严重依赖外部内核调用的模型可能有效,但跟踪可能会错过一些东西。无论如何,任何旨在模仿另一个实现的 Python 实现都可以被跟踪一次,而不是 N 次与断点一起运行。
如果您将 do_prune_layers=False 传递给模型调试器,则所有层都将输出到 json。否则,只有第一层和最后一层将显示。这在某些层(通常是交叉注意力)仅在 N 层之后出现时非常有用。
transformers.model_addition_debugger_context
< 来源 >( model debug_path: str | None = None do_prune_layers: bool = True use_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%。

用法
您可以通过两种方式运行跳过测试分析器
完整扫描(默认)
从 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 分数:测量标记集合重叠度,以识别结构相似的代码模式
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 下载,首次使用时需要互联网连接。
结果是基于代码相似性的建议,在模块化之前应手动审查。高相似度分数不能保证完美的兼容性。
在 GitHub 上更新