We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
NMS returns different results on CPU & CUDA
## 🐛 Bug

Hi, I noticed that results of `torchvision.ops.nms` in CPU and CUDA have different value

## To Reproduce

Steps to reproduce the behavior:

1. `docker run --runtime=nvidia -it pytorch/pytorch:1.5-cuda10.1-cudnn7-devel bash`
2. run this script :
  ```
import torch
import torchvision
import random

random.seed(0)
torch.manual_seed(0)
torch.backends.cudnn.deterministic = True

boxes_for_nms = torch.tensor([[0.3764, 0.0905, 0.6533, 0.4487],[0.3744, 0.0899, 0.6535, 0.4513],[0.3753, 0.0916, 0.6532, 0.4512]])
scores = torch.tensor([1., 1., 1.])
iou_threshold = 0.2

cpu_keep = torchvision.ops.nms(boxes_for_nms, scores, iou_threshold)
gpu_keep = torchvision.ops.nms(boxes_for_nms.to('cuda'), scores.to('cuda'), iou_threshold)

print(torch.__version__, torchvision.__version__)
print('cpu keep', cpu_keep)
print('gpu keep', gpu_keep)
print('cpu==gpu', int(cpu_keep)==int(gpu_keep))
  ```
3. output
```
1.5.0 0.6.0a0+82fd1c8
cpu keep tensor([0])
gpu keep tensor([2], device='cuda:0')
cpu==gpu False
```

## Expected behavior

`cpu==gpu True`

## Environment

```
PyTorch version: 1.5.0
Is debug build: No
CUDA used to build PyTorch: 10.1

OS: Ubuntu 18.04.3 LTS
GCC version: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
CMake version: Could not collect

Python version: 3.7
Is CUDA available: Yes
CUDA runtime version: 10.1.243
GPU models and configuration: GPU 0: GeForce GTX 1060 with Max-Q Design
Nvidia driver version: 418.56
cuDNN version: /usr/lib/x86_64-linux-gnu/libcudnn.so.7.6.5

Versions of relevant libraries:
[pip] numpy==1.18.1
[pip] torch==1.5.0
[pip] torchvision==0.6.0a0+82fd1c8
[conda] blas                      1.0                         mkl  
[conda] cudatoolkit               10.1.243             h6bb024c_0  
[conda] mkl                       2020.0                      166  
[conda] mkl-service               2.3.0            py37he904b0f_0  
[conda] mkl_fft                   1.0.15           py37ha843d7b_0  
[conda] mkl_random                1.1.0            py37hd6b4f25_0  
[conda] numpy                     1.18.1           py37h4f9e942_0  
[conda] numpy-base                1.18.1           py37hde5b4d6_1  
[conda] pytorch                   1.5.0           py3.7_cuda10.1.243_cudnn7.6.3_0    pytorch
[conda] torchvision               0.6.0                py37_cu101    pytorch
```

## Additional context

testing on pytorch 1.4.0 and torchvision 0.5.0 also yields different result, 


