polystep 0.12.0__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {polystep-0.12.0 → polystep-1.0.0}/CHANGELOG.md +38 -0
- {polystep-0.12.0 → polystep-1.0.0}/CITATION.cff +4 -4
- polystep-1.0.0/CONTRIBUTING.md +65 -0
- {polystep-0.12.0 → polystep-1.0.0}/LIMITATIONS.md +49 -25
- {polystep-0.12.0 → polystep-1.0.0}/PKG-INFO +52 -39
- {polystep-0.12.0 → polystep-1.0.0}/README.md +48 -32
- polystep-1.0.0/docs/api_overview.md +390 -0
- polystep-1.0.0/docs/determinism.md +61 -0
- polystep-1.0.0/docs/performance.md +237 -0
- polystep-1.0.0/docs/reproducibility.md +152 -0
- {polystep-0.12.0 → polystep-1.0.0}/pyproject.toml +5 -11
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/__init__.py +5 -48
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/_compiled.py +17 -54
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/_serialization.py +30 -77
- polystep-1.0.0/src/polystep/_step_blockwise.py +360 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/_step_core.py +74 -15
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/_step_momentum.py +1 -9
- polystep-1.0.0/src/polystep/_step_monolithic.py +1084 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/adaptive_subspace.py +42 -59
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/api.py +15 -26
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/ask_tell.py +9 -8
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/baselines/core.py +9 -13
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/baselines/methods.py +22 -32
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/benchmarks/__init__.py +0 -2
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/benchmarks/rl/cartpole.py +8 -59
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/benchmarks/rl/gym_evaluator.py +46 -49
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/benchmarks/rl/policies.py +0 -2
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/benchmarks/utils.py +20 -30
- polystep-1.0.0/src/polystep/blockwise.py +135 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/cost_nn.py +649 -306
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/costs.py +15 -14
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/dynamics.py +0 -2
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/epsilon.py +23 -7
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/factored_subspace.py +9 -19
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/geometry.py +16 -36
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/hybrid_subspace.py +89 -178
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/layers/attention.py +9 -8
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/optimizer.py +275 -548
- polystep-1.0.0/src/polystep/projection/sparse.py +249 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/solver.py +52 -94
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/solvers/__init__.py +0 -2
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/solvers/_shared.py +40 -45
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/solvers/base.py +8 -2
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/solvers/greedy.py +12 -30
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/solvers/kl_softmax.py +31 -31
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/solvers/sinkhorn.py +30 -67
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/solvers/softmax.py +16 -3
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/subspace.py +21 -2
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/transform.py +4 -13
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep.egg-info/PKG-INFO +52 -39
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep.egg-info/SOURCES.txt +1 -11
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep.egg-info/requires.txt +2 -5
- {polystep-0.12.0 → polystep-1.0.0}/tests/conftest.py +17 -97
- polystep-1.0.0/tests/test_ablation_solvers.py +214 -0
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_adaptive_subspace.py +297 -37
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_amortization.py +98 -41
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_api.py +91 -68
- polystep-1.0.0/tests/test_ask_tell.py +172 -0
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_baseline_fairness.py +70 -145
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_baselines.py +87 -24
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_benchmarks.py +2 -2
- polystep-1.0.0/tests/test_biased_rotation.py +145 -0
- polystep-1.0.0/tests/test_blockwise.py +330 -0
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_candidate_autocast.py +5 -7
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_checkpoint_resume.py +94 -91
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_compiled.py +47 -16
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_controlled.py +1 -6
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_cost_nn.py +124 -34
- polystep-1.0.0/tests/test_costs.py +134 -0
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_determinism.py +15 -14
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_dfo.py +403 -91
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_diagnostics.py +6 -6
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_dynamics.py +1 -1
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_end_to_end_learning.py +2 -42
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_epsilon.py +73 -22
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_evaluator_compile_forward.py +14 -1
- polystep-1.0.0/tests/test_factored_subspace.py +226 -0
- polystep-1.0.0/tests/test_fastpath_parity.py +426 -0
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_fused_projection.py +15 -19
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_geometry.py +40 -41
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_hybrid_subspace.py +237 -120
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_input_validation.py +71 -33
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_integration.py +44 -48
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_kl_softmax.py +69 -8
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_layers.py +159 -14
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_math_guards.py +87 -47
- polystep-1.0.0/tests/test_mixed_precision.py +779 -0
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_mnist.py +71 -38
- polystep-1.0.0/tests/test_no_test_set_leakage.py +105 -0
- polystep-1.0.0/tests/test_nondiff_data.py +86 -0
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_nondiff_models.py +2 -146
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_numerical_stress.py +5 -56
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_objectives.py +16 -42
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_optimizer.py +369 -303
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_per_sample.py +2 -2
- polystep-1.0.0/tests/test_practical.py +65 -0
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_probe_jitter.py +79 -33
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_quadratic_model.py +101 -83
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_rl_benchmarks.py +156 -4
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_search_experiments.py +56 -3
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_sequential_fast_path.py +30 -34
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_sinkhorn.py +124 -94
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_sinkhorn_numerics.py +19 -8
- polystep-1.0.0/tests/test_site_vmap.py +1192 -0
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_softmax.py +38 -66
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_softmax_integration.py +18 -46
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_sparse_delta_evaluator.py +127 -31
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_sparse_projection.py +115 -30
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_subspace_blockwise.py +132 -190
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_subspace_contract.py +14 -39
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_subspace_delta.py +67 -65
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_subspace_gain.py +2 -2
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_timeseries_val_selection.py +5 -9
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_transform.py +112 -12
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_trust_region.py +110 -55
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_tuning_sweep.py +60 -71
- polystep-0.12.0/CONTRIBUTING.md +0 -47
- polystep-0.12.0/docs/api_overview.md +0 -217
- polystep-0.12.0/docs/determinism.md +0 -31
- polystep-0.12.0/docs/performance.md +0 -129
- polystep-0.12.0/docs/reproducibility.md +0 -75
- polystep-0.12.0/src/polystep/_step_blockwise.py +0 -648
- polystep-0.12.0/src/polystep/_step_monolithic.py +0 -1295
- polystep-0.12.0/src/polystep/blockwise.py +0 -276
- polystep-0.12.0/src/polystep/cma.py +0 -117
- polystep-0.12.0/src/polystep/cma_subspace.py +0 -95
- polystep-0.12.0/src/polystep/projection/sparse.py +0 -208
- polystep-0.12.0/src/polystep/solvers/tempered_softmax.py +0 -31
- polystep-0.12.0/tests/test_ablation_solvers.py +0 -282
- polystep-0.12.0/tests/test_ask_tell.py +0 -100
- polystep-0.12.0/tests/test_biased_rotation.py +0 -82
- polystep-0.12.0/tests/test_blockwise.py +0 -219
- polystep-0.12.0/tests/test_cma.py +0 -319
- polystep-0.12.0/tests/test_cma_subspace.py +0 -380
- polystep-0.12.0/tests/test_costs.py +0 -63
- polystep-0.12.0/tests/test_evaluator_regressions.py +0 -303
- polystep-0.12.0/tests/test_factored_subspace.py +0 -107
- polystep-0.12.0/tests/test_fastpath_parity.py +0 -168
- polystep-0.12.0/tests/test_mixed_precision.py +0 -496
- polystep-0.12.0/tests/test_no_test_set_leakage.py +0 -165
- polystep-0.12.0/tests/test_nondiff_data.py +0 -151
- polystep-0.12.0/tests/test_practical.py +0 -41
- polystep-0.12.0/tests/test_regressions.py +0 -1105
- polystep-0.12.0/tests/test_silent_failures.py +0 -744
- polystep-0.12.0/tests/test_site_vmap.py +0 -382
- polystep-0.12.0/tests/test_sweep_protocol.py +0 -214
- polystep-0.12.0/tests/test_vmap_layer_compatibility.py +0 -239
- {polystep-0.12.0 → polystep-1.0.0}/LICENSE +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/MANIFEST.in +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/setup.cfg +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/baselines/__init__.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/benchmarks/rl/__init__.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/benchmarks/rl/metrics.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/benchmarks/threads.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/layers/__init__.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/layers/rnn.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/objectives/__init__.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/objectives/base.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/objectives/synthetic.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/projection/__init__.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/py.typed +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep/quadratic_model.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep.egg-info/dependency_links.txt +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/src/polystep.egg-info/top_level.txt +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/tests/__init__.py +0 -0
- {polystep-0.12.0 → polystep-1.0.0}/tests/test_sparse_integration.py +0 -0
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.0 - 2026-10-13
|
|
4
|
+
|
|
5
|
+
### Upgrade notes
|
|
6
|
+
|
|
7
|
+
- Use `PolyStepOptimizer` for neural networks and `PolyStep` for standalone objectives.
|
|
8
|
+
- Replace diagonal CMA with `AdaptiveSubspace`, tempered softmax with `SoftmaxSolver`,
|
|
9
|
+
and `auto_epsilon` with `ProgressiveEpsilon`. Probe reuse has been removed.
|
|
10
|
+
- Checkpoints use format 6. Rebuild the optimizer from saved model weights when
|
|
11
|
+
upgrading from 0.13; older optimizer checkpoints cannot be loaded.
|
|
12
|
+
- Some low-level exports and experiment helpers moved or were removed. The
|
|
13
|
+
[migration guide](docs/api_overview.md#upgrading-from-013) lists replacements and
|
|
14
|
+
changes to evaluation, configuration, and callbacks.
|
|
15
|
+
|
|
16
|
+
### Fixes
|
|
17
|
+
|
|
18
|
+
- Preserve live model weights, buffers, momentum, and trust-region state across
|
|
19
|
+
evaluation, subspace updates, and checkpoint restoration.
|
|
20
|
+
- Handle nonfinite costs, tiny transport rows, integer losses, and half-precision
|
|
21
|
+
reductions consistently. Sparse CUDA projections repeat in deterministic mode.
|
|
22
|
+
- Accept device strings in rotation sampling and float32 masks in half-precision
|
|
23
|
+
CUDA attention.
|
|
24
|
+
- Correct baseline budgets, tied ranks, rollout accounting, and download handling.
|
|
25
|
+
|
|
26
|
+
### Performance and examples
|
|
27
|
+
|
|
28
|
+
- Reuse unchanged forward work, update only affected weights, and size candidate
|
|
29
|
+
chunks from measured activations. Speed up blockwise, factored, and adaptive steps.
|
|
30
|
+
- Reduce sparse projection storage and host synchronization; compile Sinkhorn loops.
|
|
31
|
+
- Refresh all 11 examples, their evaluation paths, and their documented settings.
|
|
32
|
+
See [performance](docs/performance.md) for measurements and tradeoffs.
|
|
33
|
+
- Consolidate redundant tests and keep release validation focused on the built wheel.
|
|
34
|
+
|
|
35
|
+
## 0.13.0 - 2026-09-22
|
|
36
|
+
|
|
37
|
+
- Fix KL row mass, nonfinite inputs, evaluator hooks, and chunk handling.
|
|
38
|
+
- Reuse shared MLP forward work and load only requested MNIST images.
|
|
39
|
+
- Fix example checkpoint selection and evaluation budgets; trim demo dependencies.
|
|
40
|
+
|
|
3
41
|
## 0.12.0 - 2026-09-17
|
|
4
42
|
|
|
5
43
|
- Fix cross-entropy targets, stale caches, attention masks, nonfinite best values,
|
|
@@ -6,8 +6,8 @@ authors:
|
|
|
6
6
|
- family-names: Le
|
|
7
7
|
given-names: An T.
|
|
8
8
|
license: Apache-2.0
|
|
9
|
-
version: 0.
|
|
10
|
-
date-released: "2026-
|
|
9
|
+
version: 1.0.0
|
|
10
|
+
date-released: "2026-10-13"
|
|
11
11
|
repository-code: "https://github.com/anindex/polystep"
|
|
12
12
|
keywords:
|
|
13
13
|
- gradient-free optimization
|
|
@@ -22,9 +22,9 @@ preferred-citation:
|
|
|
22
22
|
authors:
|
|
23
23
|
- family-names: Le
|
|
24
24
|
given-names: An T.
|
|
25
|
-
journal: "
|
|
25
|
+
journal: "Transactions on Machine Learning Research"
|
|
26
26
|
year: 2026
|
|
27
|
-
url: "https://
|
|
27
|
+
url: "https://openreview.net/forum?id=8mlcqTTMuU"
|
|
28
28
|
references:
|
|
29
29
|
- type: conference-paper
|
|
30
30
|
title: "Accelerating Motion Planning via Optimal Transport"
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Install the development dependencies. Then run the CI checks:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install -e ".[dev]"
|
|
7
|
+
ruff check .
|
|
8
|
+
ruff format --check .
|
|
9
|
+
pytest tests/ -q -n auto
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Work on a branch. Add a regression test when the change needs one.
|
|
13
|
+
Open a pull request after the checks pass. Test observable behavior.
|
|
14
|
+
Keep one small regression test per bug.
|
|
15
|
+
Extend an existing case when it already covers the same path; avoid separate tests
|
|
16
|
+
for trivial defaults, getters, or repeated shapes. Keep comments specific and public
|
|
17
|
+
APIs typed.
|
|
18
|
+
|
|
19
|
+
## Tests
|
|
20
|
+
|
|
21
|
+
The default suite excludes `slow` and `gpu` tests. To select them:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pytest tests/ -m slow
|
|
25
|
+
pytest tests/ -m gpu
|
|
26
|
+
pytest tests/ -m ""
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The fast suite uses one CPU thread; `POLYSTEP_TEST_THREADS` overrides it. Slow tests
|
|
30
|
+
use `ncpu - 8` threads, clamped to 2-16, and may download datasets. Keep downloads
|
|
31
|
+
and training-quality checks in the slow suite; use synthetic inputs for unit tests.
|
|
32
|
+
Tests importing `experiments/` must skip when that directory is absent, since it is
|
|
33
|
+
excluded from distributions.
|
|
34
|
+
|
|
35
|
+
Pushes and pull requests test Python 3.11 with PyTorch 2.8 and Python 3.14 with
|
|
36
|
+
current PyTorch. Scheduled and manual runs add Python 3.12/3.13, coverage, real-data
|
|
37
|
+
learning checks, and the shipped tests against the installed wheel. Every run
|
|
38
|
+
builds both distributions and checks the wheel's imports and type marker.
|
|
39
|
+
|
|
40
|
+
## Releases
|
|
41
|
+
|
|
42
|
+
Update `polystep.__version__`. Set the same version and the release date in
|
|
43
|
+
`CITATION.cff`. Add a `CHANGELOG.md` entry with the heading `## X.Y.Z - YYYY-MM-DD`.
|
|
44
|
+
`pyproject.toml` reads the package version automatically.
|
|
45
|
+
If the project's maturity changes, update its `Development Status` classifier.
|
|
46
|
+
|
|
47
|
+
Build the distributions. Then check their metadata:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uv build
|
|
51
|
+
uvx twine check --strict dist/*
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Run the full manual CI workflow on the release commit.
|
|
55
|
+
This covers the Python matrix and repository-only experiment tests.
|
|
56
|
+
After CI passes, publish a GitHub Release with the tag `vX.Y.Z`.
|
|
57
|
+
This triggers the PyPI workflow. The workflow checks version consistency, lint, and
|
|
58
|
+
package metadata. It tests the installed wheel before it publishes the package.
|
|
59
|
+
Only the separate publish job has OIDC permission; it uses the `pypi` environment
|
|
60
|
+
and PyPI Trusted Publishing.
|
|
61
|
+
|
|
62
|
+
## Issues
|
|
63
|
+
|
|
64
|
+
Include a minimal reproduction, the traceback, Python and PyTorch versions, and
|
|
65
|
+
hardware details relevant to the failure.
|
|
@@ -13,33 +13,46 @@ projection do not apply to those columns.
|
|
|
13
13
|
`FactoredSubspace` restricts perturbations to the input directions in its fixed
|
|
14
14
|
factor. Rotation changes those directions. Retune radii when switching subspaces.
|
|
15
15
|
|
|
16
|
-
Momentum
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
`trace(C) = n`. Its default `mu_eff=1` gives rank-one adaptation only. Cumulative
|
|
23
|
-
step-size adaptation is not implemented.
|
|
16
|
+
Momentum, the `amortize_steps` coasting direction, and the `biased_rotation`
|
|
17
|
+
direction are cleared when the basis changes. `AdaptiveSubspace` rotates every step
|
|
18
|
+
by default. These options need a longer rotation interval to take effect.
|
|
19
|
+
The optimizer warns when you combine them with rotation on every step.
|
|
20
|
+
Heavy-ball momentum can amplify the barycentric displacement.
|
|
21
|
+
`step_radius` bounds the displacement before momentum.
|
|
24
22
|
|
|
25
23
|
## Evaluation
|
|
26
24
|
|
|
27
25
|
- `step()` expects `closure(batched_params) -> losses` with shape `(N,)`.
|
|
26
|
+
The candidate tensors may share storage that the next chunk overwrites, so clone
|
|
27
|
+
any you keep after the closure returns.
|
|
28
28
|
- Manual loops must register the evaluator and current batch to enable fast paths.
|
|
29
29
|
The evaluator and closure must compute the same objective.
|
|
30
|
+
- `NNCostEvaluator` and `train()` score candidates in eval mode: dropout is off and
|
|
31
|
+
batch-norm running statistics never update. A custom closure that runs the model in
|
|
32
|
+
train mode compares candidates under different dropout masks.
|
|
30
33
|
- Mixed-dtype models require `HybridSubspace` or `FactoredSubspace`. Full-space and
|
|
31
34
|
global-subspace coordinates use one dtype and reject mixed parameter dtypes.
|
|
32
35
|
- `mixed_precision=True` uses BF16 geometry and forwards; solver costs use FP32.
|
|
33
|
-
Models needing autocast internally must provide it.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
-
|
|
36
|
+
Models needing autocast internally must provide it. Half-precision candidate outputs
|
|
37
|
+
reduce in FP32 only under the builtin cross-entropy, MSE and L1 losses at their
|
|
38
|
+
defaults apart from `reduction`. Other losses may round nearby candidate scores
|
|
39
|
+
to the same value. With FP16 or BF16 parameters, `FactoredSubspace` materializes
|
|
40
|
+
every candidate and runs slower. See
|
|
41
|
+
[precision](docs/performance.md#compilation-and-precision).
|
|
42
|
+
- `train()` rejects `trust_region`. See
|
|
43
|
+
[radius control](docs/api_overview.md#quadratic-model-and-radius-control) for its
|
|
44
|
+
manual-step use.
|
|
45
|
+
- `trust_region` and `use_adaptive_radius` both scale the step. Choose one; the
|
|
46
|
+
optimizer warns when both are on.
|
|
39
47
|
- Multi-fidelity screening imputes dropped costs using an additive offset. This can
|
|
40
|
-
bias the full-fidelity cost estimate
|
|
41
|
-
-
|
|
42
|
-
options warn at construction.
|
|
48
|
+
bias the full-fidelity cost estimate.
|
|
49
|
+
- Full-space blockwise mode does not support every monolithic adaptation option;
|
|
50
|
+
unsupported options warn at construction.
|
|
51
|
+
- Automatic chunk sizing counts outputs of layers with parameters. On a site-local
|
|
52
|
+
path, it counts all module outputs from the perturbed layer onward, provided the
|
|
53
|
+
forward neither draws random numbers nor reads the perturbed parameter before
|
|
54
|
+
calling its layer. Attention scores and other temporary tensors inside a module's
|
|
55
|
+
forward are not counted. Set `chunk_size` by hand if such a model runs out of memory.
|
|
43
56
|
- The library does not distribute optimizer state across multiple GPUs.
|
|
44
57
|
|
|
45
58
|
## Attention and recurrent layers
|
|
@@ -53,9 +66,7 @@ Boolean masks use `True` for masked positions; float masks are additive. Attenti
|
|
|
53
66
|
masks accept `(query, key)`, `(batch * heads, query, key)`, and broadcastable 4D shapes.
|
|
54
67
|
The wrapper also accepts `(batch, query, key)` masks.
|
|
55
68
|
|
|
56
|
-
CPU
|
|
57
|
-
may emit a batching-fallback warning. Evaluate dropout layers in `model.eval()` mode
|
|
58
|
-
for deterministic candidate comparisons.
|
|
69
|
+
CPU vmap may emit a batching-fallback warning.
|
|
59
70
|
|
|
60
71
|
[`VmapSafeLSTM`](src/polystep/layers/rnn.py) requires batch-first dense inputs. It does
|
|
61
72
|
not support bidirectional recurrence, projection, or `PackedSequence`. Its explicit
|
|
@@ -70,10 +81,22 @@ a common direction across particles.
|
|
|
70
81
|
|
|
71
82
|
Sinkhorn requires `omega` in `[0.5, 1.95]`. Anderson acceleration and adaptive omega
|
|
72
83
|
are inactive in fixed-iteration mode (`threshold <= 0`). Both solver families promote
|
|
73
|
-
FP16/BF16 costs to FP32.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
84
|
+
FP16/BF16 costs to FP32. Cost differences and reductions must also fit the solver's
|
|
85
|
+
dtype: finite FP32 inputs near its limits can still overflow when recentered or
|
|
86
|
+
averaged. Rescale the objective before evaluation or return FP64 costs in that case.
|
|
87
|
+
|
|
88
|
+
All nonfinite costs are invalid. `min_cost_greedy` and `top_k_mean` skip a vertex
|
|
89
|
+
with any nonfinite probe, and the solve leaves a particle with no feasible vertex
|
|
90
|
+
where it is. The weighted solvers replace each nonfinite cost with twice the largest
|
|
91
|
+
finite magnitude plus one, clamped to the dtype limit. An infeasible candidate can
|
|
92
|
+
therefore retain weight, depending on epsilon. With `scale_cost='mean'` or
|
|
93
|
+
`'max_cost'`, the solvers compute the penalty after scaling. Otherwise, that weight
|
|
94
|
+
also depends on the cost offset.
|
|
95
|
+
Balanced Sinkhorn sends every column its prescribed mass, even when all of that
|
|
96
|
+
column's candidates are infeasible. The monolithic step records a vertex's cost as
|
|
97
|
+
the mean of its probes with each nonfinite probe already penalized, so with several
|
|
98
|
+
probes a vertex with only some nonfinite probes can still set the best-vertex
|
|
99
|
+
progress that drives the adaptive radius.
|
|
77
100
|
|
|
78
101
|
Quadratic fits are finite-radius models. Simplex gradients can be biased on
|
|
79
102
|
anisotropic quadratics, and block models omit cross-block curvature. A fit does not
|
|
@@ -89,4 +112,5 @@ The SNN surrogate-gradient baseline has substantial variation across seeds. MAX-
|
|
|
89
112
|
search heuristics use flip budgets, which are not equivalent to neural candidate
|
|
90
113
|
budgets. Head-only GPT-2 experiments do not establish full-model fine-tuning results.
|
|
91
114
|
|
|
92
|
-
|
|
115
|
+
The [reproducibility guide](docs/reproducibility.md#protocol) gives the protocols, and the
|
|
116
|
+
[experiment index](experiments/EXPERIMENT_INDEX.md) has the results.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: polystep
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: PyTorch PolyStep Optimizer - gradient-free neural network training via entropic optimal transport
|
|
5
5
|
Author: An T. Le
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -10,7 +10,7 @@ Project-URL: Documentation, https://github.com/anindex/polystep/blob/main/docs/a
|
|
|
10
10
|
Project-URL: Changelog, https://github.com/anindex/polystep/blob/main/CHANGELOG.md
|
|
11
11
|
Project-URL: Issues, https://github.com/anindex/polystep/issues
|
|
12
12
|
Keywords: pytorch,optimal-transport,gradient-free,sinkhorn,polystep,optimization,neural-network
|
|
13
|
-
Classifier: Development Status ::
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
|
15
15
|
Classifier: Intended Audience :: Developers
|
|
16
16
|
Classifier: Operating System :: OS Independent
|
|
@@ -27,13 +27,12 @@ License-File: LICENSE
|
|
|
27
27
|
Requires-Dist: torch>=2.8
|
|
28
28
|
Provides-Extra: examples
|
|
29
29
|
Requires-Dist: numpy>=2.0; extra == "examples"
|
|
30
|
-
Requires-Dist: torchvision>=0.25; extra == "examples"
|
|
31
30
|
Requires-Dist: matplotlib>=3.8; extra == "examples"
|
|
32
31
|
Requires-Dist: Pillow>=10.0; extra == "examples"
|
|
33
32
|
Requires-Dist: gymnasium[classic-control]>=0.29; extra == "examples"
|
|
34
|
-
Requires-Dist: python-sat; extra == "examples"
|
|
35
33
|
Provides-Extra: dev
|
|
36
34
|
Requires-Dist: numpy>=2.0; extra == "dev"
|
|
35
|
+
Requires-Dist: setuptools>=77; extra == "dev"
|
|
37
36
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
38
37
|
Requires-Dist: pytest-timeout>=2.2; extra == "dev"
|
|
39
38
|
Requires-Dist: pytest-rerunfailures>=14.0; extra == "dev"
|
|
@@ -46,14 +45,12 @@ Requires-Dist: pandas>=2.0; extra == "experiments"
|
|
|
46
45
|
Requires-Dist: python-sat; extra == "experiments"
|
|
47
46
|
Requires-Dist: torchvision>=0.25; extra == "experiments"
|
|
48
47
|
Requires-Dist: cma>=3.3; extra == "experiments"
|
|
49
|
-
Requires-Dist: snntorch>=0.7; extra == "experiments"
|
|
50
48
|
Requires-Dist: datasets>=2.14; extra == "experiments"
|
|
51
49
|
Requires-Dist: transformers>=4.40; extra == "experiments"
|
|
52
50
|
Requires-Dist: gymnasium>=0.29; extra == "experiments"
|
|
53
51
|
Provides-Extra: rl
|
|
54
|
-
Requires-Dist: gymnasium
|
|
52
|
+
Requires-Dist: gymnasium>=0.29; extra == "rl"
|
|
55
53
|
Requires-Dist: stable-baselines3>=2.3; extra == "rl"
|
|
56
|
-
Requires-Dist: swig>=4.2; extra == "rl"
|
|
57
54
|
Dynamic: license-file
|
|
58
55
|
|
|
59
56
|
# polystep
|
|
@@ -66,6 +63,8 @@ Dynamic: license-file
|
|
|
66
63
|
|
|
67
64
|
Gradient-free neural network training via optimal transport.
|
|
68
65
|
|
|
66
|
+
Accepted at [Transactions on Machine Learning Research (TMLR)](https://openreview.net/forum?id=8mlcqTTMuU).
|
|
67
|
+
|
|
69
68
|
PolyStep evaluates finite-radius parameter perturbations and updates parameters
|
|
70
69
|
through a weighted barycenter. It supports spiking networks, quantized layers, hard
|
|
71
70
|
routing, and other models without useful gradients. For differentiable models,
|
|
@@ -73,20 +72,19 @@ backpropagation is usually faster.
|
|
|
73
72
|
|
|
74
73
|
[Paper](https://arxiv.org/abs/2605.01928) ·
|
|
75
74
|
[Interactive visualization](https://vietngth.github.io/polystep-visualization/) ·
|
|
76
|
-
[API reference](docs/api_overview.md)
|
|
75
|
+
[API reference](https://github.com/anindex/polystep/blob/main/docs/api_overview.md) ·
|
|
76
|
+
[Julia package](https://github.com/anindex/PolyStep.jl)
|
|
77
77
|
|
|
78
78
|
<p align="center">
|
|
79
79
|
<img src="https://raw.githubusercontent.com/anindex/polystep/main/docs/figures/method_diagram.png" width="840"
|
|
80
|
-
alt="PolyStep:
|
|
80
|
+
alt="PolyStep: search coordinates, polytope probes, cost evaluation, soft assignment, and a barycentric update.">
|
|
81
81
|
</p>
|
|
82
82
|
|
|
83
|
-
> Want to play around with parameters? [**Viet T. Nguyen**](https://vietngth.github.io/) built a gorgeous interactive walkthrough that animates every step of the method -> **[explore the PolyStep visualization](https://vietngth.github.io/polystep-visualization/)**.
|
|
84
|
-
|
|
85
83
|
## Installation
|
|
86
84
|
|
|
87
85
|
```bash
|
|
88
86
|
pip install polystep
|
|
89
|
-
pip install "polystep[examples]" #
|
|
87
|
+
pip install "polystep[examples]" # dependencies for the repository's examples
|
|
90
88
|
```
|
|
91
89
|
|
|
92
90
|
Python 3.11+ and PyTorch 2.8+ are required. Choose a CUDA build compatible with your
|
|
@@ -99,8 +97,7 @@ For development, install `pip install -e ".[dev]"` from a checkout.
|
|
|
99
97
|
import torch
|
|
100
98
|
from torch import nn
|
|
101
99
|
from torch.utils.data import DataLoader, TensorDataset
|
|
102
|
-
from polystep import HybridSubspace, PolyStepOptimizer, TrainConfig, train
|
|
103
|
-
from polystep.transform import ParamLayout
|
|
100
|
+
from polystep import HybridSubspace, ParamLayout, PolyStepOptimizer, TrainConfig, train
|
|
104
101
|
|
|
105
102
|
model = nn.Sequential(nn.Linear(16, 32), nn.ReLU(), nn.Linear(32, 3))
|
|
106
103
|
loader = DataLoader(
|
|
@@ -114,10 +111,11 @@ optimizer = PolyStepOptimizer(model, subspace=subspace, solver="softmax")
|
|
|
114
111
|
train(model, loader, nn.CrossEntropyLoss(), optimizer, TrainConfig(epochs=5))
|
|
115
112
|
```
|
|
116
113
|
|
|
117
|
-
Replace the generated data with your dataset.
|
|
118
|
-
|
|
119
|
-
`train()` does this automatically. See
|
|
120
|
-
|
|
114
|
+
Replace the generated data with your dataset. `max_subspace_dim=128` caps the search
|
|
115
|
+
at 128 coordinates, so each step scores 144 candidates. In manual loops, call
|
|
116
|
+
`register_evaluator()` before each batch; `train()` does this automatically. See
|
|
117
|
+
[performance](https://github.com/anindex/polystep/blob/main/docs/performance.md)
|
|
118
|
+
for candidate paths, thread counts, compilation, and memory settings.
|
|
121
119
|
|
|
122
120
|
### Ask/tell
|
|
123
121
|
|
|
@@ -134,6 +132,7 @@ print(es.best_fitness, es.best_solution)
|
|
|
134
132
|
### Synthetic objectives
|
|
135
133
|
|
|
136
134
|
```python
|
|
135
|
+
import torch
|
|
137
136
|
from polystep import Ackley
|
|
138
137
|
from polystep.solver import PolyStep
|
|
139
138
|
|
|
@@ -145,7 +144,8 @@ state = solver.run(torch.randn(100, 10))
|
|
|
145
144
|
|
|
146
145
|
Each step samples a rotated polytope, evaluates its vertices, computes transport
|
|
147
146
|
weights, and moves to their barycenter. Subspaces reduce the number of coordinates
|
|
148
|
-
searched. Softmax
|
|
147
|
+
searched. Softmax normalizes each particle's vertex weights; Sinkhorn also enforces
|
|
148
|
+
the target marginal.
|
|
149
149
|
|
|
150
150
|
Finite-radius probes can cross flat regions of discontinuous losses. Performance
|
|
151
151
|
depends on the radius, representation, and evaluation budget. PolyStep's optional
|
|
@@ -155,8 +155,8 @@ inherit classical direct-search or trust-region guarantees.
|
|
|
155
155
|
## Baselines
|
|
156
156
|
|
|
157
157
|
`polystep.baselines` provides `openai_es`, `spsa`, `mezo`, `random_search`, `eggroll`,
|
|
158
|
-
and `cma_es`. One evaluation means one candidate
|
|
159
|
-
batched:
|
|
158
|
+
and `cma_es`, which needs `pip install cma`. One evaluation means one candidate
|
|
159
|
+
scored, even when candidates are batched:
|
|
160
160
|
|
|
161
161
|
```python
|
|
162
162
|
from polystep.baselines import Objective, openai_es
|
|
@@ -165,20 +165,30 @@ objective = Objective(lambda x: x.square().sum(1), dim=64, budget=10_000)
|
|
|
165
165
|
result = openai_es(objective, sigma=0.05, lr=0.1, popsize=32)
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
-
The paper runners
|
|
169
|
-
|
|
170
|
-
[reproduction protocol](docs/reproducibility.md) for tuning and budget details.
|
|
168
|
+
The paper runners match search spaces, budgets and tuning as the
|
|
169
|
+
[reproducibility guide](https://github.com/anindex/polystep/blob/main/docs/reproducibility.md#protocol) describes.
|
|
171
170
|
|
|
172
171
|
## Benchmarks
|
|
173
172
|
|
|
174
|
-
Five-seed mean ± sample standard deviation
|
|
175
|
-
validation
|
|
176
|
-
|
|
173
|
+
Five-seed mean ± sample standard deviation, with configurations and checkpoints
|
|
174
|
+
selected on validation data; the probSAT and RC2 columns are single runs. In the
|
|
175
|
+
architecture tables, OpenAI-ES, CMA-ES and EGGROLL get PolyStep's candidate-evaluation
|
|
176
|
+
budget, and SPSA, MeZO and random search get its step count. On argmax attention, hard
|
|
177
|
+
MoE and ETTh1, the population methods instead get 32 evaluations per PolyStep step,
|
|
178
|
+
spent at their own population size, and Adam trains for PolyStep's 30 epochs, except
|
|
179
|
+
50 on ETTh1. On MAX-SAT, CMA-ES and OpenAI-ES get 50 evaluations per PolyStep step.
|
|
180
|
+
OpenAI-ES scores 50 candidates at each of PolyStep's steps, while CMA-ES doubles its
|
|
181
|
+
population at each restart and takes fewer generations. The tables were recorded
|
|
182
|
+
before 1.0; the
|
|
183
|
+
[reproducibility guide](https://github.com/anindex/polystep/blob/main/docs/reproducibility.md#changes-since-the-published-tables)
|
|
184
|
+
lists the rows that 1.0 changes. The
|
|
185
|
+
[experiment index](https://github.com/anindex/polystep/blob/main/experiments/EXPERIMENT_INDEX.md)
|
|
186
|
+
has the full tables.
|
|
177
187
|
|
|
178
188
|
<!-- BENCH:START -->
|
|
179
189
|
### Non-differentiable tasks
|
|
180
190
|
|
|
181
|
-
Test accuracy %. A dash means the
|
|
191
|
+
Test accuracy %. A dash means the method was not run on that task.
|
|
182
192
|
|
|
183
193
|
| Task | PolyStep | CMA-ES | OpenAI-ES | SPSA | Adam (surrogate) | Non-diff op |
|
|
184
194
|
|---|---|---|---|---|---|---|
|
|
@@ -206,16 +216,17 @@ Test accuracy %. A dash means the cell is not in this release.
|
|
|
206
216
|
|
|
207
217
|
The SNN surrogate-gradient baseline varies substantially across seeds. Adam leads
|
|
208
218
|
on the differentiable tasks, and specialized solvers lead on MAX-SAT. See
|
|
209
|
-
[limitations](LIMITATIONS.md)
|
|
219
|
+
[limitations](https://github.com/anindex/polystep/blob/main/LIMITATIONS.md)
|
|
220
|
+
for unsupported configurations and comparison limits.
|
|
210
221
|
|
|
211
222
|
## Documentation
|
|
212
223
|
|
|
213
|
-
- [API reference](docs/api_overview.md)
|
|
214
|
-
- [Performance](docs/performance.md)
|
|
215
|
-
- [Examples](examples/README.md)
|
|
216
|
-
- [Experiments](experiments/README.md) and [reproduction](docs/reproducibility.md)
|
|
217
|
-
- [Determinism](docs/determinism.md)
|
|
218
|
-
- [Contributing](CONTRIBUTING.md) and [changelog](CHANGELOG.md)
|
|
224
|
+
- [API reference](https://github.com/anindex/polystep/blob/main/docs/api_overview.md)
|
|
225
|
+
- [Performance](https://github.com/anindex/polystep/blob/main/docs/performance.md)
|
|
226
|
+
- [Examples](https://github.com/anindex/polystep/blob/main/examples/README.md)
|
|
227
|
+
- [Experiments](https://github.com/anindex/polystep/blob/main/experiments/README.md) and [reproduction](https://github.com/anindex/polystep/blob/main/docs/reproducibility.md)
|
|
228
|
+
- [Determinism](https://github.com/anindex/polystep/blob/main/docs/determinism.md)
|
|
229
|
+
- [Contributing](https://github.com/anindex/polystep/blob/main/CONTRIBUTING.md) and [changelog](https://github.com/anindex/polystep/blob/main/CHANGELOG.md)
|
|
219
230
|
|
|
220
231
|
## Citation
|
|
221
232
|
|
|
@@ -223,15 +234,17 @@ on the differentiable tasks, and specialized solvers lead on MAX-SAT. See
|
|
|
223
234
|
@article{le2026training,
|
|
224
235
|
title={Training Non-Differentiable Networks via Optimal Transport},
|
|
225
236
|
author={Le, An T},
|
|
226
|
-
journal={
|
|
227
|
-
year={2026}
|
|
237
|
+
journal={Transactions on Machine Learning Research},
|
|
238
|
+
year={2026},
|
|
239
|
+
url={https://openreview.net/forum?id=8mlcqTTMuU}
|
|
228
240
|
}
|
|
229
241
|
```
|
|
230
242
|
|
|
231
243
|
## Acknowledgments
|
|
232
244
|
|
|
233
|
-
|
|
245
|
+
Thanks to [Viet T. Nguyen](https://vietngth.github.io/) for the
|
|
246
|
+
[interactive visualization](https://vietngth.github.io/polystep-visualization/).
|
|
234
247
|
|
|
235
248
|
## License
|
|
236
249
|
|
|
237
|
-
[Apache-2.0](LICENSE).
|
|
250
|
+
[Apache-2.0](https://github.com/anindex/polystep/blob/main/LICENSE).
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
Gradient-free neural network training via optimal transport.
|
|
10
10
|
|
|
11
|
+
Accepted at [Transactions on Machine Learning Research (TMLR)](https://openreview.net/forum?id=8mlcqTTMuU).
|
|
12
|
+
|
|
11
13
|
PolyStep evaluates finite-radius parameter perturbations and updates parameters
|
|
12
14
|
through a weighted barycenter. It supports spiking networks, quantized layers, hard
|
|
13
15
|
routing, and other models without useful gradients. For differentiable models,
|
|
@@ -15,20 +17,19 @@ backpropagation is usually faster.
|
|
|
15
17
|
|
|
16
18
|
[Paper](https://arxiv.org/abs/2605.01928) ·
|
|
17
19
|
[Interactive visualization](https://vietngth.github.io/polystep-visualization/) ·
|
|
18
|
-
[API reference](docs/api_overview.md)
|
|
20
|
+
[API reference](https://github.com/anindex/polystep/blob/main/docs/api_overview.md) ·
|
|
21
|
+
[Julia package](https://github.com/anindex/PolyStep.jl)
|
|
19
22
|
|
|
20
23
|
<p align="center">
|
|
21
24
|
<img src="https://raw.githubusercontent.com/anindex/polystep/main/docs/figures/method_diagram.png" width="840"
|
|
22
|
-
alt="PolyStep:
|
|
25
|
+
alt="PolyStep: search coordinates, polytope probes, cost evaluation, soft assignment, and a barycentric update.">
|
|
23
26
|
</p>
|
|
24
27
|
|
|
25
|
-
> Want to play around with parameters? [**Viet T. Nguyen**](https://vietngth.github.io/) built a gorgeous interactive walkthrough that animates every step of the method -> **[explore the PolyStep visualization](https://vietngth.github.io/polystep-visualization/)**.
|
|
26
|
-
|
|
27
28
|
## Installation
|
|
28
29
|
|
|
29
30
|
```bash
|
|
30
31
|
pip install polystep
|
|
31
|
-
pip install "polystep[examples]" #
|
|
32
|
+
pip install "polystep[examples]" # dependencies for the repository's examples
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
Python 3.11+ and PyTorch 2.8+ are required. Choose a CUDA build compatible with your
|
|
@@ -41,8 +42,7 @@ For development, install `pip install -e ".[dev]"` from a checkout.
|
|
|
41
42
|
import torch
|
|
42
43
|
from torch import nn
|
|
43
44
|
from torch.utils.data import DataLoader, TensorDataset
|
|
44
|
-
from polystep import HybridSubspace, PolyStepOptimizer, TrainConfig, train
|
|
45
|
-
from polystep.transform import ParamLayout
|
|
45
|
+
from polystep import HybridSubspace, ParamLayout, PolyStepOptimizer, TrainConfig, train
|
|
46
46
|
|
|
47
47
|
model = nn.Sequential(nn.Linear(16, 32), nn.ReLU(), nn.Linear(32, 3))
|
|
48
48
|
loader = DataLoader(
|
|
@@ -56,10 +56,11 @@ optimizer = PolyStepOptimizer(model, subspace=subspace, solver="softmax")
|
|
|
56
56
|
train(model, loader, nn.CrossEntropyLoss(), optimizer, TrainConfig(epochs=5))
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
Replace the generated data with your dataset.
|
|
60
|
-
|
|
61
|
-
`train()` does this automatically. See
|
|
62
|
-
|
|
59
|
+
Replace the generated data with your dataset. `max_subspace_dim=128` caps the search
|
|
60
|
+
at 128 coordinates, so each step scores 144 candidates. In manual loops, call
|
|
61
|
+
`register_evaluator()` before each batch; `train()` does this automatically. See
|
|
62
|
+
[performance](https://github.com/anindex/polystep/blob/main/docs/performance.md)
|
|
63
|
+
for candidate paths, thread counts, compilation, and memory settings.
|
|
63
64
|
|
|
64
65
|
### Ask/tell
|
|
65
66
|
|
|
@@ -76,6 +77,7 @@ print(es.best_fitness, es.best_solution)
|
|
|
76
77
|
### Synthetic objectives
|
|
77
78
|
|
|
78
79
|
```python
|
|
80
|
+
import torch
|
|
79
81
|
from polystep import Ackley
|
|
80
82
|
from polystep.solver import PolyStep
|
|
81
83
|
|
|
@@ -87,7 +89,8 @@ state = solver.run(torch.randn(100, 10))
|
|
|
87
89
|
|
|
88
90
|
Each step samples a rotated polytope, evaluates its vertices, computes transport
|
|
89
91
|
weights, and moves to their barycenter. Subspaces reduce the number of coordinates
|
|
90
|
-
searched. Softmax
|
|
92
|
+
searched. Softmax normalizes each particle's vertex weights; Sinkhorn also enforces
|
|
93
|
+
the target marginal.
|
|
91
94
|
|
|
92
95
|
Finite-radius probes can cross flat regions of discontinuous losses. Performance
|
|
93
96
|
depends on the radius, representation, and evaluation budget. PolyStep's optional
|
|
@@ -97,8 +100,8 @@ inherit classical direct-search or trust-region guarantees.
|
|
|
97
100
|
## Baselines
|
|
98
101
|
|
|
99
102
|
`polystep.baselines` provides `openai_es`, `spsa`, `mezo`, `random_search`, `eggroll`,
|
|
100
|
-
and `cma_es`. One evaluation means one candidate
|
|
101
|
-
batched:
|
|
103
|
+
and `cma_es`, which needs `pip install cma`. One evaluation means one candidate
|
|
104
|
+
scored, even when candidates are batched:
|
|
102
105
|
|
|
103
106
|
```python
|
|
104
107
|
from polystep.baselines import Objective, openai_es
|
|
@@ -107,20 +110,30 @@ objective = Objective(lambda x: x.square().sum(1), dim=64, budget=10_000)
|
|
|
107
110
|
result = openai_es(objective, sigma=0.05, lr=0.1, popsize=32)
|
|
108
111
|
```
|
|
109
112
|
|
|
110
|
-
The paper runners
|
|
111
|
-
|
|
112
|
-
[reproduction protocol](docs/reproducibility.md) for tuning and budget details.
|
|
113
|
+
The paper runners match search spaces, budgets and tuning as the
|
|
114
|
+
[reproducibility guide](https://github.com/anindex/polystep/blob/main/docs/reproducibility.md#protocol) describes.
|
|
113
115
|
|
|
114
116
|
## Benchmarks
|
|
115
117
|
|
|
116
|
-
Five-seed mean ± sample standard deviation
|
|
117
|
-
validation
|
|
118
|
-
|
|
118
|
+
Five-seed mean ± sample standard deviation, with configurations and checkpoints
|
|
119
|
+
selected on validation data; the probSAT and RC2 columns are single runs. In the
|
|
120
|
+
architecture tables, OpenAI-ES, CMA-ES and EGGROLL get PolyStep's candidate-evaluation
|
|
121
|
+
budget, and SPSA, MeZO and random search get its step count. On argmax attention, hard
|
|
122
|
+
MoE and ETTh1, the population methods instead get 32 evaluations per PolyStep step,
|
|
123
|
+
spent at their own population size, and Adam trains for PolyStep's 30 epochs, except
|
|
124
|
+
50 on ETTh1. On MAX-SAT, CMA-ES and OpenAI-ES get 50 evaluations per PolyStep step.
|
|
125
|
+
OpenAI-ES scores 50 candidates at each of PolyStep's steps, while CMA-ES doubles its
|
|
126
|
+
population at each restart and takes fewer generations. The tables were recorded
|
|
127
|
+
before 1.0; the
|
|
128
|
+
[reproducibility guide](https://github.com/anindex/polystep/blob/main/docs/reproducibility.md#changes-since-the-published-tables)
|
|
129
|
+
lists the rows that 1.0 changes. The
|
|
130
|
+
[experiment index](https://github.com/anindex/polystep/blob/main/experiments/EXPERIMENT_INDEX.md)
|
|
131
|
+
has the full tables.
|
|
119
132
|
|
|
120
133
|
<!-- BENCH:START -->
|
|
121
134
|
### Non-differentiable tasks
|
|
122
135
|
|
|
123
|
-
Test accuracy %. A dash means the
|
|
136
|
+
Test accuracy %. A dash means the method was not run on that task.
|
|
124
137
|
|
|
125
138
|
| Task | PolyStep | CMA-ES | OpenAI-ES | SPSA | Adam (surrogate) | Non-diff op |
|
|
126
139
|
|---|---|---|---|---|---|---|
|
|
@@ -148,16 +161,17 @@ Test accuracy %. A dash means the cell is not in this release.
|
|
|
148
161
|
|
|
149
162
|
The SNN surrogate-gradient baseline varies substantially across seeds. Adam leads
|
|
150
163
|
on the differentiable tasks, and specialized solvers lead on MAX-SAT. See
|
|
151
|
-
[limitations](LIMITATIONS.md)
|
|
164
|
+
[limitations](https://github.com/anindex/polystep/blob/main/LIMITATIONS.md)
|
|
165
|
+
for unsupported configurations and comparison limits.
|
|
152
166
|
|
|
153
167
|
## Documentation
|
|
154
168
|
|
|
155
|
-
- [API reference](docs/api_overview.md)
|
|
156
|
-
- [Performance](docs/performance.md)
|
|
157
|
-
- [Examples](examples/README.md)
|
|
158
|
-
- [Experiments](experiments/README.md) and [reproduction](docs/reproducibility.md)
|
|
159
|
-
- [Determinism](docs/determinism.md)
|
|
160
|
-
- [Contributing](CONTRIBUTING.md) and [changelog](CHANGELOG.md)
|
|
169
|
+
- [API reference](https://github.com/anindex/polystep/blob/main/docs/api_overview.md)
|
|
170
|
+
- [Performance](https://github.com/anindex/polystep/blob/main/docs/performance.md)
|
|
171
|
+
- [Examples](https://github.com/anindex/polystep/blob/main/examples/README.md)
|
|
172
|
+
- [Experiments](https://github.com/anindex/polystep/blob/main/experiments/README.md) and [reproduction](https://github.com/anindex/polystep/blob/main/docs/reproducibility.md)
|
|
173
|
+
- [Determinism](https://github.com/anindex/polystep/blob/main/docs/determinism.md)
|
|
174
|
+
- [Contributing](https://github.com/anindex/polystep/blob/main/CONTRIBUTING.md) and [changelog](https://github.com/anindex/polystep/blob/main/CHANGELOG.md)
|
|
161
175
|
|
|
162
176
|
## Citation
|
|
163
177
|
|
|
@@ -165,15 +179,17 @@ on the differentiable tasks, and specialized solvers lead on MAX-SAT. See
|
|
|
165
179
|
@article{le2026training,
|
|
166
180
|
title={Training Non-Differentiable Networks via Optimal Transport},
|
|
167
181
|
author={Le, An T},
|
|
168
|
-
journal={
|
|
169
|
-
year={2026}
|
|
182
|
+
journal={Transactions on Machine Learning Research},
|
|
183
|
+
year={2026},
|
|
184
|
+
url={https://openreview.net/forum?id=8mlcqTTMuU}
|
|
170
185
|
}
|
|
171
186
|
```
|
|
172
187
|
|
|
173
188
|
## Acknowledgments
|
|
174
189
|
|
|
175
|
-
|
|
190
|
+
Thanks to [Viet T. Nguyen](https://vietngth.github.io/) for the
|
|
191
|
+
[interactive visualization](https://vietngth.github.io/polystep-visualization/).
|
|
176
192
|
|
|
177
193
|
## License
|
|
178
194
|
|
|
179
|
-
[Apache-2.0](LICENSE).
|
|
195
|
+
[Apache-2.0](https://github.com/anindex/polystep/blob/main/LICENSE).
|