Skip to content

remove private imports from torch.testing #7525

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

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

pmeier
Copy link
Collaborator

@pmeier pmeier commented Apr 17, 2023

No description provided.

@pytorch-bot
Copy link

pytorch-bot bot commented Apr 17, 2023

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/vision/7525

Note: Links to docs will display an error until the docs builds have been completed.

❌ 3 Failures

As of commit f9e77a6:

NEW FAILURES - The following jobs have failed:

This comment was automatically generated by Dr. CI and updates every 15 minutes.


if error_metas:
raise error_metas[0].to_error(msg)
for actual_item, expected_item in zip(actual_flat, expected_flat):
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The only "regression" compared to the patched assert_close is that we don't get any information where inside a sample an error happened. Consider the input sample to a detection model, i.e. a two-tuple with an image and a target dictionary. If the comparison of the bounding boxes target fails, assert_close would include [1]["boxes"] in the error message, whereas now we will only see the regular message and thus have to figure out ourselves what part of the input caused this.

We can re-implement this behavior if needed, but not sure its worth it. I guesstimate that 99% of our comparisons are single elements and thus no extra traceback is needed.

Apart from this, assert_close_with_image_support should be a faithful reproduction of the patched assert_close we had before.

Comment on lines +286 to +289
# This is a dirty hack that let's us "hook" into the comparison logic of `torch.testing.assert_close`. It
# will only be triggered in case of failed value comparison. This let's us reuse all of the attribute
# checking that `torch.testing.assert_close` does while giving us the ability to ignore the regular value
# comparison.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Per comment. Note while this is a hack, it doesn't depend on any non-public functionality or assumptions.

Copy link
Member

Choose a reason for hiding this comment

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

NIT

Suggested change
# This is a dirty hack that let's us "hook" into the comparison logic of `torch.testing.assert_close`. It
# will only be triggered in case of failed value comparison. This let's us reuse all of the attribute
# checking that `torch.testing.assert_close` does while giving us the ability to ignore the regular value
# comparison.
# This is a dirty hack that lets us "hook" into the comparison logic of `torch.testing.assert_close`. It
# will only be triggered in case of failed value comparison. This lets us reuse all of the attribute
# checking that `torch.testing.assert_close` does while giving us the ability to ignore the regular value
# comparison.

Copy link
Member

@NicolasHug NicolasHug left a comment

Choose a reason for hiding this comment

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

Thanks Philip, some quick pass

Comment on lines +290 to +291
nonlocal value_comparison_failure
value_comparison_failure = True
Copy link
Member

Choose a reason for hiding this comment

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

IIUC this is the "hack" part and the rest below is just the same as the implementation for the default msg_callback?

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. Basically this is our way of detecting that there was value comparison failure since this callback is only called in this specific case.

Comment on lines +306 to +307
if not (value_comparison_failure and mae):
raise
Copy link
Member

Choose a reason for hiding this comment

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

I might be misunderstanding, but why do we even bother trying torch.testing.assert_close when mae is True?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

assert_close does a lot more checks than just the value comparison. For us the most important ones are shape, dtype, and device checks. If we don't invoke assert_close, we'll have to do this ourselves or live with the fact that check_dtype=True is ignored when mae=True is set.

Comment on lines +309 to +311
if actual.dtype is torch.uint8:
actual, expected = actual.to(torch.int), expected.to(torch.int)
mae_value = float(torch.abs(actual - expected).float().mean())
Copy link
Member

Choose a reason for hiding this comment

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

(Hopefully correct?) NIT

Suggested change
if actual.dtype is torch.uint8:
actual, expected = actual.to(torch.int), expected.to(torch.int)
mae_value = float(torch.abs(actual - expected).float().mean())
mae_value = torch.abs(actual.float() - expected.float()).mean()

Comment on lines +286 to +289
# This is a dirty hack that let's us "hook" into the comparison logic of `torch.testing.assert_close`. It
# will only be triggered in case of failed value comparison. This let's us reuse all of the attribute
# checking that `torch.testing.assert_close` does while giving us the ability to ignore the regular value
# comparison.
Copy link
Member

Choose a reason for hiding this comment

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

NIT

Suggested change
# This is a dirty hack that let's us "hook" into the comparison logic of `torch.testing.assert_close`. It
# will only be triggered in case of failed value comparison. This let's us reuse all of the attribute
# checking that `torch.testing.assert_close` does while giving us the ability to ignore the regular value
# comparison.
# This is a dirty hack that lets us "hook" into the comparison logic of `torch.testing.assert_close`. It
# will only be triggered in case of failed value comparison. This lets us reuse all of the attribute
# checking that `torch.testing.assert_close` does while giving us the ability to ignore the regular value
# comparison.


self._compare_attributes(actual, expected)
actual, expected = self._equalize_attributes(actual, expected)
enable_mae_comparison = all(isinstance(input, torch.Tensor) for input in [actual, expected])
Copy link
Member

Choose a reason for hiding this comment

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

Should this be

Suggested change
enable_mae_comparison = all(isinstance(input, torch.Tensor) for input in [actual, expected])
enable_mae_comparison = all(isinstance(input, torch.Tensor) for input in [actual, expected]) and mae

? Regardless I don't really understand the reason for enable_mae_comparison. Why can't we just convert all inputs to tensors and apply mae comparison iff mae = True?

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 wrote this as a general function that one can use like assert_close, but with_image_support. Meaning, you can still do assert_close_with_image_support(None, 5) and get a proper error message. If we force everything into a tensor, that would not be possible.

Copy link
Member

Choose a reason for hiding this comment

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

But are we ever going to use it when the inputs aren't images (either PIL or Tensors)?

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, we have such usages:

  • In the functional v2 tests, we are using assert_close (or now assert_close_with_image_support) for all kernels and dispatchers and this of course also means bounding boxes, masks and videos.
  • In the consistency tests for the detection and segmentation tests, we test full samples against each other and thus the inputs are more than just images. This is somewhat also the case in our (fairly limited) transforms tests, but will probably increase there when we ramp them up.

actual, expected = self.actual, self.expected
def assert_close_with_image_support(actual, expected, *, mae=False, atol=None, msg=None, **kwargs):
def compare(actual, expected):
if all(isinstance(input, PIL.Image.Image) for input in [actual, expected]):
Copy link
Member

Choose a reason for hiding this comment

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

Why not convert all inputs to tensors, regardless of whether they're all PIL Images? Does that mean we can't do assert_close_with_image_support(some_tensor, some_pil_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.

See #7525 (comment) for one reason. Plus, we originally had the option to pass in one tensor and one PIL image and let the function handle the conversion to tensor. However, we often saw extra flakiness in the tests just to this conversion and thus we scraped that feature. Since this irregular anyway, the few tests that need this, perform the conversion themselves now. E.g.

def pil_reference_wrapper(pil_kernel):

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants