Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unified Tensor/PIL crop #2342

Merged
merged 12 commits into from
Jun 30, 2020
Merged

Conversation

vfdev-5
Copy link
Collaborator

@vfdev-5 vfdev-5 commented Jun 23, 2020

Addresses #2292

Description:

  • Unified Tensor/PIL input for RandomCrop and F.crop
  • Unified Tensor/PIL input for CenterCrop and F.center_crop
  • Unified Tensor/PIL input for FiveCrop and F.five_crop
  • Unified Tensor/PIL input for TenCrop and F.ten_crop
  • Additionally, replaced py2 style by py3 style typing.

@vfdev-5 vfdev-5 force-pushed the issue-2292-unify-crop-op branch from 0a166fd to 94e29a4 Compare June 26, 2020 12:26
@vfdev-5 vfdev-5 marked this pull request as ready for review June 26, 2020 13:26
@vfdev-5 vfdev-5 changed the title [WIP] Unified Tensor/PIL crop Unified Tensor/PIL crop Jun 26, 2020
def ten_crop(img, size, vertical_flip=False):
"""Generate ten cropped images from the given PIL Image.
Crop the given PIL Image into four corners and the central crop plus the
def ten_crop(img: Tensor, size: List[int], vertical_flip: bool = False) -> List[Tensor]:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List[Tensor] instead of Tuple[Tensor, ..., Tensor] due to torch.jit behaviour when concat two tuples.

@vfdev-5
Copy link
Collaborator Author

vfdev-5 commented Jun 26, 2020

@fmassa could you please review this PR

Copy link
Member

@fmassa fmassa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the PR Victor!

I only really have two comments (about @torch.jit.export), apart from that the PR looks good to merge, thanks!

@@ -3,12 +3,19 @@
from torch.jit.annotations import List, BroadcastingList2


def _is_tensor_a_torch_image(input):
return input.ndim >= 2
@torch.jit.export
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure @torch.jit.export is needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right about that, I'll remove it



def vflip(img):
# type: (Tensor) -> Tensor
@torch.jit.export
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment here, we now have recursive compilation, so I don't think this is actually needed. Plus, I thought that torch.jit.export was needed only for decorating nn.Module methods?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, i'll remove it

@@ -39,12 +45,11 @@ def hflip(img):
return img.flip(-1)


def crop(img, top, left, height, width):
# type: (Tensor, int, int, int, int) -> Tensor
def crop(img: Tensor, top: int, left: int, height: int, width: int):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: missing the return type?

@@ -623,7 +640,7 @@ def __call__(self, img):
Returns:
PIL Image: Random perspectivley transformed image.
"""
if not F._is_pil_image(img):
if not F.F_pil._is_pil_image(img):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks weird? Although I see the point, I'm not sure I would recommend users importing F_pil from the functional.py file.

Plus, both the functional_pil and functional_tensor are meant to be just implementation details functions, and might be preferable if they didn't leak to transforms.py

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, looks weird. I can introduce in functional.py as shortcut

from . import functional_pil as F_pil
from . import functional_tensor as F_t


_is_pil_image = F_pil._is_pil_image

Copy link
Member

@fmassa fmassa Jun 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good to me!

- removed useless torch.jit.export
- added missing typing return type
- fixed F.F_pil._is_pil_image -> F._is_pil_image
Copy link
Collaborator Author

@vfdev-5 vfdev-5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review Francisco !
I'll push modification according to the review !

@@ -3,12 +3,19 @@
from torch.jit.annotations import List, BroadcastingList2


def _is_tensor_a_torch_image(input):
return input.ndim >= 2
@torch.jit.export
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right about that, I'll remove it



def vflip(img):
# type: (Tensor) -> Tensor
@torch.jit.export
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, i'll remove it

@@ -623,7 +640,7 @@ def __call__(self, img):
Returns:
PIL Image: Random perspectivley transformed image.
"""
if not F._is_pil_image(img):
if not F.F_pil._is_pil_image(img):
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, looks weird. I can introduce in functional.py as shortcut

from . import functional_pil as F_pil
from . import functional_tensor as F_t


_is_pil_image = F_pil._is_pil_image

_is_pil_image = F_pil._is_pil_image


@torch.jit.export
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe event this one is unnecessary

crop_left = int(round((image_width - crop_width) / 2.))

# crop_top = int(round((image_height - crop_height) / 2.))
# Result can be different between python func and scripted func
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why the results can be different? If yes this is a bug that should be reported / fixed

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is, probably, a bug with torch.jit.script:

import torch

def foo(x: int) -> int:    
    return int(round(x / 2.0))

sfoo = torch.jit.script(foo)

assert foo(7) == sfoo(7)
# but
assert foo(5) == sfoo(5)
> 2 vs 3

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the snippet, this can be further simplified as follows

import torch

def foo():    
    return round(2.5)

sfoo = torch.jit.script(foo)
print(foo(), sfoo())
# 2, 3.0
# different values and types

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened an issue in PyTorch to track this pytorch/pytorch#40771

Can you add a comment to revert back to the original implementation once that issue is fixed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I saw that you left the code commented out, so this is fine for now

Copy link
Member

@fmassa fmassa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have 3 comments left, otherwise looks good to go!


def _is_numpy(img):

@torch.jit.ignore
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think torch.jit.unused is better here, otherwise those functions won't be able to be serialized / exported

return isinstance(img, np.ndarray)


def _is_numpy_image(img):
@torch.jit.ignore
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I think torch.jit.unused is better in this case

Copy link
Member

@fmassa fmassa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot Victor!

@fmassa fmassa merged commit a99b6bd into pytorch:master Jun 30, 2020
@vfdev-5 vfdev-5 deleted the issue-2292-unify-crop-op branch June 30, 2020 13:25
de-vri-es pushed a commit to fizyr-forks/torchvision that referenced this pull request Aug 4, 2020
* [WIP] Unified Tensor/PIL crop

* Fixed misplaced type annotation

* Fixed tests
- crop with padding
- other tests using mising private functions: _is_pil_image, _get_image_size

* Unified CenterCrop and F.center_crop
- sorted includes in transforms.py
- used py3 annotations

* Unified FiveCrop and F.five_crop

* Improved tests and docs

* Unified TenCrop and F.ten_crop

* Removed useless typing in functional_pil

* Updated code according to the review
- removed useless torch.jit.export
- added missing typing return type
- fixed F.F_pil._is_pil_image -> F._is_pil_image

* Removed useless torch.jit.export

* Improved code according to the review
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants