-
Notifications
You must be signed in to change notification settings - Fork 26.3k
[BC-breaking] Shallow-copy indices and values in sparse tensor ctor #20330
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
|
@pytorchbot rebase this please |
|
This is BC breaking and it's never mentioned! |
|
@pytorchbot rebase this please |
|
@pytorchbot rebase this please |
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.
please 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.
what about the version counter? Can we please take a non-default argument to shallow_copy_and_detach for what to do with the version counter? It's troublesome that this API doesn't expose a crucial thing that needs to be considered.
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
811d7fa to
084cfe2
Compare
| /*allow_tensor_metadata_change=*/true)); | ||
| auto values_shallow_copy = Tensor(values.unsafeGetTensorImpl()->shallow_copy_and_detach( | ||
| /*version_counter=*/values.unsafeGetTensorImpl()->version_counter(), | ||
| /*allow_tensor_metadata_change=*/true)); |
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.
We don't set allow_tensor_metadata_change to false here, because we need to be able to resize the sparse tensor in subsequent operations, e.g. in https://github.com/pytorch/pytorch/blob/master/test/test_sparse.py#L1852.
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.
gchanan
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.
can you add a test for the new behavior, please?
| // NOTE: There is no guarantee that `indices` and `values` don't contain AutogradMeta. However, | ||
| // we want to maintain the invariant that `indices_` and `values_` of a sparse tensor don't | ||
| // contain AutogradMeta, and to achieve that we shallow-copy `indices` and `values` here. | ||
| auto indices_shallow_copy = LongTensor(indices.unsafeGetTensorImpl()->shallow_copy_and_detach( |
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'm a little confused about what is going on with the version counter.
Given this change, I'd expect that when I call SparseTensor._values() I get a tensor that shares the version counter with the values that were originally passed in. But that doesn't seem to be the case, either in this PR or previously -- do you know why this is?
Example:
>>> ind=torch.tensor([[0],[1]]).add_(1).sub_(1)
>>> values = torch.tensor([1.]).add_(1).add_(1).sub_(1).sub_(1)
>>> c=torch.sparse_coo_tensor(ind, values)
>>> c._values()._version
0
>>> c._indices()._version
0
>>> c=torch.sparse_coo_tensor(ind, values).coalesce()
>>> c.values()._version
0
>>> c.indices()._version
0
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.
The current implementation of VariableType::_values() makes it so that c._values() shares the same version counter as c. I think this is the right semantics because updating c._values() should also bump the version counter of c.
A related issue is we need to make sure in-place update on the original value tensor values also updates the version counter of the sparse tensor's c's values_ tensor, and it should throw version mismatch error in the backward() operation if the original value tensor is changed (this requires saving the value tensor for backward in the sparse constructor). I added the task in #13638.
test/test_sparse.py
Outdated
| v = torch.ones([1, 2, 3]) | ||
| t = torch.sparse_coo_tensor(i, v, torch.Size([2, 2, 3])) | ||
| v.transpose_(0, 1) | ||
| self.assertEqual(list(t.coalesce().values().size()), [1, 2, 3]) |
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.
what about tests for changing indices?
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.
Added tests for changing indices.
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.
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.
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.
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: (Reopens #20330 and fixes test error.) After the Variable/Tensor merge, there is no guarantee that `indices` and `values` passed into the sparse tensor constructor don't contain AutogradMeta. However, we want to maintain the existing invariant that `indices_` and `values_` of a sparse tensor don't contain AutogradMeta, and to achieve this we need do shallow-copy in the sparse tensor constructor. Note that this is BC-breaking for code that changes the sizes / strides of the indices or values tensor after it's used to create a sparse tensor. In current master, such changes will be reflected in the sparse tensor and break sparse tensor invariants. After this PR, those changes will not be reflected in the sparse tensor, and thus the sparse tensor invariants are always preserved. Specifically, running in-place size/stride-changing ops such as `resize_` / `resize_as_` / `as_strided_` / `set_` / `transpose_` on the original values tensor will not update the sparse tensor's `values_`. For example: ```python # Calling resize_ on non-requires-grad value tensor i2 = torch.zeros([1, 1]) v2 = torch.ones([1, 2, 3]) t2 = torch.sparse_coo_tensor(i2, v2, torch.Size([2, 2, 3])) v2.resize_(4, 5) t2.coalesce().values().size() # On current master, this throws "indices and values must have same nnz, but got nnz from indices: 1, nnz from values: 4", because resizing the original value tensor affects `values_` of the sparse tensor. # After this PR, this prints "torch.Size([1, 2, 3])", which means resizing the original value tensor doesn't affect `values_` of the sparse tensor. ``` Pull Request resolved: #20614 Differential Revision: D15385811 Pulled By: yf225 fbshipit-source-id: e963fcf5e4097f8c881b56145f408565d97cf5c1
Summary: (Reopens pytorch/pytorch#20330 and fixes test error.) After the Variable/Tensor merge, there is no guarantee that `indices` and `values` passed into the sparse tensor constructor don't contain AutogradMeta. However, we want to maintain the existing invariant that `indices_` and `values_` of a sparse tensor don't contain AutogradMeta, and to achieve this we need do shallow-copy in the sparse tensor constructor. Note that this is BC-breaking for code that changes the sizes / strides of the indices or values tensor after it's used to create a sparse tensor. In current master, such changes will be reflected in the sparse tensor and break sparse tensor invariants. After this PR, those changes will not be reflected in the sparse tensor, and thus the sparse tensor invariants are always preserved. Specifically, running in-place size/stride-changing ops such as `resize_` / `resize_as_` / `as_strided_` / `set_` / `transpose_` on the original values tensor will not update the sparse tensor's `values_`. For example: ```python # Calling resize_ on non-requires-grad value tensor i2 = torch.zeros([1, 1]) v2 = torch.ones([1, 2, 3]) t2 = torch.sparse_coo_tensor(i2, v2, torch.Size([2, 2, 3])) v2.resize_(4, 5) t2.coalesce().values().size() # On current master, this throws "indices and values must have same nnz, but got nnz from indices: 1, nnz from values: 4", because resizing the original value tensor affects `values_` of the sparse tensor. # After this PR, this prints "torch.Size([1, 2, 3])", which means resizing the original value tensor doesn't affect `values_` of the sparse tensor. ``` Pull Request resolved: pytorch/pytorch#20614 Differential Revision: D15385811 Pulled By: yf225 fbshipit-source-id: e963fcf5e4097f8c881b56145f408565d97cf5c1
After the Variable/Tensor merge, there is no guarantee that
indicesandvaluespassed into the sparse tensor constructor don't contain AutogradMeta. However, we want to maintain the existing invariant thatindices_andvalues_of a sparse tensor don't contain AutogradMeta, and to achieve this we need do shallow-copy in the sparse tensor constructor.Note that this is BC-breaking for code that changes the sizes / strides of the indices or values tensor after it's used to create a sparse tensor. In current master, such changes will be reflected in the sparse tensor and break sparse tensor invariants. After this PR, those changes will not be reflected in the sparse tensor, and thus the sparse tensor invariants are always preserved. Specifically, running in-place size/stride-changing ops such as
resize_/resize_as_/as_strided_/set_/transpose_on the original values tensor will not update the sparse tensor'svalues_. For example: