diff --git a/test/test_ops.py b/test/test_ops.py index b34fbe7f254..d76e57faecf 100644 --- a/test/test_ops.py +++ b/test/test_ops.py @@ -1394,6 +1394,11 @@ def test_giou_loss(self, dtype, device): assert_iou_loss(ops.generalized_box_iou_loss, box1s, box2s, 2.5, device=device, reduction="sum") assert_iou_loss(ops.generalized_box_iou_loss, box1s, box2s, 1.25, device=device, reduction="mean") + # Test reduction value + # reduction value other than ["none", "mean", "sum"] should raise a ValueError + with pytest.raises(ValueError, match="Invalid"): + ops.generalized_box_iou_loss(box1s, box2s, reduction="xyz") + @pytest.mark.parametrize("device", cpu_and_gpu()) @pytest.mark.parametrize("dtype", [torch.float32, torch.half]) def test_empty_inputs(self, dtype, device): @@ -1413,6 +1418,9 @@ def test_ciou_loss(self, dtype, device): assert_iou_loss(ops.complete_box_iou_loss, box1s, box2s, 1.2250, device=device, reduction="mean") assert_iou_loss(ops.complete_box_iou_loss, box1s, box2s, 2.4500, device=device, reduction="sum") + with pytest.raises(ValueError, match="Invalid"): + ops.complete_box_iou_loss(box1s, box2s, reduction="xyz") + @pytest.mark.parametrize("device", cpu_and_gpu()) @pytest.mark.parametrize("dtype", [torch.float32, torch.half]) def test_empty_inputs(self, dtype, device): @@ -1432,6 +1440,9 @@ def test_distance_iou_loss(self, dtype, device): assert_iou_loss(ops.distance_box_iou_loss, box1s, box2s, 1.2250, device=device, reduction="mean") assert_iou_loss(ops.distance_box_iou_loss, box1s, box2s, 2.4500, device=device, reduction="sum") + with pytest.raises(ValueError, match="Invalid"): + ops.distance_box_iou_loss(box1s, box2s, reduction="xyz") + @pytest.mark.parametrize("device", cpu_and_gpu()) @pytest.mark.parametrize("dtype", [torch.float32, torch.half]) def test_empty_distance_iou_inputs(self, dtype, device): @@ -1554,6 +1565,17 @@ def test_jit(self, alpha, gamma, reduction, device, dtype, seed): tol = 1e-3 if dtype is torch.half else 1e-5 torch.testing.assert_close(focal_loss, scripted_focal_loss, rtol=tol, atol=tol) + # Raise ValueError for anonymous reduction mode + @pytest.mark.parametrize("device", cpu_and_gpu()) + @pytest.mark.parametrize("dtype", [torch.float32, torch.half]) + def test_reduction_mode(self, device, dtype, reduction="xyz"): + if device == "cpu" and dtype is torch.half: + pytest.skip("Currently torch.half is not fully supported on cpu") + torch.random.manual_seed(0) + inputs, targets = self._generate_diverse_input_target_pair(device=device, dtype=dtype) + with pytest.raises(ValueError, match="Invalid"): + ops.sigmoid_focal_loss(inputs, targets, 0.25, 2, reduction) + class TestMasksToBoxes: def test_masks_box(self): diff --git a/torchvision/ops/ciou_loss.py b/torchvision/ops/ciou_loss.py index a9f20a5f4c8..75a1c4cb1f3 100644 --- a/torchvision/ops/ciou_loss.py +++ b/torchvision/ops/ciou_loss.py @@ -63,9 +63,16 @@ def complete_box_iou_loss( alpha = v / (1 - iou + v + eps) loss = diou_loss + alpha * v - if reduction == "mean": + + # Check reduction option and return loss accordingly + if reduction == "none": + pass + elif reduction == "mean": loss = loss.mean() if loss.numel() > 0 else 0.0 * loss.sum() elif reduction == "sum": loss = loss.sum() - + else: + raise ValueError( + f"Invalid Value for arg 'reduction': '{reduction} \n Supported reduction modes: 'none', 'mean', 'sum'" + ) return loss diff --git a/torchvision/ops/diou_loss.py b/torchvision/ops/diou_loss.py index 2187aea4cc5..caf62bd2cbf 100644 --- a/torchvision/ops/diou_loss.py +++ b/torchvision/ops/diou_loss.py @@ -50,10 +50,17 @@ def distance_box_iou_loss( loss, _ = _diou_iou_loss(boxes1, boxes2, eps) - if reduction == "mean": + # Check reduction option and return loss accordingly + if reduction == "none": + pass + elif reduction == "mean": loss = loss.mean() if loss.numel() > 0 else 0.0 * loss.sum() elif reduction == "sum": loss = loss.sum() + else: + raise ValueError( + f"Invalid Value for arg 'reduction': '{reduction} \n Supported reduction modes: 'none', 'mean', 'sum'" + ) return loss diff --git a/torchvision/ops/focal_loss.py b/torchvision/ops/focal_loss.py index c8cc9a8ac14..08c282555fc 100644 --- a/torchvision/ops/focal_loss.py +++ b/torchvision/ops/focal_loss.py @@ -32,6 +32,7 @@ def sigmoid_focal_loss( Loss tensor with the reduction option applied. """ # Original implementation from https://github.com/facebookresearch/fvcore/blob/master/fvcore/nn/focal_loss.py + if not torch.jit.is_scripting() and not torch.jit.is_tracing(): _log_api_usage_once(sigmoid_focal_loss) p = torch.sigmoid(inputs) @@ -43,9 +44,15 @@ def sigmoid_focal_loss( alpha_t = alpha * targets + (1 - alpha) * (1 - targets) loss = alpha_t * loss - if reduction == "mean": + # Check reduction option and return loss accordingly + if reduction == "none": + pass + elif reduction == "mean": loss = loss.mean() elif reduction == "sum": loss = loss.sum() - + else: + raise ValueError( + f"Invalid Value for arg 'reduction': '{reduction} \n Supported reduction modes: 'none', 'mean', 'sum'" + ) return loss diff --git a/torchvision/ops/giou_loss.py b/torchvision/ops/giou_loss.py index 0c555ec4fe9..03ef8e62291 100644 --- a/torchvision/ops/giou_loss.py +++ b/torchvision/ops/giou_loss.py @@ -62,9 +62,15 @@ def generalized_box_iou_loss( loss = 1 - miouk - if reduction == "mean": + # Check reduction option and return loss accordingly + if reduction == "none": + pass + elif reduction == "mean": loss = loss.mean() if loss.numel() > 0 else 0.0 * loss.sum() elif reduction == "sum": loss = loss.sum() - + else: + raise ValueError( + f"Invalid Value for arg 'reduction': '{reduction} \n Supported reduction modes: 'none', 'mean', 'sum'" + ) return loss