Unverified Commit 96d1fecf authored by Aditya Gandhamal's avatar Aditya Gandhamal Committed by GitHub
Browse files

Handle invalid reduction values (#6675)



* Add ValueError

* Add tests for ValueError

* Add tests for ValueError

* Add ValueError

* Change to if/else

* Ammend iou_fn tests

* Move code excerpt

* Format tests
Co-authored-by: default avatarPhilip Meier <github.pmeier@posteo.de>
Co-authored-by: default avatarVasilis Vryniotis <datumbox@users.noreply.github.com>
parent 46eae182
...@@ -1394,6 +1394,11 @@ class TestGeneralizedBoxIouLoss: ...@@ -1394,6 +1394,11 @@ class TestGeneralizedBoxIouLoss:
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, 2.5, device=device, reduction="sum")
assert_iou_loss(ops.generalized_box_iou_loss, box1s, box2s, 1.25, device=device, reduction="mean") 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("device", cpu_and_gpu())
@pytest.mark.parametrize("dtype", [torch.float32, torch.half]) @pytest.mark.parametrize("dtype", [torch.float32, torch.half])
def test_empty_inputs(self, dtype, device): def test_empty_inputs(self, dtype, device):
...@@ -1413,6 +1418,9 @@ class TestCompleteBoxIouLoss: ...@@ -1413,6 +1418,9 @@ class TestCompleteBoxIouLoss:
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, 1.2250, device=device, reduction="mean")
assert_iou_loss(ops.complete_box_iou_loss, box1s, box2s, 2.4500, device=device, reduction="sum") 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("device", cpu_and_gpu())
@pytest.mark.parametrize("dtype", [torch.float32, torch.half]) @pytest.mark.parametrize("dtype", [torch.float32, torch.half])
def test_empty_inputs(self, dtype, device): def test_empty_inputs(self, dtype, device):
...@@ -1432,6 +1440,9 @@ class TestDistanceBoxIouLoss: ...@@ -1432,6 +1440,9 @@ class TestDistanceBoxIouLoss:
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, 1.2250, device=device, reduction="mean")
assert_iou_loss(ops.distance_box_iou_loss, box1s, box2s, 2.4500, device=device, reduction="sum") 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("device", cpu_and_gpu())
@pytest.mark.parametrize("dtype", [torch.float32, torch.half]) @pytest.mark.parametrize("dtype", [torch.float32, torch.half])
def test_empty_distance_iou_inputs(self, dtype, device): def test_empty_distance_iou_inputs(self, dtype, device):
...@@ -1554,6 +1565,17 @@ class TestFocalLoss: ...@@ -1554,6 +1565,17 @@ class TestFocalLoss:
tol = 1e-3 if dtype is torch.half else 1e-5 tol = 1e-3 if dtype is torch.half else 1e-5
torch.testing.assert_close(focal_loss, scripted_focal_loss, rtol=tol, atol=tol) 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: class TestMasksToBoxes:
def test_masks_box(self): def test_masks_box(self):
......
...@@ -63,9 +63,16 @@ def complete_box_iou_loss( ...@@ -63,9 +63,16 @@ def complete_box_iou_loss(
alpha = v / (1 - iou + v + eps) alpha = v / (1 - iou + v + eps)
loss = diou_loss + alpha * v 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() loss = loss.mean() if loss.numel() > 0 else 0.0 * loss.sum()
elif reduction == "sum": elif reduction == "sum":
loss = loss.sum() loss = loss.sum()
else:
raise ValueError(
f"Invalid Value for arg 'reduction': '{reduction} \n Supported reduction modes: 'none', 'mean', 'sum'"
)
return loss return loss
...@@ -50,10 +50,17 @@ def distance_box_iou_loss( ...@@ -50,10 +50,17 @@ def distance_box_iou_loss(
loss, _ = _diou_iou_loss(boxes1, boxes2, eps) 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() loss = loss.mean() if loss.numel() > 0 else 0.0 * loss.sum()
elif reduction == "sum": elif reduction == "sum":
loss = loss.sum() loss = loss.sum()
else:
raise ValueError(
f"Invalid Value for arg 'reduction': '{reduction} \n Supported reduction modes: 'none', 'mean', 'sum'"
)
return loss return loss
......
...@@ -32,6 +32,7 @@ def sigmoid_focal_loss( ...@@ -32,6 +32,7 @@ def sigmoid_focal_loss(
Loss tensor with the reduction option applied. Loss tensor with the reduction option applied.
""" """
# Original implementation from https://github.com/facebookresearch/fvcore/blob/master/fvcore/nn/focal_loss.py # 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(): if not torch.jit.is_scripting() and not torch.jit.is_tracing():
_log_api_usage_once(sigmoid_focal_loss) _log_api_usage_once(sigmoid_focal_loss)
p = torch.sigmoid(inputs) p = torch.sigmoid(inputs)
...@@ -43,9 +44,15 @@ def sigmoid_focal_loss( ...@@ -43,9 +44,15 @@ def sigmoid_focal_loss(
alpha_t = alpha * targets + (1 - alpha) * (1 - targets) alpha_t = alpha * targets + (1 - alpha) * (1 - targets)
loss = alpha_t * loss loss = alpha_t * loss
if reduction == "mean": # Check reduction option and return loss accordingly
if reduction == "none":
pass
elif reduction == "mean":
loss = loss.mean() loss = loss.mean()
elif reduction == "sum": elif reduction == "sum":
loss = loss.sum() loss = loss.sum()
else:
raise ValueError(
f"Invalid Value for arg 'reduction': '{reduction} \n Supported reduction modes: 'none', 'mean', 'sum'"
)
return loss return loss
...@@ -62,9 +62,15 @@ def generalized_box_iou_loss( ...@@ -62,9 +62,15 @@ def generalized_box_iou_loss(
loss = 1 - miouk 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() loss = loss.mean() if loss.numel() > 0 else 0.0 * loss.sum()
elif reduction == "sum": elif reduction == "sum":
loss = loss.sum() loss = loss.sum()
else:
raise ValueError(
f"Invalid Value for arg 'reduction': '{reduction} \n Supported reduction modes: 'none', 'mean', 'sum'"
)
return loss return loss
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment