# Bộ công cụ gỡ lỗi mô hình

Trang này liệt kê tất cả các công cụ gỡ lỗi và thêm mô hình được thư viện sử dụng, cũng như các hàm tiện ích mà nó cung cấp.

Phần lớn những điều đó chỉ hữu ích nếu bạn đang thêm các mô hình mới vào thư viện.

## Trình gỡ lỗi thêm mô hình

### Trình gỡ lỗi thêm mô hình - trình quản lý ngữ cảnh cho các trình thêm mô hình

Context manager này là công cụ dành cho người dùng nâng cao, được thiết kế cho những người thêm model. Nó theo dõi tất cả các lời gọi forward bên trong một forward của model và ghi log một phần (slice) của mỗi input và output vào một JSON lồng nhau. Lưu ý rằng context manager này áp đặt `torch.no_grad()`.

### Lý do

Khi chuyển các mô hình sang transformers, ngay cả khi chỉ chuyển từ Python sang Python, những người thêm mô hình thường phải thực hiện nhiều thao tác thủ công, bao gồm lưu và nạp tensor, so sánh dtype, v.v. Công cụ nhỏ này hy vọng có thể giúp tiết kiệm một ít thời gian.

### Cách sử dụng

Thêm trình quản lý ngữ cảnh này như sau để gỡ lỗi một mô hình:

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

```

### Đọc kết quả

Bộ gỡ lỗi tạo ra hai tệp từ lời gọi forward, cả hai đều có cùng tên cơ sở, nhưng kết thúc bằng `_SUMMARY.json` hoặc `_FULL_TENSORS.json`.

Phần đầu tiên sẽ chứa tóm tắt về giá trị và hình dạng của tensor _đầu vào_ và _đầu ra_ của từng module.

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

Tệp `_FULL_TENSORS.json` sẽ hiển thị toàn bộ các tensor, rất hữu ích để so sánh hai tệp.

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

#### Lưu tensor vào đĩa

Một số người thêm model có thể được hưởng lợi từ việc ghi log giá trị tensor đầy đủ xuống đĩa để hỗ trợ, chẳng hạn như, phân tích số học giữa các triển khai.

Đặt `use_repr=False` để ghi các tensor ra đĩa bằng [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)
```

Khi sử dụng `use_repr=False`, các tensor được ghi vào cùng vị trí trên đĩa với các tệp `_SUMMARY.json` và `_FULL_TENSORS.json`. Thuộc tính `value` của các mục trong tệp `_FULL_TENSORS.json` sẽ chứa tham chiếu đường dẫn tương đối đến tệp `.safetensors` liên quan. Mỗi tensor được ghi vào tệp riêng của nó dưới dạng thuộc tính `data` của state dictionary. Tên tệp được xây dựng bằng cách sử dụng `module_path` làm tiền tố cùng một vài hậu tố có thể, được xây dựng đệ quy.

* Đầu vào của module được ký hiệu bằng `_inputs` và đầu ra bằng `_outputs`.
* Các instance của `list` và `tuple`, chẳng hạn như `args` hoặc giá trị trả về của hàm, sẽ được thêm hậu tố `_{index}`.
* Các instance `dict` sẽ được thêm hậu tố `_{key}`.

### So sánh giữa các bản triển khai

Sau khi các bước truyền tiến (forward passes) của hai mô hình đã được debugger theo dõi, ta có thể so sánh các tệp đầu ra `json`. Xem bên dưới: ta có thể thấy những khác biệt nhỏ giữa lớp dự đoán khóa (key projection layer) của hai cài đặt này. Đầu vào phần lớn là giống hệt nhau, nhưng không hoàn toàn. Việc xem xét các khác biệt trong tệp giúp dễ dàng xác định chính xác lớp nào đang có lỗi.

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

### Hạn chế và phạm vi[[transformers.model_addition_debugger_context]]

Tính năng này chỉ hoạt động với các mô hình dựa trên torch. Các mô hình phụ thuộc nhiều vào các lệnh gọi kernel bên ngoài có thể hoạt động, nhưng trace có thể bỏ sót một số chi tiết. Dù vậy, bất kỳ cài đặt python nào nhằm mô phỏng một cài đặt khác đều có thể được trace một lần thay vì chạy lại N lần với các điểm dừng.

Nếu bạn truyền `do_prune_layers=False` cho trình gỡ lỗi mô hình của bạn, TẤT CẢ các lớp sẽ được xuất ra `json`. Ngược lại, chỉ lớp đầu tiên và lớp cuối cùng sẽ được hiển thị. Điều này hữu ích khi một số lớp (thường là cross-attention) chỉ xuất hiện sau N lớp.

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

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

# Trình gỡ lỗi thêm mô hình - trình quản lý ngữ cảnh cho các trình thêm mô hình
Trình quản lý ngữ cảnh này là công cụ dành cho người dùng nâng cao, được thiết kế cho những người thêm mô hình.

Nó theo dõi tất cả các lời gọi forward trong một forward của model và ghi lại một phần của mỗi đầu vào và đầu ra vào một tệp JSON lồng nhau. Nếu `use_repr=True` (mặc định), tệp JSON sẽ ghi lại phiên bản được `repr()`- hóa của các tensor dưới dạng một danh sách các chuỗi. Nếu `use_repr=False`, các tensor đầy đủ sẽ được lưu trong các tệp SafeTensors riêng biệt và tệp JSON sẽ cung cấp đường dẫn tương đối đến tệp đó.

Lưu ý rằng trình quản lý ngữ cảnh này thực thi `torch.no_grad()`.

## Cách sử dụng

thêm context manager vào một model để gỡ lỗi

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

## Trình phân tích các bài kiểm thử bị bỏ qua

### Quét các bài kiểm tra bị bỏ qua - dành cho người thêm và người duy trì model

Công cụ tiện ích nhỏ này là một công cụ dành cho người dùng nâng cao, được thiết kế cho những người thêm và bảo trì model. Nó liệt kê tất cả các phương thức kiểm thử hiện có trong `test_modeling_common.py`, được kế thừa bởi tất cả các lớp kiểm thử model, và quét kho mã để đo lường số lượng kiểm thử bị bỏ qua và cho những model nào.

### Lý do

Khi port các model sang transformers, các test sẽ thất bại như dự kiến, và đôi khi `test_modeling_common` có vẻ không thể dung hòa với những đặc thù của model hoàn toàn mới của chúng ta. Nhưng làm sao chúng ta có thể chắc chắn rằng mình không phá hỏng mọi thứ khi thêm một skip có vẻ vô hại?

Công cụ tiện ích này:

- quét tất cả các phương thức test_modeling_common
- tìm kiếm các thời điểm mà một phương thức bị bỏ qua
- trả về một tệp json tóm tắt mà bạn có thể tải lên như một DataFrame/xem xét

**Ví dụ, test_inputs_embeds bị bỏ qua với tỷ lệ lên đến 39% tại thời điểm viết tiện ích này.**

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

### Cách sử dụng

Bạn có thể chạy trình phân tích kiểm thử bị bỏ qua theo hai cách:

#### Quét đầy đủ (mặc định)

Từ thư mục gốc của repo `transformers`, quét tất cả các phương thức kiểm thử phổ biến và xuất kết quả ra tệp JSON (mặc định: `all_tests_scan_result.json`).

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

- `--output_dir` (tùy chọn): Thư mục nơi kết quả JSON sẽ được lưu. Mặc định là thư mục hiện tại.

**Kết quả đầu ra mẫu:**

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

```

Và nó sẽ tạo ra tệp `all_tests_scan_result.json` để bạn kiểm tra. JSON được lập chỉ mục theo tên phương thức, và mỗi mục tuân theo schema này, đồng thời chỉ rõ nguồn gốc (từ `common` hoặc `GenerationMixin`.)

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

Bạn có thể trực quan hóa điều này như ở trên, ví dụ bằng `pandas`

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

```

### Quét một phương thức kiểm thử

Bạn có thể tập trung vào một phương thức kiểm thử cụ thể bằng cách sử dụng `--test_method_name`:

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

- `--test_method_name`: Tên của phương thức kiểm tra cần quét (ví dụ: `test_inputs_embeds`).
- `--output_dir` (tùy chọn): Thư mục nơi kết quả JSON sẽ được lưu.

**Kết quả đầu ra mẫu:**

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

```

## Trình phát hiện mô-đun

### Trình phân tích độ tương đồng mã - dành cho người thêm mô hình

Công cụ tiện ích này phân tích sự tương đồng mã giữa các cài đặt mô hình để xác định các cơ hội cho việc mô-đun hóa. Nó so sánh một tệp modeling mới hoặc hiện có với tất cả các mô hình trong thư viện bằng cách sử dụng các chỉ số tương đồng dựa trên embedding và dựa trên token.

### Lý do

Khi thêm một mô hình mới vào transformers, nhiều thành phần (lớp attention, MLP, đầu ra, v.v.) có thể đã tồn tại dưới dạng tương tự trong các mô hình khác. Thay vì triển khai mọi thứ từ đầu, người thêm mô hình có thể xác định các lớp hiện có nào tương tự và có khả năng tái sử dụng thông qua việc mô-đun hóa.

Công cụ tính toán hai điểm số tương tự:

- **Điểm nhúng**: Sử dụng nhúng mã ngữ nghĩa (thông qua `Qwen/Qwen3-Embedding-4B`) để phát hiện mã có chức năng tương tự ngay cả khi đặt tên khác nhau
- **Điểm Jaccard**: Đo mức độ chồng chéo của tập token để xác định các mẫu mã có cấu trúc tương tự

Điểm 1.00 có nghĩa là mã giống hệt nhau.

### Cách sử dụng

Từ thư mục gốc của kho `transformers`:

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

Công cụ sẽ tự động tải xuống chỉ mục đã được xây dựng sẵn từ Hub (yêu cầu RAM/VRAM cho mô hình nhúng).

**Kết quả đầu ra mẫu:**

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

Trường `intersection` hiển thị các lớp xuất hiện trong cả hai kết quả top-5, cho thấy độ tin cậy cao đối với các ứng viên modularization.

### Xây dựng chỉ mục tùy chỉnh

Để xây dựng lại chỉ mục từ mã nguồn cục bộ của bạn (hữu ích sau khi thêm các mô hình mới hoặc sử dụng một mô hình nhúng khác):

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

Để đẩy chỉ mục đã xây dựng lại lên bộ dữ liệu Hub:

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

### Tùy chọn

- `--modeling-file`: Đường dẫn đến tệp modeling cần phân tích
- `--build`: Xây dựng chỉ mục tương đồng mã từ tất cả các tệp mô hình hóa trong `src/transformers/models/`
- `--push-new-index`: Sau khi xây dựng, đẩy index lên một dataset trên Hub (yêu cầu `--build`)
- `--hub-dataset`: ID kho dữ liệu Hub để kéo/đẩy chỉ mục (mặc định: `hf-internal-testing/transformers_code_embeddings`)

### Hạn chế

Công cụ này yêu cầu tài nguyên GPU/CPU để chạy mô hình embedding (`Qwen/Qwen3-Embedding-4B`). Chỉ mục được xây dựng sẵn sẽ được tải xuống từ Hub theo mặc định, điều này đòi hỏi kết nối internet khi sử dụng lần đầu.

Kết quả là các gợi ý dựa trên độ tương đồng của mã và nên được xem xét thủ công trước khi thực hiện modularization. Điểm tương đồng cao không đảm bảo khả năng tương thích hoàn hảo.

