@@ -1569,5 +1569,59 @@ def test_jit(self, alpha, gamma, reduction, device, dtype, seed) -> None:
1569
1569
torch .testing .assert_close (focal_loss , scripted_focal_loss , rtol = tol , atol = tol )
1570
1570
1571
1571
1572
+ class TestGeneralizedBoxIouLoss :
1573
+ # We refer to original test: https://github.com/facebookresearch/fvcore/blob/main/tests/test_giou_loss.py
1574
+ @pytest .mark .parametrize ("device" , cpu_and_gpu ())
1575
+ @pytest .mark .parametrize ("dtype" , [torch .float32 , torch .half ])
1576
+ def test_giou_loss (self , dtype , device ) -> None :
1577
+ box1 = torch .tensor ([- 1 , - 1 , 1 , 1 ], dtype = dtype , device = device )
1578
+ box2 = torch .tensor ([0 , 0 , 1 , 1 ], dtype = dtype , device = device )
1579
+ box3 = torch .tensor ([0 , 1 , 1 , 2 ], dtype = dtype , device = device )
1580
+ box4 = torch .tensor ([1 , 1 , 2 , 2 ], dtype = dtype , device = device )
1581
+ box1s = torch .stack ([box2 , box2 ], dim = 0 )
1582
+ box2s = torch .stack ([box3 , box4 ], dim = 0 )
1583
+
1584
+ def assert_giou_loss (box1 , box2 , expected_loss , reduction = "none" ):
1585
+ tol = 1e-3 if dtype is torch .half else 1e-5
1586
+ computed_loss = ops .generalized_box_iou_loss (box1 , box2 , reduction = reduction )
1587
+ expected_loss = torch .tensor (expected_loss , device = device )
1588
+ torch .testing .assert_close (computed_loss , expected_loss , rtol = tol , atol = tol )
1589
+
1590
+ # Identical boxes should have loss of 0
1591
+ assert_giou_loss (box1 , box1 , 0.0 )
1592
+
1593
+ # quarter size box inside other box = IoU of 0.25
1594
+ assert_giou_loss (box1 , box2 , 0.75 )
1595
+
1596
+ # Two side by side boxes, area=union
1597
+ # IoU=0 and GIoU=0 (loss 1.0)
1598
+ assert_giou_loss (box2 , box3 , 1.0 )
1599
+
1600
+ # Two diagonally adjacent boxes, area=2*union
1601
+ # IoU=0 and GIoU=-0.5 (loss 1.5)
1602
+ assert_giou_loss (box2 , box4 , 1.5 )
1603
+
1604
+ # Test batched loss and reductions
1605
+ assert_giou_loss (box1s , box2s , 2.5 , reduction = "sum" )
1606
+ assert_giou_loss (box1s , box2s , 1.25 , reduction = "mean" )
1607
+
1608
+ @pytest .mark .parametrize ("device" , cpu_and_gpu ())
1609
+ @pytest .mark .parametrize ("dtype" , [torch .float32 , torch .half ])
1610
+ def test_empty_inputs (self , dtype , device ) -> None :
1611
+ box1 = torch .randn ([0 , 4 ], dtype = dtype ).requires_grad_ ()
1612
+ box2 = torch .randn ([0 , 4 ], dtype = dtype ).requires_grad_ ()
1613
+
1614
+ loss = ops .generalized_box_iou_loss (box1 , box2 , reduction = "mean" )
1615
+ loss .backward ()
1616
+
1617
+ tol = 1e-3 if dtype is torch .half else 1e-5
1618
+ torch .testing .assert_close (loss , torch .tensor (0.0 ), rtol = tol , atol = tol )
1619
+ assert box1 .grad is not None , "box1.grad should not be None after backward is called"
1620
+ assert box2 .grad is not None , "box2.grad should not be None after backward is called"
1621
+
1622
+ loss = ops .generalized_box_iou_loss (box1 , box2 , reduction = "none" )
1623
+ assert loss .numel () == 0 , "giou_loss for two empty box should be empty"
1624
+
1625
+
1572
1626
if __name__ == "__main__" :
1573
1627
pytest .main ([__file__ ])
0 commit comments