Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/transformers/loss/loss_rt_detr.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ def forward(self, outputs, targets):
giou_cost = -generalized_box_iou(center_to_corners_format(out_bbox), center_to_corners_format(target_bbox))
# Compute the final cost matrix
cost_matrix = self.bbox_cost * bbox_cost + self.class_cost * class_cost + self.giou_cost * giou_cost
# we assume any good match will not cause NaN or Inf, so we replace them with the maximum
# finite value to ensure these entries are never preferentially matched (avoids the error
# ``ValueError: cost matrix is infeasible``)
max_value = torch.finfo(cost_matrix.dtype).max
cost_matrix = torch.nan_to_num(cost_matrix, nan=max_value, posinf=max_value, neginf=max_value)
cost_matrix = cost_matrix.view(batch_size, num_queries, -1).cpu()

sizes = [len(v["boxes"]) for v in targets]
Expand Down
39 changes: 39 additions & 0 deletions tests/models/rt_detr/test_modeling_rt_detr.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
)
from transformers.testing_utils import (
Expectations,
require_scipy,
require_torch,
require_torch_accelerator,
require_vision,
Expand Down Expand Up @@ -757,3 +758,41 @@ def test_inference_object_detection_head(self):
torch.testing.assert_close(results["scores"][:4], expected_scores, rtol=2e-4, atol=2e-4)
self.assertSequenceEqual(results["labels"][:4].tolist(), expected_labels)
torch.testing.assert_close(results["boxes"][:4], expected_slice_boxes, rtol=2e-4, atol=2e-4)


@require_torch
@require_scipy
@require_vision
class RTDetrHungarianMatcherTest(unittest.TestCase):
def test_infinite_costs_do_not_crash_matcher(self):
"""
Regression test for #47000. Under AMP, fp16 sigmoid saturation makes the focal class cost
overflow to +/-inf (the 1e-8 epsilon underflows to 0 in fp16, so ``log(0)`` is hit), and
``scipy.optimize.linear_sum_assignment`` raised ``ValueError: cost matrix is infeasible``.
"""
from transformers.loss.loss_rt_detr import RTDetrHungarianMatcher

config = RTDetrConfig(num_labels=4)
matcher = RTDetrHungarianMatcher(config)

num_queries, num_targets = 4, 3
pred_boxes = torch.rand(1, num_queries, 4) * 0.5 + 0.25
targets = [
{
"class_labels": torch.tensor([0, 1, 2]),
"boxes": torch.rand(num_targets, 4) * 0.5 + 0.25,
}
]

for saturating_logit in (-30.0, 30.0, float("nan")):
# fp16 logits as produced under AMP: sigmoid saturates to exactly 0.0 (or 1.0),
# making ``pos_cost_class`` (or ``neg_cost_class``) infinite
logits = torch.full((1, num_queries, config.num_labels), saturating_logit, dtype=torch.float16)
outputs = {"logits": logits, "pred_boxes": pred_boxes}

indices = matcher(outputs, targets)

self.assertEqual(len(indices), 1)
row_indices, col_indices = indices[0]
self.assertEqual(len(row_indices), num_targets)
self.assertEqual(len(col_indices), num_targets)
Loading