Skip to content

Conversation

@VitalyFedyunin
Copy link
Contributor

@VitalyFedyunin VitalyFedyunin commented Jul 25, 2019

Define 4D tensor as stored in channels last memory format, when dimensions order is NCHW and C-strides < W-strides < H-strides < N-strides (If size of any dimension is equal to 1, this dimension strides value is not taken into account).

Channels last contiguous tensor is channel last tensor which occupies contiguous memory block. So x.is_contiguous(memory_format=torch.channels_last) checks if tensor is channels last contiguous.

@pytorchbot pytorchbot added module: internals Related to internal abstractions in c10 and ATen module: operators labels Jul 25, 2019
@VitalyFedyunin VitalyFedyunin force-pushed the channels_last_stored_in_tensor branch from baf6bf6 to 9454dd5 Compare July 25, 2019 19:49
if (dim() == 4) {
int64_t expected = 1;
for (auto& d : {1, 3, 2, 0}) {
if (size(d) != 1) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

why skip for size 1? better to be safer and check it.

Also, there might be special effects if H=W=1 but I guess it's less likely.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because size 1 strides is broken in PyTorch, for example:

N = 10; C = 3; H = 32; W = 16;                                                                                                             
x = torch.randn(N,H,W,C)                                                                                                                     
x = x.permute(0,3,1,2)                                                                                                                       
y = x[0]                                                                                                                                     
z = y.unsqueeze(0)    
y.stride()                                                                                                                                   
Out[40]: (1, 48, 3)

In [41]: z.stride()                                                                                                                                   
Out[41]: (3, 1, 48, 3)

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't follow the reasoning here. There doesn't seem to be anything wrong with x[0], so you must be complaining about the behavior of unsqueeze. But the stride of a size one dimension doesn't actually matter, since it doesn't ever get used. Maybe the choice of the last element is a bit goofy; we probably did it because it's compatible with Numpy's behavior:

>>> N = 10; C = 3; H = 32; W = 16
>>> x = np.zeros((N,H,W,C))
>>> x = x.transpose(0,3,1,2)
>>> y = x[0]
>>> y.strides
(8, 384, 24)
>>> np.expand_dims(y, 0).strides
(24, 8, 384, 24)

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe your claim is that, since strides don't matter for size one dimensions, we should ignore them. I can get behind that reason. But I'm not sure I would jump to the conclusion that it is "broken".

Copy link
Contributor

Choose a reason for hiding this comment

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

In any case this should be amply documented :>

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, you should probably also skip zero size dimensions, following this reasoning.

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, broken is incorrect word here, what I meant is they carry zero information.

return false;
}

bool TensorImpl::compute_strides_like_channels_last() const {
Copy link
Collaborator

Choose a reason for hiding this comment

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

are you trying to cover slicing of channel-last tensors? does it actually occur in practice?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Slicing and bounding. Both might happen in pre-processing.

@VitalyFedyunin VitalyFedyunin changed the title [WIP] Channels last stored in tensor Channels last stored in tensor Jul 30, 2019
TensorTypeId type_id_;
bool is_contiguous_ = true;
bool is_channels_last_contiguous_ = false;
bool is_channels_last_ = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be possible to add a comment explaining the difference between is_channels_last_contiguous_ and is_channels_last_ here? Based on the rest of the patch, I think I know what it means, but I don't think it's obvious!

return impl_->is_contiguous(memory_format);
}

at::MemoryFormat suggest_memory_format() const {
Copy link
Contributor

Choose a reason for hiding this comment

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

Dead code. When is it going to be used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In follow up PRs by me, Igor and Jie.

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.

I'd like more docs but the substantive logic makes sense.

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.

@facebook-github-bot
Copy link
Contributor

@VitalyFedyunin merged this pull request in 6e4a83a.

zdevito pushed a commit to zdevito/ATen that referenced this pull request Aug 5, 2019
Summary:
Define 4D tensor as stored in channels last memory format, when dimensions order is NCHW and C-strides < W-strides < H-strides < N-strides (If size of any dimension is equal to 1, this dimension strides value is not taken into account).

Channels last contiguous tensor is channel last tensor which occupies contiguous memory block. So x.is_contiguous(memory_format=torch.channels_last) checks if tensor is channels last contiguous.
Pull Request resolved: pytorch/pytorch#23391

Differential Revision: D16601414

Pulled By: VitalyFedyunin

fbshipit-source-id: 8d098e7eec2f00fb1d12261bc240b3645d4f5b73
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Merged module: internals Related to internal abstractions in c10 and ATen

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants