Transformers documentation
Boîtes à outils de débogage de modèles
Boîtes à outils de débogage de modèles
Cette page répertorie tous les outils de débogage et d’ajout de modèles utilisés par la bibliothèque, ainsi que les fonctions utilitaires qu’elle fournit à cet effet.
La plupart de ces éléments ne sont utiles que si vous ajoutez de nouveaux modèles à la bibliothèque.
Débogageurs d'ajout de modèles
Débogueur d'ajout de modèle - gestionnaire de contexte pour les ajouts de modèles
Ce gestionnaire de contexte est un outil destiné aux utilisateurs avancés et aux contributeurs de modèles. Il suit tous les appels forward au sein d’un forward de modèle et enregistre un extrait de chaque entrée et sortie dans un JSON imbriqué. À noter que ce gestionnaire de contexte impose torch.no_grad().
Justification
Lors du portage de modèles vers Transformers, même d’un langage Python à un autre, les personnes qui ajoutent des modèles doivent souvent effectuer de nombreuses opérations manuelles, telles que l’enregistrement et le chargement de tenseurs, la comparaison des dtypes, etc. Cet outil léger devrait permettre de gagner un peu de temps.
Utilisation
Ajoutez ce gestionnaire de contexte comme suit pour déboguer un modèle :
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)
Lecture des résultats
Le débogueur génère deux fichiers à partir de l’appel forward, tous deux portant le même nom de base, mais se terminant par _SUMMARY.json ou par _FULL_TENSORS.json.
Le premier contiendra un résumé des valeurs et des formes des tenseurs en entrée et en sortie de chaque module.
{
"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 onLe fichier _FULL_TENSORS.json affiche une vue complète de tous les tenseurs, ce qui est utile pour comparer deux fichiers.
"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')"
},Enregistrer des tenseurs sur le disque
Certains créateurs de modèles peuvent bénéficier de la journalisation des valeurs complètes des tenseurs sur disque pour prendre en charge, par exemple, l'analyse numérique entre différentes implémentations.
Définissez use_repr=False pour écrire les tenseurs sur le disque à l'aide de 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)Lors de l’utilisation de use_repr=False, les tenseurs sont écrits à l’emplacement disque des fichiers _SUMMARY.json et _FULL_TENSORS.json. La propriété value des entrées du fichier _FULL_TENSORS.json contiendra une référence de chemin relatif vers le fichier .safetensors associé. Chaque tenseur est écrit dans son propre fichier en tant que propriété data du dictionnaire d’état. Les noms de fichiers sont construits en utilisant module_path comme préfixe, avec quelques suffixes possibles construits de manière récursive.
- Les entrées des modules sont notées
_inputset les sorties_outputs. - Les instances de
listet detuple, telles queargsou les valeurs de retour de fonctions, seront suivies de_{index}. - Les instances de
dictseront suivies de_{key}.
Comparaison entre les implémentations
Une fois que les passes avant de deux modèles ont été tracées par le débogueur, on peut comparer les fichiers de sortie json. Voir
ci-dessous : on peut observer de légères différences entre la couche de projection des clés de ces deux implémentations. Les entrées sont
presque identiques, mais pas tout à fait. Examiner les différences dans le fichier facilite l’identification de la couche erronée.

Limites et périmètre
Cette fonctionnalité ne fonctionnera que pour les modèles basés sur torch. Les modèles qui s’appuient fortement sur des appels de noyaux externes peuvent fonctionner, mais la trace manquera probablement certains éléments. Quoi qu’il en soit, toute implémentation en python visant à imiter une autre implémentation peut être tracée une seule fois au lieu d’être exécutée N fois avec des points d’arrêt.
Si vous passez do_prune_layers=False à votre débogueur de modèle, toutes les couches seront exportées dans json. Sinon, seules la première et la dernière couche seront affichées. Cela est utile lorsque certaines couches (généralement l'attention croisée) n'apparaissent qu'après N couches.
transformers.model_addition_debugger_context
< source >( modeldebug_path: str | None = Nonedo_prune_layers: bool = Trueuse_repr: bool = True )
Débogueur d'ajout de modèle - gestionnaire de contexte pour les ajouts de modèles
Ce gestionnaire de contexte est un outil destiné aux utilisateurs avancés, en particulier aux personnes qui ajoutent des modèles.
Il suit tous les appels forward au sein d'un forward de modèle et enregistre un extrait de chaque entrée et sortie dans un fichier JSON imbriqué.
Si use_repr=True (par défaut), le fichier JSON enregistre une version repr() des tenseurs sous forme d'une liste de
chaînes de caractères. Si use_repr=False, les tenseurs complets sont stockés dans des fichiers SafeTensors séparés et le fichier JSON
fournit un chemin relatif vers ce fichier.
À noter, ce gestionnaire de contexte impose torch.no_grad().
Utilisation
ajouter le gestionnaire de contexte à un modèle pour le débogage
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)Analyseur des tests ignorés
Analyser les tests ignorés - pour les contributeurs et les mainteneurs de modèles
Cet utilitaire discret est un outil destiné aux utilisateurs avancés, aux personnes qui ajoutent des modèles et aux mainteneurs. Il répertorie toutes les méthodes de test présentes dans test_modeling_common.py, héritées par toutes les classes de testeur de modèles, et analyse le dépôt pour mesurer le nombre de tests ignorés et pour quels modèles.
Justification
Lors du portage de modèles vers Transformers, les tests échouent comme il se doit, et parfois test_modeling_common semble irréconciliable avec les particularités de notre tout nouveau modèle. Mais comment être sûrs de ne pas tout casser en ajoutant un skip apparemment inoffensif ?
Cette utilitaire :
- scanne toutes les méthodes de test_modeling_common
- recherche les moments où une méthode est ignorée
- renvoie un résumé au format JSON que vous pouvez charger en tant que DataFrame/inspecter
Par exemple, test_inputs_embeds est ignoré dans une proportion impressionnante de 39 % au moment de la rédaction de cet utilitaire.

