-
Notifications
You must be signed in to change notification settings - Fork 26.3k
Add per-element unique op for CPU #5503
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
|
On your questions:
|
aten/src/ATen/native/Unique.cpp
Outdated
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
aten/src/ATen/native/Unique.cpp
Outdated
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
aten/src/ATen/native/Unique.cpp
Outdated
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
aten/src/ATen/native/Unique.cpp
Outdated
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
|
Look great, had mostly nits. then in the current See here for an example. EDIT: This is a better example for CPU: https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/native/TensorCompare.cpp |
aten/src/ATen/native/Unique.cpp
Outdated
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
ssnl
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.
This at its current state still needs more work:
- Documentation at
_torch_docs.pyand_tensor_docs.py - Dispatch to other types can be in a later PR, but this will fail with cuda long tensor (probably a segfault). Can you add a cuda version as well?
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
|
I think you accidentally merged instead of rebasing |
|
Fixed merge. Documentations added and exposed unique as function as well. In order to do so, it turns out using On further thought, realized that there's not really a sensible way to do gradients for this, so explicitly declared it as not implemented. Regarding CUDA support, @ssnl - I pinged you, but it seems you're off the grid? In any case, I'd probably prefer to defer that - so is there a way to explicitly warn/catch CUDA usage for more graceful failure than segfault? |
aten/src/ATen/native/Unique.cpp
Outdated
| #include <unordered_map> | ||
| #include <unordered_set> | ||
|
|
||
| #include <iostream> |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
aten/src/ATen/native/Unique.cpp
Outdated
| if (sorted) { | ||
| std::vector<scalar_t> vec(set.begin(), set.end()); | ||
| std::sort(vec.begin(), vec.end()); | ||
| std::copy(vec.begin(), vec.end(), output->data<scalar_t>()); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
| self.assertEqual(empty_inverse, x_inverse) | ||
|
|
||
| x_unique, x_inverse = torch.autograd.Variable.unique( | ||
| x, sorted=True, return_inverse=True) |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
| return_inverse=True, | ||
| ) | ||
| self.assertEqual(torch.ByteTensor([7, 42, 128, 133]), byte_unique) | ||
| self.assertEqual(torch.LongTensor([3, 0, 0, 0, 1, 2]), byte_inverse) |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
torch/_torch_docs.py
Outdated
| - **output** (*Tensor*): the list of unique scalar elements | ||
| - **inverse_indices** (*Tensor*): the indices (same shape as input) | ||
| for where elements in the original input map to in the output | ||
| if ``return_inverse`` is ``True``; otherwise, an empty tensor. |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
|
@theweiho about gradients for |
|
@ssnl - is there some way to use Travis CI (or something else) to test the CUDA part of the code you suggested? @fmassa - that was the way we were considering doing, but not sure that totally makes sense. Attributing the gradient to the first unique element seems a bit arbitrary? (Considering all occurrences of that element "contributes" to the unique equally) I also wasn't sure what a use case for the unique gradient would be, so figured it may make sense to defer it until someone has concrete requirements. |
aten/src/ATen/native/Unique.cpp
Outdated
| const bool return_inverse, | ||
| Tensor* output, | ||
| Tensor* inverse_indices) { | ||
| set_type<scalar_t> set( |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
aten/src/ATen/native/Unique.cpp
Outdated
|
|
||
| if (sorted) { | ||
| AT_DISPATCH_ALL_TYPES(self.type(), "unique", [&] { | ||
| _unique_cpu_template<std::set, scalar_t>( |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
aten/src/ATen/native/cuda/Unique.cu
Outdated
| throw std::runtime_error( | ||
| "unique is currently CPU-only, and lacks CUDA support. " | ||
| "Pull requests welcome!"); | ||
| return std::make_tuple(self.type().tensor({0}), self.type().tensor({0})); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
aten/src/ATen/native/Unique.cpp
Outdated
| } | ||
| for (int i = 0; i < input.numel(); ++i) { | ||
| inverse_indices.data<int64_t>()[i] = | ||
| inverse_map[input.data<scalar_t>()[i]]; |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
aten/src/ATen/native/Unique.cpp
Outdated
| const Tensor& input = self.contiguous(); | ||
| set_type<scalar_t> set( | ||
| input.data<scalar_t>(), input.data<scalar_t>() + input.numel()); | ||
| Tensor output = input.type().tensor({static_cast<long long>(set.size())}); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
| expected_unique.tolist(), sorted(x_unique.tolist())) | ||
| self.assertEqual(empty_inverse, x_inverse) | ||
|
|
||
| x_unique, x_inverse = x.unique(return_inverse=True) |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
aten/src/ATen/native/cuda/Unique.cu
Outdated
| #include "ATen/ATen.h" | ||
|
|
||
| #include <tuple> | ||
| A |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
|
@pytorchbot add to whitelist |
|
@pytorchbot retest this please |
2 similar comments
|
@pytorchbot retest this please |
|
@pytorchbot retest this please |
…o returning a 0-length tensor, per off-line reviewer comments
| x_unique, x_inverse = x.unique(return_inverse=True) | ||
| self.assertEqual( | ||
| expected_unique.tolist(), sorted(x_unique.tolist())) | ||
| self.assertEqual(expected_inverse.numel(), x_inverse.numel()) |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
ezyang
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.
I don't think the tests in the hashing case are correct.
Questions/possible future works:
Testing command:
DEBUG=1 NO_CUDA=1 MACOSX_DEPLOYMENT_TARGET=10.9 CC=clang CXX=clang++ python setup.py build && DEBUG=1 NO_CUDA=1 MACOSX_DEPLOYMENT_TARGET=10.9 CC=clang CXX=clang++ python setup.py develop && python3 test/test_torch.py
Commands to preview generated documentations:
cd docs
pip install -r requirements.txt
make html