prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Raise error if target boxes are degenerate in Faster R-CNN
  We have had a number of reports with users saying that their training loss is nan after a few iterations.
  
  Most of the time, this is due to degenerate boxes (i.e., boxes with negative sizes or zero area). We should improve the user experience in those situations.
  
  I think that raising an error in `GeneralizedRCNN` if the target boxes are degenerate would be a good compromise.
  
  Related issues: https://github.com/pytorch/vision/issues/2235 https://github.com/pytorch/vision/issues/1994 https://github.com/pytorch/vision/issues/1176 https://github.com/pytorch/vision/issues/1128 #1120 and #997
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `torchvision/models/detection/generalized_rcnn.py`
  Content:
  ```
  1 # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  2 """
  3 Implements the Generalized R-CNN framework
  4 """
  5 
  6 from collections import OrderedDict
  7 import torch
  8 from torch import nn
  9 import warnings
  10 from torch.jit.annotations import Tuple, List, Dict, Optional
  11 from torch import Tensor
  12 
  13 
  14 class GeneralizedRCNN(nn.Module):
  15     """
  16     Main class for Generalized R-CNN.
  17 
  18     Arguments:
  19         backbone (nn.Module):
  20         rpn (nn.Module):
  21         roi_heads (nn.Module): takes the features + the proposals from the RPN and computes
  22             detections / masks from it.
  23         transform (nn.Module): performs the data transformation from the inputs to feed into
  24             the model
  25     """
  26 
  27     def __init__(self, backbone, rpn, roi_heads, transform):
  28         super(GeneralizedRCNN, self).__init__()
  29         self.transform = transform
  30         self.backbone = backbone
  31         self.rpn = rpn
  32         self.roi_heads = roi_heads
  33         # used only on torchscript mode
  34         self._has_warned = False
  35 
  36     @torch.jit.unused
  37     def eager_outputs(self, losses, detections):
  38         # type: (Dict[str, Tensor], List[Dict[str, Tensor]]) -> Tuple[Dict[str, Tensor], List[Dict[str, Tensor]]]
  39         if self.training:
  40             return losses
  41 
  42         return detections
  43 
  44     def forward(self, images, targets=None):
  45         # type: (List[Tensor], Optional[List[Dict[str, Tensor]]]) -> Tuple[Dict[str, Tensor], List[Dict[str, Tensor]]]
  46         """
  47         Arguments:
  48             images (list[Tensor]): images to be processed
  49             targets (list[Dict[Tensor]]): ground-truth boxes present in the image (optional)
  50 
  51         Returns:
  52             result (list[BoxList] or dict[Tensor]): the output from the model.
  53                 During training, it returns a dict[Tensor] which contains the losses.
  54                 During testing, it returns list[BoxList] contains additional fields
  55                 like `scores`, `labels` and `mask` (for Mask R-CNN models).
  56 
  57         """
  58         if self.training and targets is None:
  59             raise ValueError("In training mode, targets should be passed")
  60         if self.training:
  61             assert targets is not None
  62             for target in targets:
  63                 boxes = target["boxes"]
  64                 if isinstance(boxes, torch.Tensor):
  65                     if len(boxes.shape) != 2 or boxes.shape[-1] != 4:
  66                         raise ValueError("Expected target boxes to be a tensor"
  67                                          "of shape [N, 4], got {:}.".format(
  68                                              boxes.shape))
  69                 else:
  70                     raise ValueError("Expected target boxes to be of type "
  71                                      "Tensor, got {:}.".format(type(boxes)))
  72 
  73         original_image_sizes = torch.jit.annotate(List[Tuple[int, int]], [])
  74         for img in images:
  75             val = img.shape[-2:]
  76             assert len(val) == 2
  77             original_image_sizes.append((val[0], val[1]))
  78 
  79         images, targets = self.transform(images, targets)
  80         features = self.backbone(images.tensors)
  81         if isinstance(features, torch.Tensor):
  82             features = OrderedDict([('0', features)])
  83         proposals, proposal_losses = self.rpn(images, features, targets)
  84         detections, detector_losses = self.roi_heads(features, proposals, images.image_sizes, targets)
  85         detections = self.transform.postprocess(detections, images.image_sizes, original_image_sizes)
  86 
  87         losses = {}
  88         losses.update(detector_losses)
  89         losses.update(proposal_losses)
  90 
  91         if torch.jit.is_scripting():
  92             if not self._has_warned:
  93                 warnings.warn("RCNN always returns a (Losses, Detections) tuple in scripting")
  94                 self._has_warned = True
  95             return (losses, detections)
  96         else:
  97             return self.eager_outputs(losses, detections)
  98
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/torchvision/models/detection/generalized_rcnn.py b/torchvision/models/detection/generalized_rcnn.py
  --- a/torchvision/models/detection/generalized_rcnn.py
  +++ b/torchvision/models/detection/generalized_rcnn.py
  @@ -77,6 +77,21 @@
               original_image_sizes.append((val[0], val[1]))
   
           images, targets = self.transform(images, targets)
  +
  +        # Check for degenerate boxes
  +        # TODO: Move this to a function
  +        if targets is not None:
  +            for target_idx, target in enumerate(targets):
  +                boxes = target["boxes"]
  +                degenerate_boxes = boxes[:, 2:] <= boxes[:, :2]
  +                if degenerate_boxes.any():
  +                    # print the first degenrate box
  +                    bb_idx = degenerate_boxes.any(dim=1).nonzero().view(-1)[0]
  +                    degen_bb: List[float] = boxes[bb_idx].tolist()
  +                    raise ValueError("All bounding boxes should have positive height and width."
  +                                     " Found invaid box {} for target at index {}."
  +                                     .format(degen_bb, target_idx))
  +
           features = self.backbone(images.tensors)
           if isinstance(features, torch.Tensor):
               features = OrderedDict([('0', features)])
  
verification_info: {"golden_diff": "diff --git a/torchvision/models/detection/generalized_rcnn.py b/torchvision/models/detection/generalized_rcnn.py\n--- a/torchvision/models/detection/generalized_rcnn.py\n+++ b/torchvision/models/detection/generalized_rcnn.py\n@@ -77,6 +77,21 @@\n             original_image_sizes.append((val[0], val[1]))\n \n         images, targets = self.transform(images, targets)\n+\n+        # Check for degenerate boxes\n+        # TODO: Move this to a function\n+        if targets is not None:\n+            for target_idx, target in enumerate(targets):\n+                boxes = target[\"boxes\"]\n+                degenerate_boxes = boxes[:, 2:] <= boxes[:, :2]\n+                if degenerate_boxes.any():\n+                    # print the first degenrate box\n+                    bb_idx = degenerate_boxes.any(dim=1).nonzero().view(-1)[0]\n+                    degen_bb: List[float] = boxes[bb_idx].tolist()\n+                    raise ValueError(\"All bounding boxes should have positive height and width.\"\n+                                     \" Found invaid box {} for target at index {}.\"\n+                                     .format(degen_bb, target_idx))\n+\n         features = self.backbone(images.tensors)\n         if isinstance(features, torch.Tensor):\n             features = OrderedDict([('0', features)])\n", "issue": "Raise error if target boxes are degenerate in Faster R-CNN\nWe have had a number of reports with users saying that their training loss is nan after a few iterations.\r\n\r\nMost of the time, this is due to degenerate boxes (i.e., boxes with negative sizes or zero area). We should improve the user experience in those situations.\r\n\r\nI think that raising an error in `GeneralizedRCNN` if the target boxes are degenerate would be a good compromise.\r\n\r\nRelated issues: https://github.com/pytorch/vision/issues/2235 https://github.com/pytorch/vision/issues/1994 https://github.com/pytorch/vision/issues/1176 https://github.com/pytorch/vision/issues/1128 #1120 and #997\n", "before_files": [{"content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\"\"\"\nImplements the Generalized R-CNN framework\n\"\"\"\n\nfrom collections import OrderedDict\nimport torch\nfrom torch import nn\nimport warnings\nfrom torch.jit.annotations import Tuple, List, Dict, Optional\nfrom torch import Tensor\n\n\nclass GeneralizedRCNN(nn.Module):\n    \"\"\"\n    Main class for Generalized R-CNN.\n\n    Arguments:\n        backbone (nn.Module):\n        rpn (nn.Module):\n        roi_heads (nn.Module): takes the features + the proposals from the RPN and computes\n            detections / masks from it.\n        transform (nn.Module): performs the data transformation from the inputs to feed into\n            the model\n    \"\"\"\n\n    def __init__(self, backbone, rpn, roi_heads, transform):\n        super(GeneralizedRCNN, self).__init__()\n        self.transform = transform\n        self.backbone = backbone\n        self.rpn = rpn\n        self.roi_heads = roi_heads\n        # used only on torchscript mode\n        self._has_warned = False\n\n    @torch.jit.unused\n    def eager_outputs(self, losses, detections):\n        # type: (Dict[str, Tensor], List[Dict[str, Tensor]]) -> Tuple[Dict[str, Tensor], List[Dict[str, Tensor]]]\n        if self.training:\n            return losses\n\n        return detections\n\n    def forward(self, images, targets=None):\n        # type: (List[Tensor], Optional[List[Dict[str, Tensor]]]) -> Tuple[Dict[str, Tensor], List[Dict[str, Tensor]]]\n        \"\"\"\n        Arguments:\n            images (list[Tensor]): images to be processed\n            targets (list[Dict[Tensor]]): ground-truth boxes present in the image (optional)\n\n        Returns:\n            result (list[BoxList] or dict[Tensor]): the output from the model.\n                During training, it returns a dict[Tensor] which contains the losses.\n                During testing, it returns list[BoxList] contains additional fields\n                like `scores`, `labels` and `mask` (for Mask R-CNN models).\n\n        \"\"\"\n        if self.training and targets is None:\n            raise ValueError(\"In training mode, targets should be passed\")\n        if self.training:\n            assert targets is not None\n            for target in targets:\n                boxes = target[\"boxes\"]\n                if isinstance(boxes, torch.Tensor):\n                    if len(boxes.shape) != 2 or boxes.shape[-1] != 4:\n                        raise ValueError(\"Expected target boxes to be a tensor\"\n                                         \"of shape [N, 4], got {:}.\".format(\n                                             boxes.shape))\n                else:\n                    raise ValueError(\"Expected target boxes to be of type \"\n                                     \"Tensor, got {:}.\".format(type(boxes)))\n\n        original_image_sizes = torch.jit.annotate(List[Tuple[int, int]], [])\n        for img in images:\n            val = img.shape[-2:]\n            assert len(val) == 2\n            original_image_sizes.append((val[0], val[1]))\n\n        images, targets = self.transform(images, targets)\n        features = self.backbone(images.tensors)\n        if isinstance(features, torch.Tensor):\n            features = OrderedDict([('0', features)])\n        proposals, proposal_losses = self.rpn(images, features, targets)\n        detections, detector_losses = self.roi_heads(features, proposals, images.image_sizes, targets)\n        detections = self.transform.postprocess(detections, images.image_sizes, original_image_sizes)\n\n        losses = {}\n        losses.update(detector_losses)\n        losses.update(proposal_losses)\n\n        if torch.jit.is_scripting():\n            if not self._has_warned:\n                warnings.warn(\"RCNN always returns a (Losses, Detections) tuple in scripting\")\n                self._has_warned = True\n            return (losses, detections)\n        else:\n            return self.eager_outputs(losses, detections)\n", "path": "torchvision/models/detection/generalized_rcnn.py"}], "after_files": [{"content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\"\"\"\nImplements the Generalized R-CNN framework\n\"\"\"\n\nfrom collections import OrderedDict\nimport torch\nfrom torch import nn\nimport warnings\nfrom torch.jit.annotations import Tuple, List, Dict, Optional\nfrom torch import Tensor\n\n\nclass GeneralizedRCNN(nn.Module):\n    \"\"\"\n    Main class for Generalized R-CNN.\n\n    Arguments:\n        backbone (nn.Module):\n        rpn (nn.Module):\n        roi_heads (nn.Module): takes the features + the proposals from the RPN and computes\n            detections / masks from it.\n        transform (nn.Module): performs the data transformation from the inputs to feed into\n            the model\n    \"\"\"\n\n    def __init__(self, backbone, rpn, roi_heads, transform):\n        super(GeneralizedRCNN, self).__init__()\n        self.transform = transform\n        self.backbone = backbone\n        self.rpn = rpn\n        self.roi_heads = roi_heads\n        # used only on torchscript mode\n        self._has_warned = False\n\n    @torch.jit.unused\n    def eager_outputs(self, losses, detections):\n        # type: (Dict[str, Tensor], List[Dict[str, Tensor]]) -> Tuple[Dict[str, Tensor], List[Dict[str, Tensor]]]\n        if self.training:\n            return losses\n\n        return detections\n\n    def forward(self, images, targets=None):\n        # type: (List[Tensor], Optional[List[Dict[str, Tensor]]]) -> Tuple[Dict[str, Tensor], List[Dict[str, Tensor]]]\n        \"\"\"\n        Arguments:\n            images (list[Tensor]): images to be processed\n            targets (list[Dict[Tensor]]): ground-truth boxes present in the image (optional)\n\n        Returns:\n            result (list[BoxList] or dict[Tensor]): the output from the model.\n                During training, it returns a dict[Tensor] which contains the losses.\n                During testing, it returns list[BoxList] contains additional fields\n                like `scores`, `labels` and `mask` (for Mask R-CNN models).\n\n        \"\"\"\n        if self.training and targets is None:\n            raise ValueError(\"In training mode, targets should be passed\")\n        if self.training:\n            assert targets is not None\n            for target in targets:\n                boxes = target[\"boxes\"]\n                if isinstance(boxes, torch.Tensor):\n                    if len(boxes.shape) != 2 or boxes.shape[-1] != 4:\n                        raise ValueError(\"Expected target boxes to be a tensor\"\n                                         \"of shape [N, 4], got {:}.\".format(\n                                             boxes.shape))\n                else:\n                    raise ValueError(\"Expected target boxes to be of type \"\n                                     \"Tensor, got {:}.\".format(type(boxes)))\n\n        original_image_sizes = torch.jit.annotate(List[Tuple[int, int]], [])\n        for img in images:\n            val = img.shape[-2:]\n            assert len(val) == 2\n            original_image_sizes.append((val[0], val[1]))\n\n        images, targets = self.transform(images, targets)\n\n        # Check for degenerate boxes\n        # TODO: Move this to a function\n        if targets is not None:\n            for target_idx, target in enumerate(targets):\n                boxes = target[\"boxes\"]\n                degenerate_boxes = boxes[:, 2:] <= boxes[:, :2]\n                if degenerate_boxes.any():\n                    # print the first degenrate box\n                    bb_idx = degenerate_boxes.any(dim=1).nonzero().view(-1)[0]\n                    degen_bb: List[float] = boxes[bb_idx].tolist()\n                    raise ValueError(\"All bounding boxes should have positive height and width.\"\n                                     \" Found invaid box {} for target at index {}.\"\n                                     .format(degen_bb, target_idx))\n\n        features = self.backbone(images.tensors)\n        if isinstance(features, torch.Tensor):\n            features = OrderedDict([('0', features)])\n        proposals, proposal_losses = self.rpn(images, features, targets)\n        detections, detector_losses = self.roi_heads(features, proposals, images.image_sizes, targets)\n        detections = self.transform.postprocess(detections, images.image_sizes, original_image_sizes)\n\n        losses = {}\n        losses.update(detector_losses)\n        losses.update(proposal_losses)\n\n        if torch.jit.is_scripting():\n            if not self._has_warned:\n                warnings.warn(\"RCNN always returns a (Losses, Detections) tuple in scripting\")\n                self._has_warned = True\n            return (losses, detections)\n        else:\n            return self.eager_outputs(losses, detections)\n", "path": "torchvision/models/detection/generalized_rcnn.py"}]}