-
Notifications
You must be signed in to change notification settings - Fork 26.3k
Adding memory_format to empty and empty_like operators #20558
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
Adding memory_format to empty and empty_like operators #20558
Conversation
|
To ensure that we are not introducing BC breaking change, empty_like returns contiguous tensor by default. nCwh = torch.randn(N, C, H, W)
nhwC = nCwh.contiguous(memory_format=torch.channels_last)
new_nCwh = torch.empty_like(nhwC)
new_nCwh.is_contiguous(memory_format=torch.channels_last) == FalseNow we need a way to preserve memory format in nCwh = torch.randn(N, C, H, W)
nhwC = nCwh.contiguous(memory_format=torch.channels_last)
new_nhwC = torch.empty_like(nhwC, memory_format=torch.preserve_format)
new_nhwC.is_contiguous(memory_format=torch.channels_last) == True
like_nCwh = torch.empty_like(nCwh, memory_format=torch.preserve_format)
like_nCwh.is_contiguous(memory_format=torch.channels_last) == FalseUsage of We can also generate different memory format outputs nCwh = torch.randn(N, C, H, W)
nhwC = nCwh.contiguous(memory_format=torch.channels_last)
new_nhwC = torch.empty_like(nCwh, memory_format=torch.channels_last)
new_nhwC.is_contiguous(memory_format=torch.channels_last) == True
new_nCwh = torch.empty_like(nhwC, memory_format=torch.contiguous)
new_nCwh.is_contiguous(memory_format=torch.channels_last) == False |
4f347b2 to
fd52f83
Compare
c10/core/TensorImpl.cpp
Outdated
| } | ||
| } | ||
| return false; | ||
| return dim() == 4 && strides() == get_channels_last_strides(sizes()); |
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.
is C++ smart enough to inline std::vector and avoid memory allocation? if not, I wouldn't pull out this function
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 function call will go away in the next PR (Where I introduce 'tag') as calculating this every time is very inefficient.
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.
Is the tag advisory or not? If the tag is advisory, I would not expect is_contiguous to change behavior depending on if the tag is set or not (and so I agree with @dzhulgakov here). If the tag is non-advisory, I have concerns about the overall design :)
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.
Since we killed tags, now this comment applies once again, right?
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 code line will go away anyway in non 'tag' option too.
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.
For peace of mind, I will not pull out it now. And replace copy-pasted code in the next PR.
facebook-github-bot
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.
@VitalyFedyunin has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
|
@ailzhang Looks like it breaks XLA, what is the course of the actions to patch XLA? |
ailzhang
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.
At the first glance it looks easy to fix on xla side. So I'm fine with landing this as long as others are happy about the change.
(in the worst case I might need to revert :P )
|
@pytorchbot retest this please |
| result.sparse_resize_and_clear_(size, size.size(), 0); | ||
| } else { | ||
| result.resize_(size); | ||
| auto memory_format = optional_memory_format.value_or(MemoryFormat::Contiguous); |
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 is guaranteed to be none, right? So just set memory_format = Contiguous
| } else if (self.is_contiguous(MemoryFormat::Contiguous)) { | ||
| use_memory_format = MemoryFormat::Contiguous; | ||
| } else { | ||
| TORCH_CHECK( |
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.
Some wild speculation. Since we've completely removed the memory tag, what if we ALWAYS preserved striding in the preserve case? (Instead of only preserving if we matched a memory format). This would subsume all of the checking here, and it feels more morally correct.
This doesn't have to be fixed today because the error gives us an out; but it seems worth thinking about.
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 have been thinking same way, as it kind of makes sense to return channels_last tensor if I do something like:
y = torch.empty_like( nhwc[0].unsqueeze(0) )| } | ||
| TORCH_CHECK( | ||
| memory_format != MemoryFormat::Preserve, | ||
| "preserve memory format is unsupported by the contiguous operator"); |
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.
Or we could just no-op if you pass preserve to contiguous :) (I'm not sure if that makes any code easier to write lol)
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.
no-op meaning return itself? It is kind of unclear what to do with randomly permuted tensor in this case. I rather throw error instead of guessing what user mean.
| def _test_memory_format_empty_like(self, x): | ||
| nhwc = x.contiguous(memory_format=torch.channels_last) | ||
|
|
||
| like = torch.empty_like(nhwc, memory_format=torch.preserve_format) |
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 feel that these tests are not sufficient. Suppose I write a buggy implementation of the stride computation so that I put channels before batch rather than after. I don't think any of these tests would catch an error like that.
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 is some small utility in replicating the stride logic for a specific dimensionality here, because when you generalize the formula it will help catch errors in a less correlated way. Other properties you could check are that transpositions related the striding between channels first and channels last.
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.
Agree, but it will make sense as part of the next PR where I plan to introduce this channels_last criteria, and cover basic operations on it.
|
In the interest of being super explicit, here is what I would like to see before landing:
Things that I'd like to see soon:
|
ezyang
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.
See comments
Done
Next smaller PR. |
facebook-github-bot
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.
@VitalyFedyunin has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
facebook-github-bot
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.
@VitalyFedyunin has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
|
xla fail is expected, |
|
@VitalyFedyunin merged this pull request in 516c7e4. |
Summary: Original RFC pytorch/pytorch#19092 To ensure that we are not introducing BC breaking change, empty_like returns contiguous tensor by default. ```python nCwh = torch.randn(N, C, H, W) nhwC = nCwh.contiguous(memory_format=torch.channels_last) new_nCwh = torch.empty_like(nhwC) new_nCwh.is_contiguous(memory_format=torch.channels_last) == False ``` Now we need a way to preserve memory format in `empty_like` ```python nCwh = torch.randn(N, C, H, W) nhwC = nCwh.contiguous(memory_format=torch.channels_last) new_nhwC = torch.empty_like(nhwC, memory_format=torch.preserve_format) new_nhwC.is_contiguous(memory_format=torch.channels_last) == True like_nCwh = torch.empty_like(nCwh, memory_format=torch.preserve_format) like_nCwh.is_contiguous(memory_format=torch.channels_last) == False ``` Usage of `torch.preserve_format` allows us to avoid `if` constructs. We can also generate different memory format outputs ```python nCwh = torch.randn(N, C, H, W) nhwC = nCwh.contiguous(memory_format=torch.channels_last) new_nhwC = torch.empty_like(nCwh, memory_format=torch.channels_last) new_nhwC.is_contiguous(memory_format=torch.channels_last) == True new_nCwh = torch.empty_like(nhwC, memory_format=torch.contiguous_format) new_nCwh.is_contiguous(memory_format=torch.channels_last) == False ``` Pull Request resolved: pytorch/pytorch#20558 Differential Revision: D15502474 Pulled By: VitalyFedyunin fbshipit-source-id: 2e120d57eefad6fb8e04b8322c79871392f64331
Original RFC #19092
To ensure that we are not introducing BC breaking change, empty_like returns contiguous tensor by default.
Now we need a way to preserve memory format in
empty_likeUsage of
torch.preserve_formatallows us to avoidifconstructs.We can also generate different memory format outputs