-
Notifications
You must be signed in to change notification settings - Fork 26.3k
Enforce same input tensor storage in VariableType functions #16305
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
Conversation
| 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); |
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.
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);
tools/autograd/gen_variable_type.py
Outdated
| '_coalesced_', | ||
| } | ||
|
|
||
| # When a function modifies its input tensors, it should only change the input tensors' |
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 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?).
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.
Resizing a tensor shows the following behavior:
- Expanding a tensor: always creates a new data_ptr, doesn't create a new StorageImpl or a new Storage wrapper.
- 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.
tools/autograd/gen_variable_type.py
Outdated
| 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; |
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.
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?
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.
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.
tools/autograd/gen_variable_type.py
Outdated
| if dynamic_type == 'TensorList': | ||
| unpacked_tensorlists.append(arg['name']) | ||
| elif dynamic_type != 'SparseTensorRef': | ||
| unpacked_tensors.append(arg['name']) |
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.
how do we know these are actually tensors?
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.
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.
|
I created an issue #16589 to track the leftover work for enforcing |
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.
@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', |
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.
are you going to change these?
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.
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.
tools/autograd/gen_variable_type.py
Outdated
| 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()) ? |
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.
can you use std::transform or something similar here?
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 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());
0fa5946 to
2f65222
Compare
2f65222 to
d1c9eef
Compare
866c19d to
8519448
Compare
51438d7 to
d7bcb67
Compare
tools/autograd/gen_variable_type.py
Outdated
| 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( |
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.
nit: do you actually have to build these into strings over just keeping them as lists? I thought CodeTemplates could handle those.
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.
Fixed by using lists instead of strings :)
46ab5a3 to
ab34bb7
Compare
f81735f to
df8dc9f
Compare
This reverts commit df8dc9f.
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.
@yf225 has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
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
…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
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).