Repository: kornia/kornia

Issue:
RandomResizedCrop behavior
## 🐛 Bug

Kornia's `RandomResizedCrop` fails on image smaller than the target. It doesn't with `torchvision` implementation. This essentially makes it impossible to train Imagenet.

## To Reproduce

Steps to reproduce the behavior:

1. Generate a small tensor
1. Apply RandomResizedCrop with larger size than input
1. Fail with `ValueError: input_size (147, 190) cannot be smaller than crop size tensor([[158., 156.]]) in any dimension`
2. Run with torchvision and it succeeds.


<!-- If you have a code sample, error messages, stack traces, please provide it here as well -->

## Expected behavior

Has the same behavior as `torchvision`.

<!-- A clear and concise description of what you expected to happen. -->

## Environment

pip installed version of `kornia`



Discussion:
@GuillaumeLeclerc we are aware of issues with this funcion. There's gonna be a refactor on that soon.


Resolving patch:
diff --git a/kornia/augmentation/random_generator/random_generator.py b/kornia/augmentation/random_generator/random_generator.py
--- a/kornia/augmentation/random_generator/random_generator.py
+++ b/kornia/augmentation/random_generator/random_generator.py
@@ -384,14 +384,16 @@ def random_crop_generator(
     assert size.shape == torch.Size([batch_size, 2]), (
         "If `size` is a tensor, it must be shaped as (B, 2). "
         f"Got {size.shape} while expecting {torch.Size([batch_size, 2])}.")
+    assert input_size[0] > 0 and input_size[1] > 0 and (size > 0).all(), \
+        f"Got non-positive input size or size. {input_size}, {size}."
     size = size.floor()
 
     x_diff = input_size[1] - size[:, 1] + 1
     y_diff = input_size[0] - size[:, 0] + 1
 
-    if (x_diff < 0).any() or (y_diff < 0).any():
-        raise ValueError("input_size %s cannot be smaller than crop size %s in any dimension."
-                         % (str(input_size), str(size)))
+    # Start point will be 0 if diff < 0
+    x_diff = x_diff.clamp(0)
+    y_diff = y_diff.clamp(0)
 
     if batch_size == 0:
         return dict(
@@ -409,15 +411,15 @@ def random_crop_generator(
     crop_src = bbox_generator(
         x_start.view(-1).to(device=_device, dtype=_dtype),
         y_start.view(-1).to(device=_device, dtype=_dtype),
-        size[:, 1].to(device=_device, dtype=_dtype),
-        size[:, 0].to(device=_device, dtype=_dtype))
+        torch.where(size[:, 1] == 0, torch.tensor(input_size[1], device=_device, dtype=_dtype), size[:, 1]),
+        torch.where(size[:, 0] == 0, torch.tensor(input_size[0], device=_device, dtype=_dtype), size[:, 0]))
 
     if resize_to is None:
         crop_dst = bbox_generator(
             torch.tensor([0] * batch_size, device=_device, dtype=_dtype),
             torch.tensor([0] * batch_size, device=_device, dtype=_dtype),
-            size[:, 1].to(device=_device, dtype=_dtype),
-            size[:, 0].to(device=_device, dtype=_dtype))
+            size[:, 1],
+            size[:, 0])
     else:
         assert len(resize_to) == 2 and isinstance(resize_to[0], (int,)) and isinstance(resize_to[1], (int,)) \
             and resize_to[0] > 0 and resize_to[1] > 0, \


Test patch:
diff --git a/test/augmentation/test_augmentation.py b/test/augmentation/test_augmentation.py
--- a/test/augmentation/test_augmentation.py
+++ b/test/augmentation/test_augmentation.py
@@ -2165,6 +2165,26 @@ def test_crop_scale_ratio(self, device, dtype):
         out = rrc(inp)
         assert_allclose(out, expected, atol=1e-4, rtol=1e-4)
 
+    def test_crop_size_greater_than_input(self, device, dtype):
+        # This is included in doctest
+        torch.manual_seed(0)
+        inp = torch.tensor([[
+            [0., 1., 2.],
+            [3., 4., 5.],
+            [6., 7., 8.]
+        ]], device=device, dtype=dtype)
+
+        exp = torch.tensor([[[[1.0000, 1.3333, 1.6667, 2.0000],
+                              [3.0000, 3.3333, 3.6667, 4.0000],
+                              [5.0000, 5.3333, 5.6667, 6.0000],
+                              [7.0000, 7.3333, 7.6667, 8.0000]]]], device=device, dtype=dtype)
+
+        rrc = RandomResizedCrop(size=(4, 4), scale=(3., 3.), ratio=(2., 2.))
+        # It will crop a size of (3, 3) from the aspect ratio implementation of torch
+        out = rrc(inp)
+        assert out.shape == torch.Size([1, 1, 4, 4])
+        assert_allclose(out, exp, atol=1e-4, rtol=1e-4)
+
     def test_crop_scale_ratio_batch(self, device, dtype):
         torch.manual_seed(0)
         batch_size = 2
diff --git a/test/augmentation/test_random_generator.py b/test/augmentation/test_random_generator.py
--- a/test/augmentation/test_random_generator.py
+++ b/test/augmentation/test_random_generator.py
@@ -434,9 +434,7 @@ def test_valid_param_combinations(
 
     @pytest.mark.parametrize('input_size,size,resize_to', [
         ((-300, 300), (200, 200), (100, 100)),
-        ((100, 100), (200, 200), (100, 100)),
         ((200, 200), torch.tensor([50, 50]), (100, 100)),
-        ((100, 100), torch.tensor([[200, 200], [200, 200]]), (100, 100)),
     ])
     def test_invalid_param_combinations(self, input_size, size, resize_to, device, dtype):
         batch_size = 2