Repository: pytorch/vision

Issue:
incorrect aspect ratio in RandomResizedCrop
https://github.com/pytorch/vision/blob/86001a871d3335046e2dca7715d9babf73e6956f/torchvision/transforms/transforms.py#L565
Inverted aspect ratio may be out of the range specified.
For example, RandomResizedCrop.get_params(img, ratio=(0.75,0.75)) can return something like (41, 17, 153, 204) where aspect ratio is 1.33.


Discussion:
Looks like you are right.
But I don't think it's simply a matter of removing the line you pointed out, because the sampling will not be uniform over the aspect ratios.
To give an example of why, imagine that we use ratios of 0.1 and 10. Randomly sampling over this interval will generally lead to samples with aspect ratio > 1, while one would expect it to be sampling with the same probability both cases (and that's why we have the line you mentioned).
How about
```python
if random.random() < 0.5 and min(ratio) <= 1/aspect_ratio <= max(ratio):
    w, h = h, w
```
@fmassa what do u think about the proposed solution ?

Resolving patch:
diff --git a/torchvision/transforms/functional.py b/torchvision/transforms/functional.py
--- a/torchvision/transforms/functional.py
+++ b/torchvision/transforms/functional.py
@@ -376,8 +376,8 @@ def resized_crop(img, i, j, h, w, size, interpolation=Image.BILINEAR):
 
     Args:
         img (PIL Image): Image to be cropped.
-        i: Upper pixel coordinate.
-        j: Left pixel coordinate.
+        i: i in (i,j) i.e coordinates of the upper left corner
+        j: j in (i,j) i.e coordinates of the upper left corner
         h: Height of the cropped image.
         w: Width of the cropped image.
         size (sequence or int): Desired output size. Same semantics as ``resize``.
diff --git a/torchvision/transforms/transforms.py b/torchvision/transforms/transforms.py
--- a/torchvision/transforms/transforms.py
+++ b/torchvision/transforms/transforms.py
@@ -543,7 +543,13 @@ class RandomResizedCrop(object):
     """
 
     def __init__(self, size, scale=(0.08, 1.0), ratio=(3. / 4., 4. / 3.), interpolation=Image.BILINEAR):
-        self.size = (size, size)
+        if isinstance(size, tuple):
+            self.size = size
+        else:
+            self.size = (size, size)
+        if (scale[0] > scale[1]) or (ratio[0] > ratio[1]):
+            warnings.warn("range should be of kind (min, max)")
+
         self.interpolation = interpolation
         self.scale = scale
         self.ratio = ratio
@@ -570,7 +576,7 @@ def get_params(img, scale, ratio):
             w = int(round(math.sqrt(target_area * aspect_ratio)))
             h = int(round(math.sqrt(target_area / aspect_ratio)))
 
-            if random.random() < 0.5:
+            if random.random() < 0.5 and min(ratio) <= (h / w) <= max(ratio):
                 w, h = h, w
 
             if w <= img.size[0] and h <= img.size[1]:


Test patch:
diff --git a/test/test_transforms.py b/test/test_transforms.py
--- a/test/test_transforms.py
+++ b/test/test_transforms.py
@@ -1,3 +1,4 @@
+from __future__ import division
 import torch
 import torchvision.transforms as transforms
 import torchvision.transforms.functional as F
@@ -130,6 +131,25 @@ def test_ten_crop(self):
                 assert len(results) == 10
                 assert expected_output == results
 
+    def test_randomresized_params(self):
+        height = random.randint(24, 32) * 2
+        width = random.randint(24, 32) * 2
+        img = torch.ones(3, height, width)
+        to_pil_image = transforms.ToPILImage()
+        img = to_pil_image(img)
+        size = 100
+        epsilon = 0.05
+        for i in range(10):
+            scale_min = round(random.random(), 2)
+            scale_range = (scale_min, scale_min + round(random.random(), 2))
+            aspect_min = round(random.random(), 2)
+            aspect_ratio_range = (aspect_min, aspect_min + round(random.random(), 2))
+            randresizecrop = transforms.RandomResizedCrop(size, scale_range, aspect_ratio_range)
+            _, _, h, w = randresizecrop.get_params(img, scale_range, aspect_ratio_range)
+            aspect_ratio_obtained = w / h
+            assert (min(aspect_ratio_range) - epsilon <= aspect_ratio_obtained <= max(aspect_ratio_range) + epsilon or
+                    aspect_ratio_obtained == 1.0)
+
     def test_resize(self):
         height = random.randint(24, 32) * 2
         width = random.randint(24, 32) * 2