[MRG] Add QSW sampling for sliced Wasserstein - #838
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #838 +/- ##
==========================================
+ Coverage 96.86% 96.88% +0.01%
==========================================
Files 128 128
Lines 25972 26137 +165
==========================================
+ Hits 25158 25322 +164
- Misses 814 815 +1 🚀 New features to boost your workflow:
|
clbonet
left a comment
There was a problem hiding this comment.
Thank you @Samuel-Vangu for the great PR! Overall the code is great.
About the name of the method in "sampling_slices", I am wondering whether we should put something more precised than "qsw". The generalized_spiral seems to be the fastest method, but maybe we would like to add other Quasi Monte-Carlo methods in the future such as the minimization of the Coulomb energy or something else. Thus, I think we should put something more precised, e.g. "spiral_qmc"?
Also, for the randomized option. Since it can be applied to any Quasi-Monte Carlo method, maybe it should be "randomized_spiral_qmc", and we can get the boolean with checking "randomized" in sampling_slices?
What do you think @Samuel-Vangu, @rflamary ?
Otherwise, I have few minor comments below.
|
|
||
|
|
||
| def get_projections_spiral( | ||
| d, n_projections, randomized=True, seed=None, backend=None, type_as=None |
There was a problem hiding this comment.
Generalized spirals are only valid for d==3, so maybe we don't need d here
| if d != 3: | ||
| raise ValueError( | ||
| f"get_projections_spiral is only implemented for d=3, got d={d}" | ||
| ) |
| # sin/cos are not exposed by the backend abstraction (only arccos, atan2 | ||
| # exist), so the deterministic point construction is done in plain NumPy | ||
| # and converted to the target backend at the end. |
There was a problem hiding this comment.
You can add sin and cos to the backend and use nx instead of np
|
Hi @clbonet, Thanks for the detailed review! Here's a summary of what I changed in response to each point: Naming ( Missing reference
sin/cos on the backend RELEASES.md
Let me know if any of these choices don't sit right. |
clbonet
left a comment
There was a problem hiding this comment.
Thank you @Samuel-Vangu. A last small comment, if you add sin and cos to the backend, can you also please add the tests.
…Vangu/POT into feature/add-qsw-sampling
|
Hi @clbonet , Added sin/cos coverage to both test_empty_backend and test_func_backends, |
rflamary
left a comment
There was a problem hiding this comment.
Hello @Samuel-Vangu
Thanks for the contribution. I detected a few remeianing somments thta need sto be adressed but we are close to merging the PR.
|
|
||
| results = {} | ||
| projections_by_backend = {} | ||
| for nx in backends: |
There was a problem hiding this comment.
no loop inside the etsts please pass nx as a parameter of the functin and pytest will loop over available backends
| X_t = rng.normal(1, 1, (30, d)) | ||
|
|
||
| results = {} | ||
| for nx in backends: |
| mean_uniform_error = np.mean(uniform_errors) | ||
| mean_rqsw_error = np.mean(rqsw_errors) | ||
|
|
||
| print(f"\n[DEBUG] mean uniform error={mean_uniform_error:.6e}") |
There was a problem hiding this comment.
remove the debugging print
| if not randomized: | ||
| return theta | ||
|
|
||
| if isinstance(seed, np.random.RandomState) and str(nx) == "numpy": |
There was a problem hiding this comment.
this test should not be there, nx.seed and nx.randn shoudl work with numpy backend too
…n the last review
|
Hi @rflamary, addressed all three test/sliced/test_sliced_distances.py On the import numpy as np
rng_self = np.random.RandomState()
rng_passed = np.random.RandomState(42)
rng_self.seed(rng_passed)
# TypeError: Cannot cast scalar from dtype('O') to dtype('int64')
# according to the rule 'safe'So the generic |
|
Hello @Samuel-Vangu thanks for the fixeds. About nx.seed : if it breaks then it means that we need to fix the numpy backend (and do the test in the nx.seed function). We need a backend that can run this without if/then tests. Coiuld you do that please? And thank you for identifying this bug. |
|
@rflamary , I'd rather open a follow-up PR for the actual fix -- ot/backend.py is |
|
OK we can merge but please before open an issue with precise description of what needs to be done and where (and hopefully indeed do the PR after ;) ). The whole point of the backend is to have shared code and this is a bug so it should be listed in Issues. |
|
@Samuel-Vangu Don't forget to add your name in the Contributors file. |
|
Hi @clbonet , Added my name to CONTRIBUTORS.md. |
Types of changes
Motivation and context / Related issue
Closes #835
This PR adds Quasi-Monte Carlo (QMC) sampling of projection directions to the Sliced Wasserstein module.
Currently,
sliced_wasserstein_distancesamples projection directions uniformly at random, corresponding to standard Monte Carlo sampling. This PR adds two alternatives based on the generalized spiral point construction described in [Nguyen, Bariletto & Ho (2024)](https://arxiv.org/abs/2309.11713):sampling_slices="qsw": deterministic Quasi-Sliced Wasserstein (QSW) projection directions.sampling_slices="rqsw": Randomized QSW (RQSW), obtained by applying a random rotation to the deterministic spiral point set.The new sampling methods are currently limited to 3D, while the existing
"uniform"sampling remains the default.The implementation also exposes
get_projections_spiraland updates the documentation, README references, release notes, and adds a 3D example.How has this been tested (if it applies)
The changes have been tested with:
pre-commit run --all-files— all checks pass.pytest test/sliced/test_sliced_distances.py— 62 tests passed.Added tests covering:
PR checklist