Skip to content

Conversation

@yf225
Copy link
Contributor

@yf225 yf225 commented Jan 24, 2019

In VariableType.cpp, when a function modifies its input tensors, it should only change the input tensors' storage data in-place, and should never change the input tensors' storage pointers. This PR adds checks for this, and also fixes functions that fail this test.

This is part of the Variable/Tensor merge work (#13638).

@yf225 yf225 requested review from ezyang and gchanan January 24, 2019 05:48
@yf225 yf225 mentioned this pull request Jan 24, 2019
22 tasks
std::tie(solution, lu) = at::_gesv_helper(self, A);
Tensor solution_tmp, lu_tmp;
std::tie(solution_tmp, lu_tmp) = at::_gesv_helper(self, A);
solution.resize_as_(solution_tmp);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: it's a little nicer to read if you do this all on one line, e.g.:
solution.resize_as_(solution_tmp).copy_(solution_tmp);

'_coalesced_',
}

# When a function modifies its input tensors, it should only change the input tensors'
Copy link
Contributor

Choose a reason for hiding this comment

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

this isn't quite accurate -- we usually call resize, which means we are only guaranteed to keep the storage pointer if the size is equal (or less? is that right? can you check?).

Copy link
Contributor Author

@yf225 yf225 Jan 24, 2019

Choose a reason for hiding this comment

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

Resizing a tensor shows the following behavior:

  1. Expanding a tensor: always creates a new data_ptr, doesn't create a new StorageImpl or a new Storage wrapper.
  2. Shrinking a tensor: doesn't create a new data_ptr / StorageImpl / Storage.

For our purpose I think we should only check that StorageImpl stays the same after the internal function call (by checking storage.is_alias_of(storage_original), and we should allow the internal function to resize the tensor / change the data_ptr as needed.

baseType->${method_prefix_derived}${base_name}(${unpacked_args})""")

SAVE_TENSOR_STORAGE_PTR = CodeTemplate("""\
StorageImpl* ${tensor_name}_storage_ptr_saved = (${tensor_name}.defined() && !${tensor_name}.is_sparse()) ? ${tensor_name}.storage().unsafeGetStorageImpl() : nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

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

why do we need to look at the actual StorageImpl and not just the data pointer? Also, can't the Storage go away from under us because we aren't holding onto a reference?

Copy link
Contributor Author

@yf225 yf225 Jan 24, 2019

Choose a reason for hiding this comment

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

If we only checks the tensor data_ptr, we won't be able to allow in-place resize in the internal function (since in-place expanding a tensor will change its data_ptr), which might be putting too much of a constraint on what the internal function can do. Checking Storage or StorageImpl avoids this constraint, while still ensuring that data is being put into the original Storage.

if dynamic_type == 'TensorList':
unpacked_tensorlists.append(arg['name'])
elif dynamic_type != 'SparseTensorRef':
unpacked_tensors.append(arg['name'])
Copy link
Contributor

Choose a reason for hiding this comment

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

how do we know these are actually tensors?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

requires_unpack(arg) above checks whether the arg's dynamic_type contains Tensor, and the if 'TensorOptions' not in dynamic_type: check eliminates the TensorOptions case, so we know that these args are guaranteed to be tensors.

@yf225
Copy link
Contributor Author

yf225 commented Jan 31, 2019

I created an issue #16589 to track the leftover work for enforcing data_ptr equality for input tensors that have non-zero size.

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.

@yf225 has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

# The following list contains functions that we don't enforce the invariant on.
DONT_ENFORCE_SAME_TENSOR_IMPL_OR_STORAGE = {
# These functions are expected to change impl or storage of input tensors
'_th_set_', '_cudnn_rnn_flatten_weight',
Copy link
Contributor

Choose a reason for hiding this comment

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

are you going to change these?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's likely not possible to fix _th_set_ because changing storage is exactly its purpose. For fixing _cudnn_rnn_flatten_weight, I opened an issue at #16695.

std::vector<Storage> ${tensorlist_name}_storage_saved(${tensorlist_name}.size());
for (size_t i=0; i<${tensorlist_name}.size(); i++) {
${tensorlist_name}_storage_saved[i] =
(${tensorlist_name}[i].defined() && !${tensorlist_name}[i].is_sparse()) ?
Copy link
Contributor

Choose a reason for hiding this comment

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

can you use std::transform or something similar here?

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 feel that using std::transform might make the code a bit harder to read. I changed this to

for (Tensor tensor : ${tensorlist_name})
  ${tensorlist_name}_storage_saved.push_back(tensor.has_storage() ? tensor.storage() : Storage());

@yf225 yf225 force-pushed the gesv_fix_pointer_equality branch 4 times, most recently from 0fa5946 to 2f65222 Compare February 8, 2019 21:47
@yf225 yf225 force-pushed the gesv_fix_pointer_equality branch from 2f65222 to d1c9eef Compare February 8, 2019 21:49
@yf225 yf225 force-pushed the gesv_fix_pointer_equality branch from 866c19d to 8519448 Compare February 8, 2019 22:11
@yf225 yf225 force-pushed the gesv_fix_pointer_equality branch from 51438d7 to d7bcb67 Compare February 8, 2019 23:09
for arg in env.get('unpacked_args', []):
simple_type = env['unpacked_args_simple_type'][arg]
if simple_type == 'TensorList':
save_ptrs_block += SAVE_STORAGE_AND_IMPL.substitute(
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: do you actually have to build these into strings over just keeping them as lists? I thought CodeTemplates could handle those.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed by using lists instead of strings :)

@yf225 yf225 force-pushed the gesv_fix_pointer_equality branch from 46ab5a3 to ab34bb7 Compare February 11, 2019 16:16
@yf225 yf225 force-pushed the gesv_fix_pointer_equality branch from f81735f to df8dc9f Compare February 11, 2019 16:25
This reverts commit df8dc9f.
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.

@yf225 has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

zdevito pushed a commit to zdevito/ATen that referenced this pull request Feb 11, 2019
Summary:
In VariableType.cpp, when a function modifies its input tensors, it should only change the input tensors' storage data in-place, and should never change the input tensors' storage pointers. This PR adds checks for this, and also fixes functions that fail this test.

This is part of the Variable/Tensor merge work (pytorch/pytorch#13638).
Pull Request resolved: pytorch/pytorch#16305

Differential Revision: D13897855

Pulled By: yf225

fbshipit-source-id: 0c4fc7eb530d30db88037b1f0981f6f8454d3b79
pearu pushed a commit to Quansight/pytorch that referenced this pull request Feb 12, 2019
…16305)

Summary:
In VariableType.cpp, when a function modifies its input tensors, it should only change the input tensors' storage data in-place, and should never change the input tensors' storage pointers. This PR adds checks for this, and also fixes functions that fail this test.

This is part of the Variable/Tensor merge work (pytorch#13638).
Pull Request resolved: pytorch#16305

Differential Revision: D13897855

Pulled By: yf225

fbshipit-source-id: 0c4fc7eb530d30db88037b1f0981f6f8454d3b79
@ezyang ezyang added the merged label Jun 25, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants