-
Notifications
You must be signed in to change notification settings - Fork 26.3k
[RFC] Introduce SobolEngine #10505
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
[RFC] Introduce SobolEngine #10505
Conversation
1. Added the native implementations to ATen 2. Created a basic interface for SobolEngine for Python which needs documentation Todo: - Compile (there is a linking issue - Tests
New developments: - Sequences are not the same - Segmentation fault in the scramble function - Chunking of ltm in scramble throws error when using at::native::where
…nstead of its reverse in cdot_pow2
| return at::mul(inter, bmat).sum(-1); | ||
| } | ||
|
|
||
| /// All definitions below this point are data. These are constant, and should not be modified |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
torch/quasirandom.py
Outdated
| if self.seed is not None: | ||
| g.manual_seed(self.seed) | ||
|
|
||
| self.shift = torch.mv(torch.randint(2, (self.dimension, self.MAXBIT), dtype=torch.float, generator=g), |
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 got the following results in comparison to cython (on my machine!) using the following changes Could someone try to reproduce this? |
|
@cpuhrsch I can confirm this runs much faster now, basically on par with cython: Thanks a lot for digging into this! Looks like ATen just has a ton of overhead here compared to pure C. |
|
OK some more testing shows that the results hold up, and that the samples agree (see below). @vishwakftw, can you incorporate this patch, and also extend the After that I this is ready to go in! import torch
from torch.quasirandom import SobolEngine as TorchSobol
from botorch.qmc.normal import SobolEngineBefore changestngin = TorchSobol(20, scramble=True)
bngin = SobolEngine(20, scramble=True)%timeit tngin.draw(10000)
55.2 ms ± 890 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)%timeit bngin.draw(10000)
387 µs ± 3.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)bngin = SobolEngine(100, scramble=True)
tngin = TorchSobol(100, scramble=True)%timeit tngin.draw(200_000)
1.44 s ± 67.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)%timeit bngin.draw(200_000)
104 ms ± 815 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)Using cpuhrsch's pure C implementationtngin = TorchSobol(20, scramble=True)
bngin = SobolEngine(20, scramble=True)%timeit tngin.draw(10000)
451 µs ± 8.38 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)%timeit bngin.draw(10000)
384 µs ± 2.39 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)bngin = SobolEngine(100, scramble=True)
tngin = TorchSobol(100, scramble=True)%timeit tngin.draw(200_000)
80.8 ms ± 771 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)%timeit bngin.draw(200_000)
105 ms ± 1.54 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)Let's make sure the samples agreetngin = TorchSobol(1, scramble=False)
bngin = SobolEngine(1, scramble=False)tngin.draw(5).view(-1)
tensor([0.5000, 0.7500, 0.2500, 0.3750, 0.8750])bngin.draw(5).flatten()
array([0.5 , 0.75 , 0.25 , 0.375, 0.875])tngin = TorchSobol(4, scramble=False)
bngin = SobolEngine(4, scramble=False)tngin.draw(3)bngin.draw(3)tngin = TorchSobol(4, scramble=True, seed=1234)
bngin = SobolEngine(4, scramble=True, seed=1234)tngin.draw(3)bngin.draw(3) |
|
@cpuhrsch thank you for looking into this, and for providing the benchmark. I was under the impression that TensorAccessor operated on I believe the I am now working on including your changes in the PR. @Balandat thank you for verifying that this works as expected. |
Thank you Christian Puhrsch - Add dtype and out arguments
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.
@Balandat has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
Balandat
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 looks great. Many thanks for all your work on this. This will be super useful.
|
Aside: I do have some utilities ready for transforming the Sobol samples into qMC multivariate normal samples (that can all happen from python). I'll put up a PR for that myself. |
7726187 to
745cd7c
Compare
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.
@Balandat has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
|
@pytorchbot rebase this please |
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.
@Balandat has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
|
Test failures are spurious. |
|
@pytorchbot merge this please |
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.
@ezyang is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
Summary: `SobolEngine` is a quasi-random sampler used to sample points evenly between [0,1]. Here we use direction numbers to generate these samples. The maximum supported dimension for the sampler is 1111. Documentation has been added, tests have been added based on Balandat 's references. The implementation is an optimized / tensor-ized implementation of Balandat 's implementation in Cython as provided in #9332. This closes #9332 . cc: soumith Balandat Pull Request resolved: pytorch/pytorch#10505 Reviewed By: zou3519 Differential Revision: D9330179 Pulled By: ezyang fbshipit-source-id: 01d5588e765b33b06febe99348f14d1e7fe8e55d
Summary: Most of this is actually just copying Sobol over. This is meant to be temporary, the goal is to use the torch native version from pytorch/pytorch#10505 once the performance issues have been resolved. The new content is doing qMC for standard Normal RVs, using the Box-Muller transform. Reviewed By: bletham Differential Revision: D13591551 fbshipit-source-id: cd57745ef837b1a88054bb6a55c760b553c144fa
Summary: Simplify installation (and building of cython). For now this requires both `numpy` and `cython` to be available at setup time. We could also ship generated `.c` files in the furture (see e.g. https://cython.readthedocs.io/en/latest/src/userguide/source_files_and_compilation.html#distributing-cython-modules), but that is low-pri given that we want to move to the torch native Sobol engine from pytorch/pytorch#10505 (if that finally makes its way in...) Reviewed By: bkarrer Differential Revision: D13592395 fbshipit-source-id: 4bd2c7fada88dfad2bffce7c8b31dae3fca47e1f
SobolEngineis a quasi-random sampler used to sample points evenly between [0,1]. Here we use direction numbers to generate these samples. The maximum supported dimension for the sampler is 1111.Documentation has been added, tests have been added based on @Balandat 's references. The implementation is an optimized / tensor-ized implementation of @Balandat 's implementation in Cython as provided in #9332.
This closes #9332 .
cc: @soumith @Balandat