Utilisation
Vous pouvez exécuter l'analyseur de tests ignorés de deux manières :
Analyse complète (par défaut)
Depuis la racine du dépôt transformers, scanne toutes les méthodes de test courantes et affiche les résultats dans un fichier JSON (par défaut : all_tests_scan_result.json).
python utils/scan_skipped_tests.py --output_dir path/to/output
--output_dir(facultatif) : répertoire où les résultats JSON seront enregistrés. Par défaut, le répertoire courant est utilisé.
Exemple de sortie :
🔬 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
Il génère le fichier all_tests_scan_result.json que vous pouvez inspecter. Le JSON est indexé par nom de méthode, et chaque entrée suit ce schéma, indiquant également l’origine (depuis common ou GenerationMixin.)
{
"<method_name>": {
"origin": "<test suite>"
"models_ran": ["<model_name>", ...],
"models_skipped": ["<model_name>", ...],
"skipped_proportion": <float>,
"reasons_skipped": ["<model_name>: <reason>",
...
]
},
...
}Ce que vous pouvez visualiser comme ci-dessus avec, par exemple, pandas
df = pd.read_json('all_tests_scan_result.json').T
df.sort_values(by=['skipped_proportion'], ascending=False)
Analyser une seule méthode de test
Vous pouvez cibler une méthode de test spécifique à l’aide de --test_method_name :
python utils/scan_skipped_tests.py --test_method_name test_inputs_embeds --output_dir path/to/output
--test_method_name: Nom de la méthode de test à analyser (par exemple,test_inputs_embeds).--output_dir(facultatif) : répertoire où le résultat JSON sera enregistré.
Exemple de sortie :
$ 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
Détecteur de modèles modulaire
Analyseur de similarité de code - pour les ajouts de modèles
Cet utilitaire analyse les similarités de code entre les implémentations de modèles afin d’identifier les opportunités de modularisation. Il compare un fichier de modélisation nouveau ou existant à tous les modèles de la bibliothèque à l’aide de métriques de similarité basées sur les embeddings et sur les jetons.
Justification
Lors de l’ajout d’un nouveau modèle à transformers, de nombreux composants (couches d’attention, MLP, sorties, etc.) peuvent déjà exister sous une forme similaire dans d’autres modèles. Plutôt que d’implémenter tout à partir de zéro, les ajouts de modèles peuvent identifier quelles classes existantes sont similaires et potentiellement réutilisables grâce à la modularisation.
L'outil calcule deux scores de similarité :
- Score d'embedding : Utilise des embeddings de code sémantiques (via
Qwen/Qwen3-Embedding-4B) pour détecter du code fonctionnellement similaire, même avec des noms différents - Score de Jaccard : Mesure le chevauchement des ensembles de jetons pour identifier des motifs de code structurellement similaires
Un score de 1.00 signifie que le code est identique.
Utilisation
Depuis la racine du dépôt transformers :
python utils/modular_model_detector.py --modeling-file path/to/modeling_file.py
L'outil téléchargera automatiquement l'index préconstruit depuis le Hub (nécessite de la RAM/VRAM pour le modèle d'embedding).
Exemple de sortie :
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:Le champ intersection affiche les classes qui apparaissent dans les deux résultats top-5, indiquant une forte confiance pour les candidats à la modularisation.
Créer un index personnalisé
Pour reconstruire l'index à partir de votre base de code locale (utile après l'ajout de nouveaux modèles ou l'utilisation d'un modèle d'embedding différent) :
python utils/modular_model_detector.py --build
Pour pousser l'index reconstruit vers un jeu de données du Hub :
python utils/modular_model_detector.py --build --push-new-index --hub-dataset your-org/your-dataset
Options
--modeling-file: Chemin vers le fichier de modélisation à analyser--build: Construit l'index de similarité du code à partir de tous les fichiers de modélisation danssrc/transformers/models/--push-new-index: après la construction, pousse l’index vers un jeu de données du Hub (nécessite--build)--hub-dataset: identifiant du dépôt de jeu de données sur le Hub à partir duquel tirer/pousser l'index (par défaut :hf-internal-testing/transformers_code_embeddings)
Limites
Cet outil nécessite des ressources GPU/CPU pour exécuter le modèle d'embedding (Qwen/Qwen3-Embedding-4B). L'index préconstruit est téléchargé depuis le Hub par défaut, ce qui requiert une connexion internet lors de la première utilisation.
Les résultats sont des suggestions basées sur la similarité du code et doivent être examinées manuellement avant la modularisation. Des scores de similarité élevés ne garantissent pas une compatibilité parfaite.
Update on GitHub