We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Replace assert with ValueError in AnchorGenerator
## 🐛 Bug

I think with the Retina Net PR, there was an update to anchor utils.
My old code still works fine on torchvision 0.7 and pytorch 1.6. But on upgrading to 0.8 it doesn't.
I am not sure if this was BC Breaking change.

## To Reproduce

Steps to reproduce the behavior:

1. Following is the code block to create FRCNN
```
import torchvision
import torchvision.transforms as T
from torchvision.models.detection.rpn import AnchorGenerator
from torchvision.models.detection import FasterRCNN

device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')

def create_model(num_classes, min_size=300, max_size=500, backbone="mobile_net"):

    model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
    in_features = model.roi_heads.box_predictor.cls_score.in_features

    ft_mean = [0.485, 0.456, 0.406]
    ft_std = [0.229, 0.224, 0.225]

    mobile_net = torchvision.models.mobilenet_v2(pretrained=True)

    ft_backbone = mobile_net.features
    ft_backbone.out_channels = 1280

    ft_model = FasterRCNN(backbone=ft_backbone,
                        num_classes=num_classes, 
                        image_mean=ft_mean, 
                        image_std=ft_std,)
```
2. When I do These three function sequeantially
```

def load_model():
    detector = model.create_model(num_classes=config.NUM_CLASSES)
    detector.load_state_dict(torch.load(config.MODEL_SAVE_PATH, map_location=device))
    detector.eval()
    detector.to(device)
    return detector


def load_image_tensor(image_path, device):
    image_tensor = T.ToTensor() (Image.open(image_path))
    input_images = [image_tensor.to(device)]
    return input_images


def get_prediction(detector, images):
    with torch.no_grad():
        prediction = detector(images)
        return prediction

```

I get an assertion error from [this ](https://github.com/pytorch/vision/blob/master/torchvision/models/detection/anchor_utils.py#L103)line

## Expected behavior

It should work fine, I think an upgrade to torchvision should not break Anchor utils for FRCNN.

## Environment


 - PyTorch / torchvision Version (e.g., 1.0 / 0.4.0): PT -> 1.7  TV-> 0.8.1
 - OS (e.g., Linux): Windows
 - How you installed PyTorch / torchvision (`conda`, `pip`, source): conda
 - Build command you used (if compiling from source):
 - Python version: 3.7
 - CUDA/cuDNN version: NA
 - GPU models and configuration: NA

## Additional context

1. Maybe something has changed and I'm not aware of
2. Can we remove these assertions and raise `ValueError` with suitable messages ? I cannot debug at all with `assert` errors.
3. Slightly associated with #2955 

--- 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/anchor_utils.py`
Content:
```
1 # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2 import torch
3 from torch import nn
4 
5 from torch.jit.annotations import List, Optional, Dict
6 from .image_list import ImageList
7 
8 
9 class AnchorGenerator(nn.Module):
10     """
11     Module that generates anchors for a set of feature maps and
12     image sizes.
13 
14     The module support computing anchors at multiple sizes and aspect ratios
15     per feature map. This module assumes aspect ratio = height / width for
16     each anchor.
17 
18     sizes and aspect_ratios should have the same number of elements, and it should
19     correspond to the number of feature maps.
20 
21     sizes[i] and aspect_ratios[i] can have an arbitrary number of elements,
22     and AnchorGenerator will output a set of sizes[i] * aspect_ratios[i] anchors
23     per spatial location for feature map i.
24 
25     Arguments:
26         sizes (Tuple[Tuple[int]]):
27         aspect_ratios (Tuple[Tuple[float]]):
28     """
29 
30     __annotations__ = {
31         "cell_anchors": Optional[List[torch.Tensor]],
32         "_cache": Dict[str, List[torch.Tensor]]
33     }
34 
35     def __init__(
36         self,
37         sizes=((128, 256, 512),),
38         aspect_ratios=((0.5, 1.0, 2.0),),
39     ):
40         super(AnchorGenerator, self).__init__()
41 
42         if not isinstance(sizes[0], (list, tuple)):
43             # TODO change this
44             sizes = tuple((s,) for s in sizes)
45         if not isinstance(aspect_ratios[0], (list, tuple)):
46             aspect_ratios = (aspect_ratios,) * len(sizes)
47 
48         assert len(sizes) == len(aspect_ratios)
49 
50         self.sizes = sizes
51         self.aspect_ratios = aspect_ratios
52         self.cell_anchors = None
53         self._cache = {}
54 
55     # TODO: https://github.com/pytorch/pytorch/issues/26792
56     # For every (aspect_ratios, scales) combination, output a zero-centered anchor with those values.
57     # (scales, aspect_ratios) are usually an element of zip(self.scales, self.aspect_ratios)
58     # This method assumes aspect ratio = height / width for an anchor.
59     def generate_anchors(self, scales, aspect_ratios, dtype=torch.float32, device="cpu"):
60         # type: (List[int], List[float], int, Device) -> Tensor  # noqa: F821
61         scales = torch.as_tensor(scales, dtype=dtype, device=device)
62         aspect_ratios = torch.as_tensor(aspect_ratios, dtype=dtype, device=device)
63         h_ratios = torch.sqrt(aspect_ratios)
64         w_ratios = 1 / h_ratios
65 
66         ws = (w_ratios[:, None] * scales[None, :]).view(-1)
67         hs = (h_ratios[:, None] * scales[None, :]).view(-1)
68 
69         base_anchors = torch.stack([-ws, -hs, ws, hs], dim=1) / 2
70         return base_anchors.round()
71 
72     def set_cell_anchors(self, dtype, device):
73         # type: (int, Device) -> None  # noqa: F821
74         if self.cell_anchors is not None:
75             cell_anchors = self.cell_anchors
76             assert cell_anchors is not None
77             # suppose that all anchors have the same device
78             # which is a valid assumption in the current state of the codebase
79             if cell_anchors[0].device == device:
80                 return
81 
82         cell_anchors = [
83             self.generate_anchors(
84                 sizes,
85                 aspect_ratios,
86                 dtype,
87                 device
88             )
89             for sizes, aspect_ratios in zip(self.sizes, self.aspect_ratios)
90         ]
91         self.cell_anchors = cell_anchors
92 
93     def num_anchors_per_location(self):
94         return [len(s) * len(a) for s, a in zip(self.sizes, self.aspect_ratios)]
95 
96     # For every combination of (a, (g, s), i) in (self.cell_anchors, zip(grid_sizes, strides), 0:2),
97     # output g[i] anchors that are s[i] distance apart in direction i, with the same dimensions as a.
98     def grid_anchors(self, grid_sizes, strides):
99         # type: (List[List[int]], List[List[Tensor]]) -> List[Tensor]
100         anchors = []
101         cell_anchors = self.cell_anchors
102         assert cell_anchors is not None
103         assert len(grid_sizes) == len(strides) == len(cell_anchors)
104 
105         for size, stride, base_anchors in zip(
106             grid_sizes, strides, cell_anchors
107         ):
108             grid_height, grid_width = size
109             stride_height, stride_width = stride
110             device = base_anchors.device
111 
112             # For output anchor, compute [x_center, y_center, x_center, y_center]
113             shifts_x = torch.arange(
114                 0, grid_width, dtype=torch.float32, device=device
115             ) * stride_width
116             shifts_y = torch.arange(
117                 0, grid_height, dtype=torch.float32, device=device
118             ) * stride_height
119             shift_y, shift_x = torch.meshgrid(shifts_y, shifts_x)
120             shift_x = shift_x.reshape(-1)
121             shift_y = shift_y.reshape(-1)
122             shifts = torch.stack((shift_x, shift_y, shift_x, shift_y), dim=1)
123 
124             # For every (base anchor, output anchor) pair,
125             # offset each zero-centered base anchor by the center of the output anchor.
126             anchors.append(
127                 (shifts.view(-1, 1, 4) + base_anchors.view(1, -1, 4)).reshape(-1, 4)
128             )
129 
130         return anchors
131 
132     def cached_grid_anchors(self, grid_sizes, strides):
133         # type: (List[List[int]], List[List[Tensor]]) -> List[Tensor]
134         key = str(grid_sizes) + str(strides)
135         if key in self._cache:
136             return self._cache[key]
137         anchors = self.grid_anchors(grid_sizes, strides)
138         self._cache[key] = anchors
139         return anchors
140 
141     def forward(self, image_list, feature_maps):
142         # type: (ImageList, List[Tensor]) -> List[Tensor]
143         grid_sizes = list([feature_map.shape[-2:] for feature_map in feature_maps])
144         image_size = image_list.tensors.shape[-2:]
145         dtype, device = feature_maps[0].dtype, feature_maps[0].device
146         strides = [[torch.tensor(image_size[0] // g[0], dtype=torch.int64, device=device),
147                     torch.tensor(image_size[1] // g[1], dtype=torch.int64, device=device)] for g in grid_sizes]
148         self.set_cell_anchors(dtype, device)
149         anchors_over_all_feature_maps = self.cached_grid_anchors(grid_sizes, strides)
150         anchors = torch.jit.annotate(List[List[torch.Tensor]], [])
151         for i, (image_height, image_width) in enumerate(image_list.image_sizes):
152             anchors_in_image = []
153             for anchors_per_feature_map in anchors_over_all_feature_maps:
154                 anchors_in_image.append(anchors_per_feature_map)
155             anchors.append(anchors_in_image)
156         anchors = [torch.cat(anchors_per_image) for anchors_per_image in anchors]
157         # Clear the cache in case that memory leaks.
158         self._cache.clear()
159         return anchors
160
```
--- 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/models/detection/anchor_utils.py b/torchvision/models/detection/anchor_utils.py
--- a/torchvision/models/detection/anchor_utils.py
+++ b/torchvision/models/detection/anchor_utils.py
@@ -100,7 +100,12 @@
         anchors = []
         cell_anchors = self.cell_anchors
         assert cell_anchors is not None
-        assert len(grid_sizes) == len(strides) == len(cell_anchors)
+
+        if not (len(grid_sizes) == len(strides) == len(cell_anchors)):
+            raise ValueError("Achors should be Tuple[Tuple[int]] because each feature "
+                             "map could potentially have different sizes and aspect ratios. "
+                             "There needs to be a match between the number of "
+                             "feature maps passed and the number of sizes / aspect ratios specified.")
 
         for size, stride, base_anchors in zip(
             grid_sizes, strides, cell_anchors

{"golden_diff": "diff --git a/torchvision/models/detection/anchor_utils.py b/torchvision/models/detection/anchor_utils.py\n--- a/torchvision/models/detection/anchor_utils.py\n+++ b/torchvision/models/detection/anchor_utils.py\n@@ -100,7 +100,12 @@\n         anchors = []\n         cell_anchors = self.cell_anchors\n         assert cell_anchors is not None\n-        assert len(grid_sizes) == len(strides) == len(cell_anchors)\n+\n+        if not (len(grid_sizes) == len(strides) == len(cell_anchors)):\n+            raise ValueError(\"Achors should be Tuple[Tuple[int]] because each feature \"\n+                             \"map could potentially have different sizes and aspect ratios. \"\n+                             \"There needs to be a match between the number of \"\n+                             \"feature maps passed and the number of sizes / aspect ratios specified.\")\n \n         for size, stride, base_anchors in zip(\n             grid_sizes, strides, cell_anchors\n", "issue": "Replace assert with ValueError in AnchorGenerator\n## \ud83d\udc1b Bug\r\n\r\nI think with the Retina Net PR, there was an update to anchor utils.\r\nMy old code still works fine on torchvision 0.7 and pytorch 1.6. But on upgrading to 0.8 it doesn't.\r\nI am not sure if this was BC Breaking change.\r\n\r\n## To Reproduce\r\n\r\nSteps to reproduce the behavior:\r\n\r\n1. Following is the code block to create FRCNN\r\n```\r\nimport torchvision\r\nimport torchvision.transforms as T\r\nfrom torchvision.models.detection.rpn import AnchorGenerator\r\nfrom torchvision.models.detection import FasterRCNN\r\n\r\ndevice = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\r\n\r\ndef create_model(num_classes, min_size=300, max_size=500, backbone=\"mobile_net\"):\r\n\r\n    model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)\r\n    in_features = model.roi_heads.box_predictor.cls_score.in_features\r\n\r\n    ft_mean = [0.485, 0.456, 0.406]\r\n    ft_std = [0.229, 0.224, 0.225]\r\n\r\n    mobile_net = torchvision.models.mobilenet_v2(pretrained=True)\r\n\r\n    ft_backbone = mobile_net.features\r\n    ft_backbone.out_channels = 1280\r\n\r\n    ft_model = FasterRCNN(backbone=ft_backbone,\r\n                        num_classes=num_classes, \r\n                        image_mean=ft_mean, \r\n                        image_std=ft_std,)\r\n```\r\n2. When I do These three function sequeantially\r\n```\r\n\r\ndef load_model():\r\n    detector = model.create_model(num_classes=config.NUM_CLASSES)\r\n    detector.load_state_dict(torch.load(config.MODEL_SAVE_PATH, map_location=device))\r\n    detector.eval()\r\n    detector.to(device)\r\n    return detector\r\n\r\n\r\ndef load_image_tensor(image_path, device):\r\n    image_tensor = T.ToTensor() (Image.open(image_path))\r\n    input_images = [image_tensor.to(device)]\r\n    return input_images\r\n\r\n\r\ndef get_prediction(detector, images):\r\n    with torch.no_grad():\r\n        prediction = detector(images)\r\n        return prediction\r\n\r\n```\r\n\r\nI get an assertion error from [this ](https://github.com/pytorch/vision/blob/master/torchvision/models/detection/anchor_utils.py#L103)line\r\n\r\n## Expected behavior\r\n\r\nIt should work fine, I think an upgrade to torchvision should not break Anchor utils for FRCNN.\r\n\r\n## Environment\r\n\r\n\r\n - PyTorch / torchvision Version (e.g., 1.0 / 0.4.0): PT -> 1.7  TV-> 0.8.1\r\n - OS (e.g., Linux): Windows\r\n - How you installed PyTorch / torchvision (`conda`, `pip`, source): conda\r\n - Build command you used (if compiling from source):\r\n - Python version: 3.7\r\n - CUDA/cuDNN version: NA\r\n - GPU models and configuration: NA\r\n\r\n## Additional context\r\n\r\n1. Maybe something has changed and I'm not aware of\r\n2. Can we remove these assertions and raise `ValueError` with suitable messages ? I cannot debug at all with `assert` errors.\r\n3. Slightly associated with #2955 \n", "before_files": [{"content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\nimport torch\nfrom torch import nn\n\nfrom torch.jit.annotations import List, Optional, Dict\nfrom .image_list import ImageList\n\n\nclass AnchorGenerator(nn.Module):\n    \"\"\"\n    Module that generates anchors for a set of feature maps and\n    image sizes.\n\n    The module support computing anchors at multiple sizes and aspect ratios\n    per feature map. This module assumes aspect ratio = height / width for\n    each anchor.\n\n    sizes and aspect_ratios should have the same number of elements, and it should\n    correspond to the number of feature maps.\n\n    sizes[i] and aspect_ratios[i] can have an arbitrary number of elements,\n    and AnchorGenerator will output a set of sizes[i] * aspect_ratios[i] anchors\n    per spatial location for feature map i.\n\n    Arguments:\n        sizes (Tuple[Tuple[int]]):\n        aspect_ratios (Tuple[Tuple[float]]):\n    \"\"\"\n\n    __annotations__ = {\n        \"cell_anchors\": Optional[List[torch.Tensor]],\n        \"_cache\": Dict[str, List[torch.Tensor]]\n    }\n\n    def __init__(\n        self,\n        sizes=((128, 256, 512),),\n        aspect_ratios=((0.5, 1.0, 2.0),),\n    ):\n        super(AnchorGenerator, self).__init__()\n\n        if not isinstance(sizes[0], (list, tuple)):\n            # TODO change this\n            sizes = tuple((s,) for s in sizes)\n        if not isinstance(aspect_ratios[0], (list, tuple)):\n            aspect_ratios = (aspect_ratios,) * len(sizes)\n\n        assert len(sizes) == len(aspect_ratios)\n\n        self.sizes = sizes\n        self.aspect_ratios = aspect_ratios\n        self.cell_anchors = None\n        self._cache = {}\n\n    # TODO: https://github.com/pytorch/pytorch/issues/26792\n    # For every (aspect_ratios, scales) combination, output a zero-centered anchor with those values.\n    # (scales, aspect_ratios) are usually an element of zip(self.scales, self.aspect_ratios)\n    # This method assumes aspect ratio = height / width for an anchor.\n    def generate_anchors(self, scales, aspect_ratios, dtype=torch.float32, device=\"cpu\"):\n        # type: (List[int], List[float], int, Device) -> Tensor  # noqa: F821\n        scales = torch.as_tensor(scales, dtype=dtype, device=device)\n        aspect_ratios = torch.as_tensor(aspect_ratios, dtype=dtype, device=device)\n        h_ratios = torch.sqrt(aspect_ratios)\n        w_ratios = 1 / h_ratios\n\n        ws = (w_ratios[:, None] * scales[None, :]).view(-1)\n        hs = (h_ratios[:, None] * scales[None, :]).view(-1)\n\n        base_anchors = torch.stack([-ws, -hs, ws, hs], dim=1) / 2\n        return base_anchors.round()\n\n    def set_cell_anchors(self, dtype, device):\n        # type: (int, Device) -> None  # noqa: F821\n        if self.cell_anchors is not None:\n            cell_anchors = self.cell_anchors\n            assert cell_anchors is not None\n            # suppose that all anchors have the same device\n            # which is a valid assumption in the current state of the codebase\n            if cell_anchors[0].device == device:\n                return\n\n        cell_anchors = [\n            self.generate_anchors(\n                sizes,\n                aspect_ratios,\n                dtype,\n                device\n            )\n            for sizes, aspect_ratios in zip(self.sizes, self.aspect_ratios)\n        ]\n        self.cell_anchors = cell_anchors\n\n    def num_anchors_per_location(self):\n        return [len(s) * len(a) for s, a in zip(self.sizes, self.aspect_ratios)]\n\n    # For every combination of (a, (g, s), i) in (self.cell_anchors, zip(grid_sizes, strides), 0:2),\n    # output g[i] anchors that are s[i] distance apart in direction i, with the same dimensions as a.\n    def grid_anchors(self, grid_sizes, strides):\n        # type: (List[List[int]], List[List[Tensor]]) -> List[Tensor]\n        anchors = []\n        cell_anchors = self.cell_anchors\n        assert cell_anchors is not None\n        assert len(grid_sizes) == len(strides) == len(cell_anchors)\n\n        for size, stride, base_anchors in zip(\n            grid_sizes, strides, cell_anchors\n        ):\n            grid_height, grid_width = size\n            stride_height, stride_width = stride\n            device = base_anchors.device\n\n            # For output anchor, compute [x_center, y_center, x_center, y_center]\n            shifts_x = torch.arange(\n                0, grid_width, dtype=torch.float32, device=device\n            ) * stride_width\n            shifts_y = torch.arange(\n                0, grid_height, dtype=torch.float32, device=device\n            ) * stride_height\n            shift_y, shift_x = torch.meshgrid(shifts_y, shifts_x)\n            shift_x = shift_x.reshape(-1)\n            shift_y = shift_y.reshape(-1)\n            shifts = torch.stack((shift_x, shift_y, shift_x, shift_y), dim=1)\n\n            # For every (base anchor, output anchor) pair,\n            # offset each zero-centered base anchor by the center of the output anchor.\n            anchors.append(\n                (shifts.view(-1, 1, 4) + base_anchors.view(1, -1, 4)).reshape(-1, 4)\n            )\n\n        return anchors\n\n    def cached_grid_anchors(self, grid_sizes, strides):\n        # type: (List[List[int]], List[List[Tensor]]) -> List[Tensor]\n        key = str(grid_sizes) + str(strides)\n        if key in self._cache:\n            return self._cache[key]\n        anchors = self.grid_anchors(grid_sizes, strides)\n        self._cache[key] = anchors\n        return anchors\n\n    def forward(self, image_list, feature_maps):\n        # type: (ImageList, List[Tensor]) -> List[Tensor]\n        grid_sizes = list([feature_map.shape[-2:] for feature_map in feature_maps])\n        image_size = image_list.tensors.shape[-2:]\n        dtype, device = feature_maps[0].dtype, feature_maps[0].device\n        strides = [[torch.tensor(image_size[0] // g[0], dtype=torch.int64, device=device),\n                    torch.tensor(image_size[1] // g[1], dtype=torch.int64, device=device)] for g in grid_sizes]\n        self.set_cell_anchors(dtype, device)\n        anchors_over_all_feature_maps = self.cached_grid_anchors(grid_sizes, strides)\n        anchors = torch.jit.annotate(List[List[torch.Tensor]], [])\n        for i, (image_height, image_width) in enumerate(image_list.image_sizes):\n            anchors_in_image = []\n            for anchors_per_feature_map in anchors_over_all_feature_maps:\n                anchors_in_image.append(anchors_per_feature_map)\n            anchors.append(anchors_in_image)\n        anchors = [torch.cat(anchors_per_image) for anchors_per_image in anchors]\n        # Clear the cache in case that memory leaks.\n        self._cache.clear()\n        return anchors\n", "path": "torchvision/models/detection/anchor_utils.py"}], "after_files": [{"content": "# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\nimport torch\nfrom torch import nn\n\nfrom torch.jit.annotations import List, Optional, Dict\nfrom .image_list import ImageList\n\n\nclass AnchorGenerator(nn.Module):\n    \"\"\"\n    Module that generates anchors for a set of feature maps and\n    image sizes.\n\n    The module support computing anchors at multiple sizes and aspect ratios\n    per feature map. This module assumes aspect ratio = height / width for\n    each anchor.\n\n    sizes and aspect_ratios should have the same number of elements, and it should\n    correspond to the number of feature maps.\n\n    sizes[i] and aspect_ratios[i] can have an arbitrary number of elements,\n    and AnchorGenerator will output a set of sizes[i] * aspect_ratios[i] anchors\n    per spatial location for feature map i.\n\n    Arguments:\n        sizes (Tuple[Tuple[int]]):\n        aspect_ratios (Tuple[Tuple[float]]):\n    \"\"\"\n\n    __annotations__ = {\n        \"cell_anchors\": Optional[List[torch.Tensor]],\n        \"_cache\": Dict[str, List[torch.Tensor]]\n    }\n\n    def __init__(\n        self,\n        sizes=((128, 256, 512),),\n        aspect_ratios=((0.5, 1.0, 2.0),),\n    ):\n        super(AnchorGenerator, self).__init__()\n\n        if not isinstance(sizes[0], (list, tuple)):\n            # TODO change this\n            sizes = tuple((s,) for s in sizes)\n        if not isinstance(aspect_ratios[0], (list, tuple)):\n            aspect_ratios = (aspect_ratios,) * len(sizes)\n\n        assert len(sizes) == len(aspect_ratios)\n\n        self.sizes = sizes\n        self.aspect_ratios = aspect_ratios\n        self.cell_anchors = None\n        self._cache = {}\n\n    # TODO: https://github.com/pytorch/pytorch/issues/26792\n    # For every (aspect_ratios, scales) combination, output a zero-centered anchor with those values.\n    # (scales, aspect_ratios) are usually an element of zip(self.scales, self.aspect_ratios)\n    # This method assumes aspect ratio = height / width for an anchor.\n    def generate_anchors(self, scales, aspect_ratios, dtype=torch.float32, device=\"cpu\"):\n        # type: (List[int], List[float], int, Device) -> Tensor  # noqa: F821\n        scales = torch.as_tensor(scales, dtype=dtype, device=device)\n        aspect_ratios = torch.as_tensor(aspect_ratios, dtype=dtype, device=device)\n        h_ratios = torch.sqrt(aspect_ratios)\n        w_ratios = 1 / h_ratios\n\n        ws = (w_ratios[:, None] * scales[None, :]).view(-1)\n        hs = (h_ratios[:, None] * scales[None, :]).view(-1)\n\n        base_anchors = torch.stack([-ws, -hs, ws, hs], dim=1) / 2\n        return base_anchors.round()\n\n    def set_cell_anchors(self, dtype, device):\n        # type: (int, Device) -> None  # noqa: F821\n        if self.cell_anchors is not None:\n            cell_anchors = self.cell_anchors\n            assert cell_anchors is not None\n            # suppose that all anchors have the same device\n            # which is a valid assumption in the current state of the codebase\n            if cell_anchors[0].device == device:\n                return\n\n        cell_anchors = [\n            self.generate_anchors(\n                sizes,\n                aspect_ratios,\n                dtype,\n                device\n            )\n            for sizes, aspect_ratios in zip(self.sizes, self.aspect_ratios)\n        ]\n        self.cell_anchors = cell_anchors\n\n    def num_anchors_per_location(self):\n        return [len(s) * len(a) for s, a in zip(self.sizes, self.aspect_ratios)]\n\n    # For every combination of (a, (g, s), i) in (self.cell_anchors, zip(grid_sizes, strides), 0:2),\n    # output g[i] anchors that are s[i] distance apart in direction i, with the same dimensions as a.\n    def grid_anchors(self, grid_sizes, strides):\n        # type: (List[List[int]], List[List[Tensor]]) -> List[Tensor]\n        anchors = []\n        cell_anchors = self.cell_anchors\n        assert cell_anchors is not None\n\n        if not (len(grid_sizes) == len(strides) == len(cell_anchors)):\n            raise ValueError(\"Achors should be Tuple[Tuple[int]] because each feature \"\n                             \"map could potentially have different sizes and aspect ratios. \"\n                             \"There needs to be a match between the number of \"\n                             \"feature maps passed and the number of sizes / aspect ratios specified.\")\n\n        for size, stride, base_anchors in zip(\n            grid_sizes, strides, cell_anchors\n        ):\n            grid_height, grid_width = size\n            stride_height, stride_width = stride\n            device = base_anchors.device\n\n            # For output anchor, compute [x_center, y_center, x_center, y_center]\n            shifts_x = torch.arange(\n                0, grid_width, dtype=torch.float32, device=device\n            ) * stride_width\n            shifts_y = torch.arange(\n                0, grid_height, dtype=torch.float32, device=device\n            ) * stride_height\n            shift_y, shift_x = torch.meshgrid(shifts_y, shifts_x)\n            shift_x = shift_x.reshape(-1)\n            shift_y = shift_y.reshape(-1)\n            shifts = torch.stack((shift_x, shift_y, shift_x, shift_y), dim=1)\n\n            # For every (base anchor, output anchor) pair,\n            # offset each zero-centered base anchor by the center of the output anchor.\n            anchors.append(\n                (shifts.view(-1, 1, 4) + base_anchors.view(1, -1, 4)).reshape(-1, 4)\n            )\n\n        return anchors\n\n    def cached_grid_anchors(self, grid_sizes, strides):\n        # type: (List[List[int]], List[List[Tensor]]) -> List[Tensor]\n        key = str(grid_sizes) + str(strides)\n        if key in self._cache:\n            return self._cache[key]\n        anchors = self.grid_anchors(grid_sizes, strides)\n        self._cache[key] = anchors\n        return anchors\n\n    def forward(self, image_list, feature_maps):\n        # type: (ImageList, List[Tensor]) -> List[Tensor]\n        grid_sizes = list([feature_map.shape[-2:] for feature_map in feature_maps])\n        image_size = image_list.tensors.shape[-2:]\n        dtype, device = feature_maps[0].dtype, feature_maps[0].device\n        strides = [[torch.tensor(image_size[0] // g[0], dtype=torch.int64, device=device),\n                    torch.tensor(image_size[1] // g[1], dtype=torch.int64, device=device)] for g in grid_sizes]\n        self.set_cell_anchors(dtype, device)\n        anchors_over_all_feature_maps = self.cached_grid_anchors(grid_sizes, strides)\n        anchors = torch.jit.annotate(List[List[torch.Tensor]], [])\n        for i, (image_height, image_width) in enumerate(image_list.image_sizes):\n            anchors_in_image = []\n            for anchors_per_feature_map in anchors_over_all_feature_maps:\n                anchors_in_image.append(anchors_per_feature_map)\n            anchors.append(anchors_in_image)\n        anchors = [torch.cat(anchors_per_image) for anchors_per_image in anchors]\n        # Clear the cache in case that memory leaks.\n        self._cache.clear()\n        return anchors\n", "path": "torchvision/models/detection/anchor_utils.py"}]}