--- 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/ops/boxes.py`
Content:
```
1 import torch
2 from torch.jit.annotations import Tuple
3 from torch import Tensor
4 import torchvision
5 
6 
7 def nms(boxes, scores, iou_threshold):
8     # type: (Tensor, Tensor, float)
9     """
10     Performs non-maximum suppression (NMS) on the boxes according
11     to their intersection-over-union (IoU).
12 
13     NMS iteratively removes lower scoring boxes which have an
14     IoU greater than iou_threshold with another (higher scoring)
15     box.
16 
17     Parameters
18     ----------
19     boxes : Tensor[N, 4])
20         boxes to perform NMS on. They
21         are expected to be in (x1, y1, x2, y2) format
22     scores : Tensor[N]
23         scores for each one of the boxes
24     iou_threshold : float
25         discards all overlapping
26         boxes with IoU > iou_threshold
27 
28     Returns
29     -------
30     keep : Tensor
31         int64 tensor with the indices
32         of the elements that have been kept
33         by NMS, sorted in decreasing order of scores
34     """
35     return torch.ops.torchvision.nms(boxes, scores, iou_threshold)
36 
37 
38 def batched_nms(boxes, scores, idxs, iou_threshold):
39     # type: (Tensor, Tensor, Tensor, float)
40     """
41     Performs non-maximum suppression in a batched fashion.
42 
43     Each index value correspond to a category, and NMS
44     will not be applied between elements of different categories.
45 
46     Parameters
47     ----------
48     boxes : Tensor[N, 4]
49         boxes where NMS will be performed. They
50         are expected to be in (x1, y1, x2, y2) format
51     scores : Tensor[N]
52         scores for each one of the boxes
53     idxs : Tensor[N]
54         indices of the categories for each one of the boxes.
55     iou_threshold : float
56         discards all overlapping boxes
57         with IoU > iou_threshold
58 
59     Returns
60     -------
61     keep : Tensor
62         int64 tensor with the indices of
63         the elements that have been kept by NMS, sorted
64         in decreasing order of scores
65     """
66     if boxes.numel() == 0:
67         return torch.empty((0,), dtype=torch.int64, device=boxes.device)
68     # strategy: in order to perform NMS independently per class.
69     # we add an offset to all the boxes. The offset is dependent
70     # only on the class idx, and is large enough so that boxes
71     # from different classes do not overlap
72     max_coordinate = boxes.max()
73     offsets = idxs.to(boxes) * (max_coordinate + 1)
74     boxes_for_nms = boxes + offsets[:, None]
75     keep = nms(boxes_for_nms, scores, iou_threshold)
76     return keep
77 
78 
79 def remove_small_boxes(boxes, min_size):
80     # type: (Tensor, float)
81     """
82     Remove boxes which contains at least one side smaller than min_size.
83 
84     Arguments:
85         boxes (Tensor[N, 4]): boxes in (x1, y1, x2, y2) format
86         min_size (float): minimum size
87 
88     Returns:
89         keep (Tensor[K]): indices of the boxes that have both sides
90             larger than min_size
91     """
92     ws, hs = boxes[:, 2] - boxes[:, 0], boxes[:, 3] - boxes[:, 1]
93     keep = (ws >= min_size) & (hs >= min_size)
94     keep = keep.nonzero().squeeze(1)
95     return keep
96 
97 
98 def clip_boxes_to_image(boxes, size):
99     # type: (Tensor, Tuple[int, int])
100     """
101     Clip boxes so that they lie inside an image of size `size`.
102 
103     Arguments:
104         boxes (Tensor[N, 4]): boxes in (x1, y1, x2, y2) format
105         size (Tuple[height, width]): size of the image
106 
107     Returns:
108         clipped_boxes (Tensor[N, 4])
109     """
110     dim = boxes.dim()
111     boxes_x = boxes[..., 0::2]
112     boxes_y = boxes[..., 1::2]
113     height, width = size
114 
115     if torchvision._is_tracing():
116         boxes_x = torch.max(boxes_x, torch.tensor(0, dtype=boxes.dtype, device=boxes.device))
117         boxes_x = torch.min(boxes_x, torch.tensor(width, dtype=boxes.dtype, device=boxes.device))
118         boxes_y = torch.max(boxes_y, torch.tensor(0, dtype=boxes.dtype, device=boxes.device))
119         boxes_y = torch.min(boxes_y, torch.tensor(height, dtype=boxes.dtype, device=boxes.device))
120     else:
121         boxes_x = boxes_x.clamp(min=0, max=width)
122         boxes_y = boxes_y.clamp(min=0, max=height)
123 
124     clipped_boxes = torch.stack((boxes_x, boxes_y), dim=dim)
125     return clipped_boxes.reshape(boxes.shape)
126 
127 
128 def box_area(boxes):
129     """
130     Computes the area of a set of bounding boxes, which are specified by its
131     (x1, y1, x2, y2) coordinates.
132 
133     Arguments:
134         boxes (Tensor[N, 4]): boxes for which the area will be computed. They
135             are expected to be in (x1, y1, x2, y2) format
136 
137     Returns:
138         area (Tensor[N]): area for each box
139     """
140     return (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
141 
142 
143 # implementation from https://github.com/kuangliu/torchcv/blob/master/torchcv/utils/box.py
144 # with slight modifications
145 def box_iou(boxes1, boxes2):
146     """
147     Return intersection-over-union (Jaccard index) of boxes.
148 
149     Both sets of boxes are expected to be in (x1, y1, x2, y2) format.
150 
151     Arguments:
152         boxes1 (Tensor[N, 4])
153         boxes2 (Tensor[M, 4])
154 
155     Returns:
156         iou (Tensor[N, M]): the NxM matrix containing the pairwise
157             IoU values for every element in boxes1 and boxes2
158     """
159     area1 = box_area(boxes1)
160     area2 = box_area(boxes2)
161 
162     lt = torch.max(boxes1[:, None, :2], boxes2[:, :2])  # [N,M,2]
163     rb = torch.min(boxes1[:, None, 2:], boxes2[:, 2:])  # [N,M,2]
164 
165     wh = (rb - lt).clamp(min=0)  # [N,M,2]
166     inter = wh[:, :, 0] * wh[:, :, 1]  # [N,M]
167 
168     iou = inter / (area1[:, None] + area2 - inter)
169     return iou
170
```
--- 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()

```

diff --git a/torchvision/ops/boxes.py b/torchvision/ops/boxes.py
--- a/torchvision/ops/boxes.py
+++ b/torchvision/ops/boxes.py
@@ -14,6 +14,11 @@
     IoU greater than iou_threshold with another (higher scoring)
     box.
 
+    If multiple boxes have the exact same score and satisfy the IoU 
+    criterion with respect to a reference box, the selected box is 
+    not guaranteed to be the same between CPU and GPU. This is similar 
+    to the behavior of argsort in PyTorch when repeated values are present.
+
     Parameters
     ----------
     boxes : Tensor[N, 4])

{"golden_diff": "diff --git a/torchvision/ops/boxes.py b/torchvision/ops/boxes.py\n--- a/torchvision/ops/boxes.py\n+++ b/torchvision/ops/boxes.py\n@@ -14,6 +14,11 @@\n     IoU greater than iou_threshold with another (higher scoring)\n     box.\n \n+    If multiple boxes have the exact same score and satisfy the IoU \n+    criterion with respect to a reference box, the selected box is \n+    not guaranteed to be the same between CPU and GPU. This is similar \n+    to the behavior of argsort in PyTorch when repeated values are present.\n+\n     Parameters\n     ----------\n     boxes : Tensor[N, 4])\n", "issue": "NMS returns different results on CPU & CUDA\n## \ud83d\udc1b Bug\r\n\r\nHi, I noticed that results of `torchvision.ops.nms` in CPU and CUDA have different value\r\n\r\n## To Reproduce\r\n\r\nSteps to reproduce the behavior:\r\n\r\n1. `docker run --runtime=nvidia -it pytorch/pytorch:1.5-cuda10.1-cudnn7-devel bash`\r\n2. run this script :\r\n  ```\r\nimport torch\r\nimport torchvision\r\nimport random\r\n\r\nrandom.seed(0)\r\ntorch.manual_seed(0)\r\ntorch.backends.cudnn.deterministic = True\r\n\r\nboxes_for_nms = torch.tensor([[0.3764, 0.0905, 0.6533, 0.4487],[0.3744, 0.0899, 0.6535, 0.4513],[0.3753, 0.0916, 0.6532, 0.4512]])\r\nscores = torch.tensor([1., 1., 1.])\r\niou_threshold = 0.2\r\n\r\ncpu_keep = torchvision.ops.nms(boxes_for_nms, scores, iou_threshold)\r\ngpu_keep = torchvision.ops.nms(boxes_for_nms.to('cuda'), scores.to('cuda'), iou_threshold)\r\n\r\nprint(torch.__version__, torchvision.__version__)\r\nprint('cpu keep', cpu_keep)\r\nprint('gpu keep', gpu_keep)\r\nprint('cpu==gpu', int(cpu_keep)==int(gpu_keep))\r\n  ```\r\n3. output\r\n```\r\n1.5.0 0.6.0a0+82fd1c8\r\ncpu keep tensor([0])\r\ngpu keep tensor([2], device='cuda:0')\r\ncpu==gpu False\r\n```\r\n\r\n## Expected behavior\r\n\r\n`cpu==gpu True`\r\n\r\n## Environment\r\n\r\n```\r\nPyTorch version: 1.5.0\r\nIs debug build: No\r\nCUDA used to build PyTorch: 10.1\r\n\r\nOS: Ubuntu 18.04.3 LTS\r\nGCC version: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0\r\nCMake version: Could not collect\r\n\r\nPython version: 3.7\r\nIs CUDA available: Yes\r\nCUDA runtime version: 10.1.243\r\nGPU models and configuration: GPU 0: GeForce GTX 1060 with Max-Q Design\r\nNvidia driver version: 418.56\r\ncuDNN version: /usr/lib/x86_64-linux-gnu/libcudnn.so.7.6.5\r\n\r\nVersions of relevant libraries:\r\n[pip] numpy==1.18.1\r\n[pip] torch==1.5.0\r\n[pip] torchvision==0.6.0a0+82fd1c8\r\n[conda] blas                      1.0                         mkl  \r\n[conda] cudatoolkit               10.1.243             h6bb024c_0  \r\n[conda] mkl                       2020.0                      166  \r\n[conda] mkl-service               2.3.0            py37he904b0f_0  \r\n[conda] mkl_fft                   1.0.15           py37ha843d7b_0  \r\n[conda] mkl_random                1.1.0            py37hd6b4f25_0  \r\n[conda] numpy                     1.18.1           py37h4f9e942_0  \r\n[conda] numpy-base                1.18.1           py37hde5b4d6_1  \r\n[conda] pytorch                   1.5.0           py3.7_cuda10.1.243_cudnn7.6.3_0    pytorch\r\n[conda] torchvision               0.6.0                py37_cu101    pytorch\r\n```\r\n\r\n## Additional context\r\n\r\ntesting on pytorch 1.4.0 and torchvision 0.5.0 also yields different result, \r\n\n", "before_files": [{"content": "import torch\nfrom torch.jit.annotations import Tuple\nfrom torch import Tensor\nimport torchvision\n\n\ndef nms(boxes, scores, iou_threshold):\n    # type: (Tensor, Tensor, float)\n    \"\"\"\n    Performs non-maximum suppression (NMS) on the boxes according\n    to their intersection-over-union (IoU).\n\n    NMS iteratively removes lower scoring boxes which have an\n    IoU greater than iou_threshold with another (higher scoring)\n    box.\n\n    Parameters\n    ----------\n    boxes : Tensor[N, 4])\n        boxes to perform NMS on. They\n        are expected to be in (x1, y1, x2, y2) format\n    scores : Tensor[N]\n        scores for each one of the boxes\n    iou_threshold : float\n        discards all overlapping\n        boxes with IoU > iou_threshold\n\n    Returns\n    -------\n    keep : Tensor\n        int64 tensor with the indices\n        of the elements that have been kept\n        by NMS, sorted in decreasing order of scores\n    \"\"\"\n    return torch.ops.torchvision.nms(boxes, scores, iou_threshold)\n\n\ndef batched_nms(boxes, scores, idxs, iou_threshold):\n    # type: (Tensor, Tensor, Tensor, float)\n    \"\"\"\n    Performs non-maximum suppression in a batched fashion.\n\n    Each index value correspond to a category, and NMS\n    will not be applied between elements of different categories.\n\n    Parameters\n    ----------\n    boxes : Tensor[N, 4]\n        boxes where NMS will be performed. They\n        are expected to be in (x1, y1, x2, y2) format\n    scores : Tensor[N]\n        scores for each one of the boxes\n    idxs : Tensor[N]\n        indices of the categories for each one of the boxes.\n    iou_threshold : float\n        discards all overlapping boxes\n        with IoU > iou_threshold\n\n    Returns\n    -------\n    keep : Tensor\n        int64 tensor with the indices of\n        the elements that have been kept by NMS, sorted\n        in decreasing order of scores\n    \"\"\"\n    if boxes.numel() == 0:\n        return torch.empty((0,), dtype=torch.int64, device=boxes.device)\n    # strategy: in order to perform NMS independently per class.\n    # we add an offset to all the boxes. The offset is dependent\n    # only on the class idx, and is large enough so that boxes\n    # from different classes do not overlap\n    max_coordinate = boxes.max()\n    offsets = idxs.to(boxes) * (max_coordinate + 1)\n    boxes_for_nms = boxes + offsets[:, None]\n    keep = nms(boxes_for_nms, scores, iou_threshold)\n    return keep\n\n\ndef remove_small_boxes(boxes, min_size):\n    # type: (Tensor, float)\n    \"\"\"\n    Remove boxes which contains at least one side smaller than min_size.\n\n    Arguments:\n        boxes (Tensor[N, 4]): boxes in (x1, y1, x2, y2) format\n        min_size (float): minimum size\n\n    Returns:\n        keep (Tensor[K]): indices of the boxes that have both sides\n            larger than min_size\n    \"\"\"\n    ws, hs = boxes[:, 2] - boxes[:, 0], boxes[:, 3] - boxes[:, 1]\n    keep = (ws >= min_size) & (hs >= min_size)\n    keep = keep.nonzero().squeeze(1)\n    return keep\n\n\ndef clip_boxes_to_image(boxes, size):\n    # type: (Tensor, Tuple[int, int])\n    \"\"\"\n    Clip boxes so that they lie inside an image of size `size`.\n\n    Arguments:\n        boxes (Tensor[N, 4]): boxes in (x1, y1, x2, y2) format\n        size (Tuple[height, width]): size of the image\n\n    Returns:\n        clipped_boxes (Tensor[N, 4])\n    \"\"\"\n    dim = boxes.dim()\n    boxes_x = boxes[..., 0::2]\n    boxes_y = boxes[..., 1::2]\n    height, width = size\n\n    if torchvision._is_tracing():\n        boxes_x = torch.max(boxes_x, torch.tensor(0, dtype=boxes.dtype, device=boxes.device))\n        boxes_x = torch.min(boxes_x, torch.tensor(width, dtype=boxes.dtype, device=boxes.device))\n        boxes_y = torch.max(boxes_y, torch.tensor(0, dtype=boxes.dtype, device=boxes.device))\n        boxes_y = torch.min(boxes_y, torch.tensor(height, dtype=boxes.dtype, device=boxes.device))\n    else:\n        boxes_x = boxes_x.clamp(min=0, max=width)\n        boxes_y = boxes_y.clamp(min=0, max=height)\n\n    clipped_boxes = torch.stack((boxes_x, boxes_y), dim=dim)\n    return clipped_boxes.reshape(boxes.shape)\n\n\ndef box_area(boxes):\n    \"\"\"\n    Computes the area of a set of bounding boxes, which are specified by its\n    (x1, y1, x2, y2) coordinates.\n\n    Arguments:\n        boxes (Tensor[N, 4]): boxes for which the area will be computed. They\n            are expected to be in (x1, y1, x2, y2) format\n\n    Returns:\n        area (Tensor[N]): area for each box\n    \"\"\"\n    return (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])\n\n\n# implementation from https://github.com/kuangliu/torchcv/blob/master/torchcv/utils/box.py\n# with slight modifications\ndef box_iou(boxes1, boxes2):\n    \"\"\"\n    Return intersection-over-union (Jaccard index) of boxes.\n\n    Both sets of boxes are expected to be in (x1, y1, x2, y2) format.\n\n    Arguments:\n        boxes1 (Tensor[N, 4])\n        boxes2 (Tensor[M, 4])\n\n    Returns:\n        iou (Tensor[N, M]): the NxM matrix containing the pairwise\n            IoU values for every element in boxes1 and boxes2\n    \"\"\"\n    area1 = box_area(boxes1)\n    area2 = box_area(boxes2)\n\n    lt = torch.max(boxes1[:, None, :2], boxes2[:, :2])  # [N,M,2]\n    rb = torch.min(boxes1[:, None, 2:], boxes2[:, 2:])  # [N,M,2]\n\n    wh = (rb - lt).clamp(min=0)  # [N,M,2]\n    inter = wh[:, :, 0] * wh[:, :, 1]  # [N,M]\n\n    iou = inter / (area1[:, None] + area2 - inter)\n    return iou\n", "path": "torchvision/ops/boxes.py"}], "after_files": [{"content": "import torch\nfrom torch.jit.annotations import Tuple\nfrom torch import Tensor\nimport torchvision\n\n\ndef nms(boxes, scores, iou_threshold):\n    # type: (Tensor, Tensor, float)\n    \"\"\"\n    Performs non-maximum suppression (NMS) on the boxes according\n    to their intersection-over-union (IoU).\n\n    NMS iteratively removes lower scoring boxes which have an\n    IoU greater than iou_threshold with another (higher scoring)\n    box.\n\n    If multiple boxes have the exact same score and satisfy the IoU \n    criterion with respect to a reference box, the selected box is \n    not guaranteed to be the same between CPU and GPU. This is similar \n    to the behavior of argsort in PyTorch when repeated values are present.\n\n    Parameters\n    ----------\n    boxes : Tensor[N, 4])\n        boxes to perform NMS on. They\n        are expected to be in (x1, y1, x2, y2) format\n    scores : Tensor[N]\n        scores for each one of the boxes\n    iou_threshold : float\n        discards all overlapping\n        boxes with IoU > iou_threshold\n\n    Returns\n    -------\n    keep : Tensor\n        int64 tensor with the indices\n        of the elements that have been kept\n        by NMS, sorted in decreasing order of scores\n    \"\"\"\n    return torch.ops.torchvision.nms(boxes, scores, iou_threshold)\n\n\ndef batched_nms(boxes, scores, idxs, iou_threshold):\n    # type: (Tensor, Tensor, Tensor, float)\n    \"\"\"\n    Performs non-maximum suppression in a batched fashion.\n\n    Each index value correspond to a category, and NMS\n    will not be applied between elements of different categories.\n\n    Parameters\n    ----------\n    boxes : Tensor[N, 4]\n        boxes where NMS will be performed. They\n        are expected to be in (x1, y1, x2, y2) format\n    scores : Tensor[N]\n        scores for each one of the boxes\n    idxs : Tensor[N]\n        indices of the categories for each one of the boxes.\n    iou_threshold : float\n        discards all overlapping boxes\n        with IoU > iou_threshold\n\n    Returns\n    -------\n    keep : Tensor\n        int64 tensor with the indices of\n        the elements that have been kept by NMS, sorted\n        in decreasing order of scores\n    \"\"\"\n    if boxes.numel() == 0:\n        return torch.empty((0,), dtype=torch.int64, device=boxes.device)\n    # strategy: in order to perform NMS independently per class.\n    # we add an offset to all the boxes. The offset is dependent\n    # only on the class idx, and is large enough so that boxes\n    # from different classes do not overlap\n    max_coordinate = boxes.max()\n    offsets = idxs.to(boxes) * (max_coordinate + 1)\n    boxes_for_nms = boxes + offsets[:, None]\n    keep = nms(boxes_for_nms, scores, iou_threshold)\n    return keep\n\n\ndef remove_small_boxes(boxes, min_size):\n    # type: (Tensor, float)\n    \"\"\"\n    Remove boxes which contains at least one side smaller than min_size.\n\n    Arguments:\n        boxes (Tensor[N, 4]): boxes in (x1, y1, x2, y2) format\n        min_size (float): minimum size\n\n    Returns:\n        keep (Tensor[K]): indices of the boxes that have both sides\n            larger than min_size\n    \"\"\"\n    ws, hs = boxes[:, 2] - boxes[:, 0], boxes[:, 3] - boxes[:, 1]\n    keep = (ws >= min_size) & (hs >= min_size)\n    keep = keep.nonzero().squeeze(1)\n    return keep\n\n\ndef clip_boxes_to_image(boxes, size):\n    # type: (Tensor, Tuple[int, int])\n    \"\"\"\n    Clip boxes so that they lie inside an image of size `size`.\n\n    Arguments:\n        boxes (Tensor[N, 4]): boxes in (x1, y1, x2, y2) format\n        size (Tuple[height, width]): size of the image\n\n    Returns:\n        clipped_boxes (Tensor[N, 4])\n    \"\"\"\n    dim = boxes.dim()\n    boxes_x = boxes[..., 0::2]\n    boxes_y = boxes[..., 1::2]\n    height, width = size\n\n    if torchvision._is_tracing():\n        boxes_x = torch.max(boxes_x, torch.tensor(0, dtype=boxes.dtype, device=boxes.device))\n        boxes_x = torch.min(boxes_x, torch.tensor(width, dtype=boxes.dtype, device=boxes.device))\n        boxes_y = torch.max(boxes_y, torch.tensor(0, dtype=boxes.dtype, device=boxes.device))\n        boxes_y = torch.min(boxes_y, torch.tensor(height, dtype=boxes.dtype, device=boxes.device))\n    else:\n        boxes_x = boxes_x.clamp(min=0, max=width)\n        boxes_y = boxes_y.clamp(min=0, max=height)\n\n    clipped_boxes = torch.stack((boxes_x, boxes_y), dim=dim)\n    return clipped_boxes.reshape(boxes.shape)\n\n\ndef box_area(boxes):\n    \"\"\"\n    Computes the area of a set of bounding boxes, which are specified by its\n    (x1, y1, x2, y2) coordinates.\n\n    Arguments:\n        boxes (Tensor[N, 4]): boxes for which the area will be computed. They\n            are expected to be in (x1, y1, x2, y2) format\n\n    Returns:\n        area (Tensor[N]): area for each box\n    \"\"\"\n    return (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])\n\n\n# implementation from https://github.com/kuangliu/torchcv/blob/master/torchcv/utils/box.py\n# with slight modifications\ndef box_iou(boxes1, boxes2):\n    \"\"\"\n    Return intersection-over-union (Jaccard index) of boxes.\n\n    Both sets of boxes are expected to be in (x1, y1, x2, y2) format.\n\n    Arguments:\n        boxes1 (Tensor[N, 4])\n        boxes2 (Tensor[M, 4])\n\n    Returns:\n        iou (Tensor[N, M]): the NxM matrix containing the pairwise\n            IoU values for every element in boxes1 and boxes2\n    \"\"\"\n    area1 = box_area(boxes1)\n    area2 = box_area(boxes2)\n\n    lt = torch.max(boxes1[:, None, :2], boxes2[:, :2])  # [N,M,2]\n    rb = torch.min(boxes1[:, None, 2:], boxes2[:, 2:])  # [N,M,2]\n\n    wh = (rb - lt).clamp(min=0)  # [N,M,2]\n    inter = wh[:, :, 0] * wh[:, :, 1]  # [N,M]\n\n    iou = inter / (area1[:, None] + area2 - inter)\n    return iou\n", "path": "torchvision/ops/boxes.py"}]}