-
Notifications
You must be signed in to change notification settings - Fork 7.2k
Implement Flip transforms with CVCUDA backend #9277
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
base: main
Are you sure you want to change the base?
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/vision/9277
Note: Links to docs will display an error until the docs builds have been completed. ❗ 2 Active SEVsThere are 2 currently active SEVs. If your PR is affected, please view them below: This comment was automatically generated by Dr. CI and updates every 15 minutes. |
9cb272b to
02c320a
Compare
|
@zy1git What is the strategy for creating the tests for the transforms with CV-CUDA backends? Do we want to have all the tests live entirely inside the existing classes or make a new class? The PRs for gaussian_blur, normalize, and to_dtype I made all use new classes, but I can switch it be more centralized. |
02c320a to
330db00
Compare
AntoineSimoulin
left a comment
There was a problem hiding this 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 submitting this PR! This is looking good. I added some comments to make sure we have an extensive test coverage:)
|
@justincdavis replying to your question in #9277 (comment): we prefer centralizing the tests in the existing test class. The idea is that, as much as possible, we'd just add CV-CUDA as a parametrization entry with |
|
@NicolasHug Makes sense! I will follow the comments you and Antoine left on this PR |
… according to the comments
330db00 to
98616f4
Compare
There was a problem hiding this 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 addressing the initial comments! I left some final adjustments to make. Let's also make sure linting and tests are passing!
|
@AntoineSimoulin @NicolasHug @zy1git I would propose that we take an approach like this to simplify the comparison of CV-CUDA tensors with PIL references. We would add the following function to Then we would modify Then when we compare the actual tensor ( Additionally, with the helper function to These changes are integrated in this PR |
NicolasHug
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the great work @zy1git ! I made another pass.
| tol=1e-5, | ||
| msg=None, | ||
| agg_method="mean", | ||
| allowed_percentage_diff=None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Above: this looks like a cosmetic change? Try to avoid that and revert the previous state, it's distracting when reviewing and it also affects git blame unnecessarily :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this cosmetic change happens after I use pre-commit hooks which run both ufmt and flake8 as described here
| "ignore", | ||
| message=re.escape("operator() profile_node %"), | ||
| category=UserWarning, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, this looks like a cosmetic change?
|
|
||
| from .functional._utils import _get_kernel | ||
|
|
||
| CVCUDA_AVAILABLE = _is_cvcuda_available() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem to be used, we can remove it.
| # Remove batch dimension if it's 1 for easier comparison | ||
| if actual.shape[0] == 1: | ||
| actual = actual[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems unnecessary, we should be able to compare tensors where the batch dim is 1. Try to remove it, if it doesn't work for any reason let me know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EDIT: ah, OK, it's for when we compare a 3D PIL image to a 4D cvcuda tensor. That's... fine. Let's explain why then (addition in bold):
Remove batch dimension if it's 1 for easier comparison against 3D PIL images
| try: | ||
| import cvcuda | ||
| from torchvision.transforms.v2.functional import cvcuda_to_tensor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use the _is_cvcuda_available() instead of a try/except. You can then call cvcuda = _import_cvcuda() which is safer and less surprising than a raw import cvcuda.
| if isinstance(input, cvcuda.Tensor): | ||
| assert_equal(F.cvcuda_to_tensor(output), F.cvcuda_to_tensor(input)) | ||
| else: | ||
| assert_equal(output, input) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there should be no need to manually convert anymore, assert_equal should be able to handle it. Also don't make raw cvcuda accesses! It would force a hard dependency :)
|
|
||
| assert_equal(valid, torch.tensor(expected_valid_mask)) | ||
| assert type(valid) == torch.Tensor | ||
| assert type(valid) is torch.Tensor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
revert both above, they seem unrelated and not needed.
| # Convert PIL images to tv_tensors.Image (regardless of what the other is) | ||
| if isinstance(actual, PIL.Image.Image): | ||
| actual = to_image(actual) | ||
| if isinstance(expected, PIL.Image.Image): | ||
| expected = to_image(expected) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noting that the above is a change of behavior: we used to convert both inputs, or none of them, which means we'd error when comparing a tensor to a PIL image. We now accept it. I think that's fine.
@justincdavis thanks for sharing your implementation in https://github.com/pytorch/vision/pull/9284/files#diff-f833e6bb21df531837a51e84306266c2f1f6d1565340a498095868e24b3f27de. I think you were being slightly more conservative in your added logic. Was there any particular edge-case you had in mind that you wanted to guard against?
| if CVCUDA_AVAILABLE: | ||
| _transformed_types = (torch.Tensor, PIL.Image.Image, cvcuda.Tensor) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be
| if CVCUDA_AVAILABLE: | |
| _transformed_types = (torch.Tensor, PIL.Image.Image, cvcuda.Tensor) | |
| _transformed_types = _RandomApplyTransform._transformed_types + (is_cvcuda_tensor, ) |
where is_cvcuda_tensor is @justincdavis 's implementation from:
https://github.com/pytorch/vision/pull/9283/files#diff-6e892912803ab29861746f7118e9e462a5c9eaab50ad286903e87f09f6c44ff3R175
The function is great and it allows us to avoid the big if CVCUDA_AVAILABLE.
To follow-up from the discussion in https://github.com/pytorch/vision/pull/9277/files#r2566354008 about whether this _transformed_types should be in each child transform class or in the base Transform class: I think it should be in each child transform for now (as done here):
- we may have a to push a release where we won't have implemented cvcuda support for all transforms, so if this was in the base class then we'd be claiming cvcuda support for some transforms that actually do not support it
- we may publish new transforms in the future which won't immediately come with cvcuda support, causing the same kind of problem.
We could revisit this eventually. It might eventually be simpler to just have that once and for all in the base Transform class. But having it in each child classes isn't much work, and it makes it easier to track which ones support cvcuda, and which ones don't.
Summary:
Implemented _horizontal_flip_image_cvcuda and _vertical_flip_image_cvcuda kernels using cvcuda.flip operator. The kernels are automatically registered when CVCUDA is available and route cvcuda.Tensor inputs appropriately.
Test Plan: