Repository: pytorch/vision

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 


Discussion:
Hi,

Thanks for opening this issue.

I believe the code snippet that you included is not supposed to work, and it only worked before by accident (although potentially leading to worse results)

Indeed, you need to pass a custom `AnchorGenerator` that will only return one feature map, as your backbone is only returning one feature map.

The assert was added in https://github.com/pytorch/vision/pull/2722 as the without the assert users were using it incorrectly, which could lead to worse results.

The expected way to construct the model with mobilenet so that it works is illustrated in the documentation https://github.com/pytorch/vision/blob/6b071be9da221998c9ba4173fb5e4186dabdc9fe/torchvision/models/detection/faster_rcnn.py#L109-L141

We would be glad to accept a PR removing the `assert` and adding a `ValueError` message instead. Could you send a PR with it?
Hi, Thank you for answering this.
Yes definitely. I will send PR removing assert.

Resolving patch:
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 @@ def grid_anchors(self, grid_sizes, strides):
         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


Test patch: