Skip to content

Conversation

@VitalyFedyunin
Copy link
Contributor

@VitalyFedyunin VitalyFedyunin commented May 15, 2019

Original RFC #19092

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) == False

Now we need a way to preserve memory format in empty_like

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

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

@pytorchbot pytorchbot added caffe2 oncall: jit Add this issue/PR to JIT oncall triage queue module: build Build system issues module: cuda Related to torch.cuda, and CUDA support in general module: internals Related to internal abstractions in c10 and ATen module: operators module: pybind Related to our Python bindings / interactions with other Python libraries module: sparse Related to torch.sparse module: typing Related to mypy type annotations labels May 15, 2019
@VitalyFedyunin
Copy link
Contributor Author

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) == False

Now we need a way to preserve memory format in empty_like

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

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

@VitalyFedyunin VitalyFedyunin changed the title [WIP] Adding memory_format to randn and empty operators [WIP] Adding memory_format to empty and empty_like operators May 22, 2019
@pytorchbot pytorchbot added the module: autograd Related to torch.autograd, and the autograd engine in general label May 22, 2019
@VitalyFedyunin VitalyFedyunin changed the title [WIP] Adding memory_format to empty and empty_like operators Adding memory_format to empty and empty_like operators May 22, 2019
@VitalyFedyunin VitalyFedyunin requested a review from dzhulgakov May 22, 2019 21:04
@VitalyFedyunin VitalyFedyunin force-pushed the memory_format_empty_like branch from 4f347b2 to fd52f83 Compare May 22, 2019 21:08
@pytorchbot pytorchbot added the module: cpp-extensions Related to torch.utils.cpp_extension label May 23, 2019
}
}
return false;
return dim() == 4 && strides() == get_channels_last_strides(sizes());
Copy link
Collaborator

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

Copy link
Contributor Author

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.

Copy link
Contributor

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 :)

Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a 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.

@VitalyFedyunin
Copy link
Contributor Author

@ailzhang Looks like it breaks XLA, what is the course of the actions to patch XLA?

@VitalyFedyunin VitalyFedyunin requested a review from ezyang June 18, 2019 20:39
Copy link
Contributor

@ailzhang ailzhang left a 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 )

@VitalyFedyunin
Copy link
Contributor Author

@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);
Copy link
Contributor

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(
Copy link
Contributor

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.

Copy link
Contributor Author

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");
Copy link
Contributor

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)

Copy link
Contributor Author

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)
Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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.

@ezyang
Copy link
Contributor

ezyang commented Jun 19, 2019

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:

Copy link
Contributor

@ezyang ezyang left a comment

Choose a reason for hiding this comment

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

See comments

@VitalyFedyunin
Copy link
Contributor Author

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a 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.

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a 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.

@VitalyFedyunin
Copy link
Contributor Author

xla fail is expected, empty, empty_like and empty_out signatures have to be updated in xla

@facebook-github-bot
Copy link
Contributor

@VitalyFedyunin merged this pull request in 516c7e4.

zdevito pushed a commit to zdevito/ATen that referenced this pull request Jun 26, 2019
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

caffe2 Merged module: autograd Related to torch.autograd, and the autograd engine in general module: build Build system issues module: cpp-extensions Related to torch.utils.cpp_extension module: cuda Related to torch.cuda, and CUDA support in general module: internals Related to internal abstractions in c10 and ATen module: mkldnn Related to Intel IDEEP or oneDNN (a.k.a. mkldnn) integration module: pybind Related to our Python bindings / interactions with other Python libraries module: sparse Related to torch.sparse module: typing Related to mypy type annotations oncall: jit Add this issue/PR to JIT oncall triage queue oncall: quantization Quantization support in PyTorch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants