torchsparsegradutils 0.2.1__tar.gz → 0.2.2__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.
- {torchsparsegradutils-0.2.1/torchsparsegradutils.egg-info → torchsparsegradutils-0.2.2}/PKG-INFO +19 -10
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/README.md +11 -7
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/docs/source/conf.py +3 -3
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/pyproject.toml +8 -2
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/cupy/__init__.py +11 -2
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/cupy/cupy_bindings.py +25 -11
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/cupy/cupy_sparse_solve.py +92 -95
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/indexed_matmul.py +3 -2
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/sparse_matmul.py +3 -3
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/sparse_solve.py +2 -2
- torchsparsegradutils-0.2.2/torchsparsegradutils/tests/conftest.py +48 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_bicgstab.py +8 -11
- torchsparsegradutils-0.2.2/torchsparsegradutils/tests/test_config.py +62 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_cupy_bindings.py +9 -12
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_cupy_sparse_solve.py +45 -39
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_dist_stats_helpers.py +1 -12
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_distributions.py +22 -42
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_encoders.py +2 -1
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_indexed_matmul.py +30 -5
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_integration_pairwise_sparse_mvn.py +66 -16
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_jax_bindings.py +1 -5
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_jax_sparse_solve.py +19 -27
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_linear_cg.py +0 -19
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_lsmr.py +19 -23
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_minres.py +3 -11
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_random.py +9 -10
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_sparse_lstsq.py +3 -7
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_sparse_matmul.py +7 -14
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_sparse_solve.py +28 -37
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_sparse_triangular_solve.py +8 -17
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_utils.py +2 -7
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/utils/utils.py +6 -8
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2/torchsparsegradutils.egg-info}/PKG-INFO +19 -10
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils.egg-info/SOURCES.txt +2 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils.egg-info/requires.txt +10 -3
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/LICENSE +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/MANIFEST.in +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/setup.cfg +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/setup.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/__init__.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/benchmarks/__init__.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/benchmarks/batched_sparse_mm_rand.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/benchmarks/benchmark_suite.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/benchmarks/benchmark_utils.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/benchmarks/sparse_generic_solve_rand.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/benchmarks/sparse_generic_solve_suite.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/benchmarks/sparse_mm_rand.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/benchmarks/sparse_mm_suite.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/benchmarks/sparse_triangular_solve_rand.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/benchmarks/sparse_triangular_solve_suitesparse.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/benchmarks/visualize_benchmark_results.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/distributions/__init__.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/distributions/constraints.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/distributions/sparse_multivariate_normal.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/encoders/__init__.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/encoders/pairwise_encoder.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/encoders/pairwise_voxel_encoder.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/jax/__init__.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/jax/jax_bindings.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/jax/jax_sparse_solve.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/sparse_lstsq.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/__init__.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_doctests.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_params/czyx_shifts.yaml +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_params/pairwise_coo_indices.yaml +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_params/xyz_coords.yaml +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/tests/test_quickstart_guide.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/utils/__init__.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/utils/bicgstab.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/utils/dist_stats_helpers.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/utils/linear_cg.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/utils/lsmr.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/utils/minres.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/utils/random_sparse.py +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils.egg-info/dependency_links.txt +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils.egg-info/not-zip-safe +0 -0
- {torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils.egg-info/top_level.txt +0 -0
{torchsparsegradutils-0.2.1/torchsparsegradutils.egg-info → torchsparsegradutils-0.2.2}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: torchsparsegradutils
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A collection of utility functions to work with PyTorch sparse tensors
|
|
5
5
|
Author-email: CAI4CAI research group <contact@cai4cai.uk>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -19,9 +19,14 @@ Description-Content-Type: text/markdown
|
|
|
19
19
|
License-File: LICENSE
|
|
20
20
|
Requires-Dist: torch>=2.5
|
|
21
21
|
Requires-Dist: scipy
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Requires-Dist: cupy; extra == "
|
|
22
|
+
Requires-Dist: packaging
|
|
23
|
+
Provides-Extra: cupy
|
|
24
|
+
Requires-Dist: cupy-cuda12x>=13.0; extra == "cupy"
|
|
25
|
+
Provides-Extra: jax
|
|
26
|
+
Requires-Dist: jax[cuda12]; extra == "jax"
|
|
27
|
+
Provides-Extra: all
|
|
28
|
+
Requires-Dist: cupy-cuda12x>=13.0; extra == "all"
|
|
29
|
+
Requires-Dist: jax[cuda12]; extra == "all"
|
|
25
30
|
Provides-Extra: docs
|
|
26
31
|
Requires-Dist: sphinx>=7.0.0; extra == "docs"
|
|
27
32
|
Requires-Dist: sphinx-rtd-theme>=1.3.0; extra == "docs"
|
|
@@ -42,7 +47,7 @@ Dynamic: license-file
|
|
|
42
47
|
|
|
43
48
|
# torchsparsegradutils: Sparsity-preserving gradient utility tools for PyTorch
|
|
44
49
|
|
|
45
|
-
[](https://pypi.org/project/torchsparsegradutils/) [](https://pypi.org/project/torchsparsegradutils/) [](https://pypi.org/project/torchsparsegradutils/)  ](https://pypi.org/project/torchsparsegradutils/) [](https://pypi.org/project/torchsparsegradutils/) [](https://pypi.org/project/torchsparsegradutils/)   [](https://github.com/cai4cai/torchsparsegradutils/actions/workflows/python-package.yml) [](https://readthedocs.org/projects/torchsparsegradutils) [](https://github.com/psf/black) [](LICENSE) [](https://joss.theoj.org/papers/6da0e92488d06f70c0a03d0a7cbfba7d)
|
|
46
51
|
|
|
47
52
|
A comprehensive collection of utility functions to work with PyTorch sparse tensors, ensuring memory efficiency and supporting various sparsity-preserving tensor operations with automatic differentiation. This package addresses fundamental gaps in PyTorch's sparse tensor ecosystem, providing essential operations that preserve sparsity in gradients during backpropagation.
|
|
48
53
|
|
|
@@ -133,17 +138,21 @@ pip install git+https://github.com/cai4cai/torchsparsegradutils
|
|
|
133
138
|
For full functionality, install optional dependencies:
|
|
134
139
|
|
|
135
140
|
```bash
|
|
136
|
-
# For CuPy sparse solver support (GPU acceleration)
|
|
137
|
-
pip install cupy
|
|
141
|
+
# For CuPy sparse solver support (GPU acceleration, requires CUDA 12.x)
|
|
142
|
+
pip install torchsparsegradutils[cupy]
|
|
138
143
|
|
|
139
144
|
# For JAX sparse solver support
|
|
140
|
-
pip install
|
|
141
|
-
|
|
145
|
+
pip install torchsparsegradutils[jax]
|
|
146
|
+
|
|
147
|
+
# Install all optional dependencies
|
|
148
|
+
pip install torchsparsegradutils[all]
|
|
142
149
|
|
|
143
150
|
# For benchmarking and testing
|
|
144
151
|
pip install scipy matplotlib pandas tqdm pytest
|
|
145
152
|
```
|
|
146
153
|
|
|
154
|
+
> **Note:** The CuPy extra installs `cupy-cuda12x>=13.0`. If you are using a different CUDA version, install the appropriate CuPy package manually (e.g. `pip install cupy-cuda11x`).
|
|
155
|
+
|
|
147
156
|
### Requirements
|
|
148
157
|
|
|
149
158
|
- **Python**: ≥ 3.10
|
|
@@ -160,7 +169,7 @@ Our comprehensive benchmark suite demonstrates significant performance improveme
|
|
|
160
169
|
|
|
161
170
|

|
|
162
171
|
|
|
163
|
-

|
|
164
173
|
|
|
165
174
|
## 🚀 Quick Start
|
|
166
175
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# torchsparsegradutils: Sparsity-preserving gradient utility tools for PyTorch
|
|
2
2
|
|
|
3
|
-
[](https://pypi.org/project/torchsparsegradutils/) [](https://pypi.org/project/torchsparsegradutils/) [](https://pypi.org/project/torchsparsegradutils/)  ](https://pypi.org/project/torchsparsegradutils/) [](https://pypi.org/project/torchsparsegradutils/) [](https://pypi.org/project/torchsparsegradutils/)   [](https://github.com/cai4cai/torchsparsegradutils/actions/workflows/python-package.yml) [](https://readthedocs.org/projects/torchsparsegradutils) [](https://github.com/psf/black) [](LICENSE) [](https://joss.theoj.org/papers/6da0e92488d06f70c0a03d0a7cbfba7d)
|
|
4
4
|
|
|
5
5
|
A comprehensive collection of utility functions to work with PyTorch sparse tensors, ensuring memory efficiency and supporting various sparsity-preserving tensor operations with automatic differentiation. This package addresses fundamental gaps in PyTorch's sparse tensor ecosystem, providing essential operations that preserve sparsity in gradients during backpropagation.
|
|
6
6
|
|
|
@@ -91,17 +91,21 @@ pip install git+https://github.com/cai4cai/torchsparsegradutils
|
|
|
91
91
|
For full functionality, install optional dependencies:
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
|
-
# For CuPy sparse solver support (GPU acceleration)
|
|
95
|
-
pip install cupy
|
|
94
|
+
# For CuPy sparse solver support (GPU acceleration, requires CUDA 12.x)
|
|
95
|
+
pip install torchsparsegradutils[cupy]
|
|
96
96
|
|
|
97
97
|
# For JAX sparse solver support
|
|
98
|
-
pip install
|
|
99
|
-
|
|
98
|
+
pip install torchsparsegradutils[jax]
|
|
99
|
+
|
|
100
|
+
# Install all optional dependencies
|
|
101
|
+
pip install torchsparsegradutils[all]
|
|
100
102
|
|
|
101
103
|
# For benchmarking and testing
|
|
102
104
|
pip install scipy matplotlib pandas tqdm pytest
|
|
103
105
|
```
|
|
104
106
|
|
|
107
|
+
> **Note:** The CuPy extra installs `cupy-cuda12x>=13.0`. If you are using a different CUDA version, install the appropriate CuPy package manually (e.g. `pip install cupy-cuda11x`).
|
|
108
|
+
|
|
105
109
|
### Requirements
|
|
106
110
|
|
|
107
111
|
- **Python**: ≥ 3.10
|
|
@@ -118,7 +122,7 @@ Our comprehensive benchmark suite demonstrates significant performance improveme
|
|
|
118
122
|
|
|
119
123
|

|
|
120
124
|
|
|
121
|
-

|
|
122
126
|
|
|
123
127
|
## 🚀 Quick Start
|
|
124
128
|
|
|
@@ -658,4 +662,4 @@ dist_stable = SparseMultivariateNormal(
|
|
|
658
662
|
- **No SPD Constraints**: Doesn't require strict positive definiteness
|
|
659
663
|
- **Better Conditioning**: Diagonal component can be controlled independently
|
|
660
664
|
|
|
661
|
-
**Status**: This is a known limitation of the LL^T precision formulation. LDL^T parameterization is the recommended approach for precision matrices.
|
|
665
|
+
**Status**: This is a known limitation of the LL^T precision formulation. LDL^T parameterization is the recommended approach for precision matrices.
|
|
@@ -13,10 +13,10 @@ import sys
|
|
|
13
13
|
sys.path.insert(0, os.path.abspath("../../"))
|
|
14
14
|
|
|
15
15
|
project = "torchsparsegradutils"
|
|
16
|
-
copyright = "
|
|
16
|
+
copyright = "2026, CAI4CAI research group"
|
|
17
17
|
author = "CAI4CAI research group"
|
|
18
|
-
release = "0.2.
|
|
19
|
-
version = "0.2.
|
|
18
|
+
release = "0.2.2"
|
|
19
|
+
version = "0.2.2"
|
|
20
20
|
|
|
21
21
|
# -- General configuration ---------------------------------------------------
|
|
22
22
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "torchsparsegradutils"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "A collection of utility functions to work with PyTorch sparse tensors"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -22,10 +22,13 @@ classifiers = [
|
|
|
22
22
|
dependencies = [
|
|
23
23
|
"torch>=2.5",
|
|
24
24
|
"scipy",
|
|
25
|
+
"packaging",
|
|
25
26
|
]
|
|
26
27
|
|
|
27
28
|
[project.optional-dependencies]
|
|
28
|
-
|
|
29
|
+
cupy = ["cupy-cuda12x>=13.0"]
|
|
30
|
+
jax = ["jax[cuda12]"]
|
|
31
|
+
all = ["cupy-cuda12x>=13.0", "jax[cuda12]"]
|
|
29
32
|
docs = [
|
|
30
33
|
"sphinx>=7.0.0",
|
|
31
34
|
"sphinx-rtd-theme>=1.3.0",
|
|
@@ -99,6 +102,9 @@ addopts = ["-v"]
|
|
|
99
102
|
testpaths = [
|
|
100
103
|
"torchsparsegradutils/tests",
|
|
101
104
|
]
|
|
105
|
+
pythonpath = [
|
|
106
|
+
"torchsparsegradutils/tests",
|
|
107
|
+
]
|
|
102
108
|
doctest_optionflags = [
|
|
103
109
|
"NORMALIZE_WHITESPACE",
|
|
104
110
|
"IGNORE_EXCEPTION_DETAIL",
|
{torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/cupy/__init__.py
RENAMED
|
@@ -11,7 +11,16 @@ if cupy_spec is None:
|
|
|
11
11
|
else:
|
|
12
12
|
have_cupy = True
|
|
13
13
|
|
|
14
|
-
from .cupy_bindings import _get_array_modules, c2t_coo, c2t_csr, t2c_coo, t2c_csr
|
|
14
|
+
from .cupy_bindings import _backend_to_torch, _get_array_modules, _torch_to_backend, c2t_coo, c2t_csr, t2c_coo, t2c_csr
|
|
15
15
|
from .cupy_sparse_solve import sparse_solve_c4t
|
|
16
16
|
|
|
17
|
-
__all__ = [
|
|
17
|
+
__all__ = [
|
|
18
|
+
"c2t_coo",
|
|
19
|
+
"t2c_coo",
|
|
20
|
+
"c2t_csr",
|
|
21
|
+
"t2c_csr",
|
|
22
|
+
"_get_array_modules",
|
|
23
|
+
"_torch_to_backend",
|
|
24
|
+
"_backend_to_torch",
|
|
25
|
+
"sparse_solve_c4t",
|
|
26
|
+
]
|
{torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/cupy/cupy_bindings.py
RENAMED
|
@@ -38,6 +38,20 @@ import scipy.sparse.linalg
|
|
|
38
38
|
import torch
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
def _torch_to_backend(tensor: torch.Tensor, xp) -> Any:
|
|
42
|
+
r"""Convert a PyTorch tensor to a backend array (NumPy or CuPy) using DLPack for CUDA."""
|
|
43
|
+
if tsgucupy.have_cupy and xp is cp:
|
|
44
|
+
return cp.from_dlpack(tensor)
|
|
45
|
+
return xp.asarray(tensor)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _backend_to_torch(array) -> torch.Tensor:
|
|
49
|
+
r"""Convert a backend array (NumPy or CuPy) to a PyTorch tensor using DLPack for CUDA."""
|
|
50
|
+
if tsgucupy.have_cupy and isinstance(array, cp.ndarray):
|
|
51
|
+
return torch.from_dlpack(array)
|
|
52
|
+
return torch.as_tensor(array)
|
|
53
|
+
|
|
54
|
+
|
|
41
55
|
def _get_array_modules(x: Any) -> Tuple[Any, Any]:
|
|
42
56
|
r"""
|
|
43
57
|
Select dense & sparse array modules (NumPy/SciPy or CuPy/cupyx.scipy.sparse).
|
|
@@ -116,9 +130,9 @@ def t2c_csr(x_torch: torch.Tensor) -> Any:
|
|
|
116
130
|
"""
|
|
117
131
|
xp, xsp = _get_array_modules(x_torch)
|
|
118
132
|
|
|
119
|
-
data_c =
|
|
120
|
-
col_idx_c =
|
|
121
|
-
ind_ptr_c =
|
|
133
|
+
data_c = _torch_to_backend(x_torch.values(), xp)
|
|
134
|
+
col_idx_c = _torch_to_backend(x_torch.col_indices(), xp)
|
|
135
|
+
ind_ptr_c = _torch_to_backend(x_torch.crow_indices(), xp)
|
|
122
136
|
x_cupy = xsp.csr_matrix((data_c, col_idx_c, ind_ptr_c), shape=x_torch.shape)
|
|
123
137
|
return x_cupy
|
|
124
138
|
|
|
@@ -150,9 +164,9 @@ def c2t_csr(x_cupy: Any) -> torch.Tensor:
|
|
|
150
164
|
>>> x.layout is torch.sparse_csr
|
|
151
165
|
True
|
|
152
166
|
"""
|
|
153
|
-
data_t =
|
|
154
|
-
idices_t =
|
|
155
|
-
ind_ptr_t =
|
|
167
|
+
data_t = _backend_to_torch(x_cupy.data)
|
|
168
|
+
idices_t = _backend_to_torch(x_cupy.indices)
|
|
169
|
+
ind_ptr_t = _backend_to_torch(x_cupy.indptr)
|
|
156
170
|
x_torch = torch.sparse_csr_tensor(ind_ptr_t, idices_t, data_t, x_cupy.shape)
|
|
157
171
|
return x_torch
|
|
158
172
|
|
|
@@ -205,8 +219,8 @@ def t2c_coo(x_torch: torch.Tensor) -> Any:
|
|
|
205
219
|
"Requested a conversion from torch to cupy/numpy on a non-coalesced tensor -> coalescing implicitly"
|
|
206
220
|
)
|
|
207
221
|
x_torch = x_torch.coalesce()
|
|
208
|
-
data_c =
|
|
209
|
-
idx_cp =
|
|
222
|
+
data_c = _torch_to_backend(x_torch.values(), xp)
|
|
223
|
+
idx_cp = _torch_to_backend(x_torch.indices(), xp)
|
|
210
224
|
x_cupy = xsp.coo_matrix((data_c, idx_cp), shape=x_torch.shape)
|
|
211
225
|
return x_cupy
|
|
212
226
|
|
|
@@ -238,8 +252,8 @@ def c2t_coo(x_cupy: Any) -> torch.Tensor:
|
|
|
238
252
|
>>> x.layout is torch.sparse_coo
|
|
239
253
|
True
|
|
240
254
|
"""
|
|
241
|
-
data_t =
|
|
242
|
-
row_t =
|
|
243
|
-
col_t =
|
|
255
|
+
data_t = _backend_to_torch(x_cupy.data)
|
|
256
|
+
row_t = _backend_to_torch(x_cupy.row)
|
|
257
|
+
col_t = _backend_to_torch(x_cupy.col)
|
|
244
258
|
x_torch = torch.sparse_coo_tensor(torch.stack([row_t, col_t], dim=0), data_t, x_cupy.shape)
|
|
245
259
|
return x_torch
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import inspect
|
|
1
2
|
import warnings
|
|
2
3
|
from typing import Any, Callable, Dict, Optional, Tuple, Union
|
|
3
4
|
|
|
@@ -8,6 +9,90 @@ import torchsparsegradutils.cupy as tsgucupy
|
|
|
8
9
|
# from cupyx.scipy.sparse.linalg import cg, cgs, minres, gmres, spsolve
|
|
9
10
|
|
|
10
11
|
|
|
12
|
+
def _wrap_iterative_solver(base_solver, backend_type, solver_name=None):
|
|
13
|
+
"""Wrap an iterative solver to handle parameter mapping and return format."""
|
|
14
|
+
|
|
15
|
+
# Introspect the actual solver signature to determine accepted parameter names
|
|
16
|
+
try:
|
|
17
|
+
sig_params = set(inspect.signature(base_solver).parameters.keys())
|
|
18
|
+
except (ValueError, TypeError):
|
|
19
|
+
sig_params = set()
|
|
20
|
+
|
|
21
|
+
def wrapped_solver(A, b, **solver_kwargs):
|
|
22
|
+
# Create a copy to avoid modifying the original
|
|
23
|
+
filtered_kwargs = solver_kwargs.copy()
|
|
24
|
+
|
|
25
|
+
# Extract tolerance parameter and map to correct name for the backend
|
|
26
|
+
tolerance = filtered_kwargs.pop("tol", None)
|
|
27
|
+
atol = filtered_kwargs.pop("atol", None)
|
|
28
|
+
|
|
29
|
+
if tolerance is not None:
|
|
30
|
+
# Use introspection to determine correct tolerance parameter name
|
|
31
|
+
if "rtol" in sig_params:
|
|
32
|
+
filtered_kwargs["rtol"] = tolerance
|
|
33
|
+
elif "tol" in sig_params:
|
|
34
|
+
filtered_kwargs["tol"] = tolerance
|
|
35
|
+
|
|
36
|
+
# Handle atol parameter if the solver accepts it
|
|
37
|
+
if atol is not None and "atol" in sig_params:
|
|
38
|
+
filtered_kwargs["atol"] = atol
|
|
39
|
+
|
|
40
|
+
# Filter to only parameters the solver actually accepts
|
|
41
|
+
common_params = {"x0", "M", "callback", "show", "check"}
|
|
42
|
+
if sig_params:
|
|
43
|
+
final_kwargs = {k: v for k, v in filtered_kwargs.items() if k in sig_params or k in common_params}
|
|
44
|
+
else:
|
|
45
|
+
# Fallback: pass everything if we couldn't introspect
|
|
46
|
+
final_kwargs = filtered_kwargs
|
|
47
|
+
|
|
48
|
+
# Call the base solver
|
|
49
|
+
result = base_solver(A, b, **final_kwargs)
|
|
50
|
+
|
|
51
|
+
# Handle return format - some solvers return (solution, info) tuples
|
|
52
|
+
if isinstance(result, tuple):
|
|
53
|
+
return result[0] # Return just the solution
|
|
54
|
+
return result
|
|
55
|
+
|
|
56
|
+
return wrapped_solver
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _wrap_direct_solver(base_solver):
|
|
60
|
+
"""Wrap a direct solver to ignore tolerance parameters."""
|
|
61
|
+
|
|
62
|
+
def wrapped_solver(A, b, **solver_kwargs):
|
|
63
|
+
# Direct solvers don't use iterative solver parameters, so ignore them all
|
|
64
|
+
filtered_kwargs = {
|
|
65
|
+
k: v
|
|
66
|
+
for k, v in solver_kwargs.items()
|
|
67
|
+
if k not in ["tol", "tolerance", "atol", "rtol", "maxiter", "matvec_max"]
|
|
68
|
+
}
|
|
69
|
+
return base_solver(A, b, **filtered_kwargs)
|
|
70
|
+
|
|
71
|
+
return wrapped_solver
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _get_solver_function(solver_name, xsp, device):
|
|
75
|
+
"""Get the appropriate solver function based on the backend."""
|
|
76
|
+
if solver_name is None or callable(solver_name):
|
|
77
|
+
return solver_name
|
|
78
|
+
|
|
79
|
+
# Determine backend type
|
|
80
|
+
backend_type = "scipy" if device.type == "cpu" else "cupy"
|
|
81
|
+
|
|
82
|
+
solver_map = {
|
|
83
|
+
"cg": _wrap_iterative_solver(xsp.linalg.cg, backend_type, "cg"),
|
|
84
|
+
"cgs": _wrap_iterative_solver(xsp.linalg.cgs, backend_type, "cgs"),
|
|
85
|
+
"minres": _wrap_iterative_solver(xsp.linalg.minres, backend_type, "minres"),
|
|
86
|
+
"gmres": _wrap_iterative_solver(xsp.linalg.gmres, backend_type, "gmres"),
|
|
87
|
+
"spsolve": _wrap_direct_solver(xsp.linalg.spsolve),
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if solver_name not in solver_map:
|
|
91
|
+
raise ValueError(f"Unknown solver: {solver_name}. Supported solvers: {list(solver_map.keys())}")
|
|
92
|
+
|
|
93
|
+
return solver_map[solver_name]
|
|
94
|
+
|
|
95
|
+
|
|
11
96
|
def sparse_solve_c4t(
|
|
12
97
|
A: torch.Tensor,
|
|
13
98
|
B: torch.Tensor,
|
|
@@ -154,94 +239,7 @@ def sparse_solve_c4t(
|
|
|
154
239
|
f"Use transpose_solve='spsolve' or transpose_solve=None for multi-RHS problems."
|
|
155
240
|
)
|
|
156
241
|
|
|
157
|
-
# Convert string solver names to
|
|
158
|
-
def _get_solver_function(solver_name, xsp):
|
|
159
|
-
"""Get the appropriate solver function based on the backend."""
|
|
160
|
-
if solver_name is None or callable(solver_name):
|
|
161
|
-
return solver_name
|
|
162
|
-
|
|
163
|
-
def _wrap_iterative_solver(base_solver, backend_type, solver_name=None):
|
|
164
|
-
"""Wrap an iterative solver to handle parameter mapping and return format."""
|
|
165
|
-
|
|
166
|
-
def wrapped_solver(A, b, **solver_kwargs):
|
|
167
|
-
# Create a copy to avoid modifying the original
|
|
168
|
-
filtered_kwargs = solver_kwargs.copy()
|
|
169
|
-
|
|
170
|
-
# Extract tolerance parameter and map to correct name for the backend
|
|
171
|
-
tolerance = filtered_kwargs.pop("tol", None)
|
|
172
|
-
atol = filtered_kwargs.pop("atol", None)
|
|
173
|
-
|
|
174
|
-
# Define solver-specific parameter support
|
|
175
|
-
solver_params = {
|
|
176
|
-
"cg": {"rtol", "maxiter", "atol"} if backend_type == "scipy" else {"tol", "maxiter", "atol"},
|
|
177
|
-
"cgs": {"rtol", "maxiter", "atol"} if backend_type == "scipy" else {"tol", "maxiter", "atol"},
|
|
178
|
-
"minres": {"rtol", "maxiter", "shift"} if backend_type == "scipy" else {"tol", "maxiter"},
|
|
179
|
-
"gmres": {"rtol", "maxiter", "atol"} if backend_type == "scipy" else {"tol", "maxiter", "atol"},
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
# Get supported parameters for this solver
|
|
183
|
-
supported_params = solver_params.get(solver_name, set())
|
|
184
|
-
|
|
185
|
-
if tolerance is not None:
|
|
186
|
-
# Map tolerance parameter based on backend and solver support
|
|
187
|
-
if backend_type == "scipy" and "rtol" in supported_params:
|
|
188
|
-
filtered_kwargs["rtol"] = tolerance
|
|
189
|
-
elif backend_type == "cupy" and "tol" in supported_params:
|
|
190
|
-
filtered_kwargs["tol"] = tolerance
|
|
191
|
-
|
|
192
|
-
# Handle atol parameter if supported
|
|
193
|
-
if atol is not None and "atol" in supported_params:
|
|
194
|
-
filtered_kwargs["atol"] = atol
|
|
195
|
-
|
|
196
|
-
# Filter out unsupported parameters
|
|
197
|
-
final_kwargs = {
|
|
198
|
-
k: v
|
|
199
|
-
for k, v in filtered_kwargs.items()
|
|
200
|
-
if k in supported_params
|
|
201
|
-
or k in {"x0", "M", "callback", "show", "check"} # Always allow common parameters
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
# Call the base solver
|
|
205
|
-
result = base_solver(A, b, **final_kwargs)
|
|
206
|
-
|
|
207
|
-
# Handle return format - some solvers return (solution, info) tuples
|
|
208
|
-
if isinstance(result, tuple):
|
|
209
|
-
return result[0] # Return just the solution
|
|
210
|
-
return result
|
|
211
|
-
|
|
212
|
-
return wrapped_solver
|
|
213
|
-
|
|
214
|
-
def _wrap_direct_solver(base_solver):
|
|
215
|
-
"""Wrap a direct solver to ignore tolerance parameters."""
|
|
216
|
-
|
|
217
|
-
def wrapped_solver(A, b, **solver_kwargs):
|
|
218
|
-
# Direct solvers don't use iterative solver parameters, so ignore them all
|
|
219
|
-
filtered_kwargs = {
|
|
220
|
-
k: v
|
|
221
|
-
for k, v in solver_kwargs.items()
|
|
222
|
-
if k not in ["tol", "tolerance", "atol", "rtol", "maxiter", "matvec_max"]
|
|
223
|
-
}
|
|
224
|
-
return base_solver(A, b, **filtered_kwargs)
|
|
225
|
-
|
|
226
|
-
return wrapped_solver
|
|
227
|
-
|
|
228
|
-
# Determine backend type
|
|
229
|
-
backend_type = "scipy" if A.device.type == "cpu" else "cupy"
|
|
230
|
-
|
|
231
|
-
solver_map = {
|
|
232
|
-
"cg": _wrap_iterative_solver(xsp.linalg.cg, backend_type, "cg"),
|
|
233
|
-
"cgs": _wrap_iterative_solver(xsp.linalg.cgs, backend_type, "cgs"),
|
|
234
|
-
"minres": _wrap_iterative_solver(xsp.linalg.minres, backend_type, "minres"),
|
|
235
|
-
"gmres": _wrap_iterative_solver(xsp.linalg.gmres, backend_type, "gmres"),
|
|
236
|
-
"spsolve": _wrap_direct_solver(xsp.linalg.spsolve),
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if solver_name not in solver_map:
|
|
240
|
-
raise ValueError(f"Unknown solver: {solver_name}. Supported solvers: {list(solver_map.keys())}")
|
|
241
|
-
|
|
242
|
-
return solver_map[solver_name]
|
|
243
|
-
|
|
244
|
-
# Get the appropriate backend modules
|
|
242
|
+
# Convert string solver names to functions
|
|
245
243
|
xp, xsp = tsgucupy._get_array_modules(A.data)
|
|
246
244
|
|
|
247
245
|
# Warn about dtype issues with minres on CPU
|
|
@@ -262,9 +260,8 @@ def sparse_solve_c4t(
|
|
|
262
260
|
stacklevel=2,
|
|
263
261
|
)
|
|
264
262
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
transpose_solve_func = _get_solver_function(transpose_solve, xsp)
|
|
263
|
+
solve_func = _get_solver_function(solve, xsp, A.device)
|
|
264
|
+
transpose_solve_func = _get_solver_function(transpose_solve, xsp, A.device)
|
|
268
265
|
|
|
269
266
|
return SparseSolveC4T.apply(A, B, solve_func, transpose_solve_func, kwargs)
|
|
270
267
|
|
|
@@ -307,7 +304,7 @@ class SparseSolveC4T(torch.autograd.Function):
|
|
|
307
304
|
A_c = tsgucupy.t2c_csr(A.detach())
|
|
308
305
|
else:
|
|
309
306
|
raise TypeError(f"Unsupported layout type: {A.layout}")
|
|
310
|
-
B_c =
|
|
307
|
+
B_c = tsgucupy._torch_to_backend(B.detach(), xp)
|
|
311
308
|
|
|
312
309
|
# Solve the sparse system
|
|
313
310
|
ctx.factorisedsolver = None
|
|
@@ -329,7 +326,7 @@ class SparseSolveC4T(torch.autograd.Function):
|
|
|
329
326
|
# If the solver returns a tuple, we assume the first element is the solution
|
|
330
327
|
x_c = x_c[0]
|
|
331
328
|
|
|
332
|
-
x =
|
|
329
|
+
x = tsgucupy._backend_to_torch(x_c)
|
|
333
330
|
|
|
334
331
|
# Ensure output dtype matches input dtype
|
|
335
332
|
if x.dtype != A.dtype:
|
|
@@ -354,7 +351,7 @@ class SparseSolveC4T(torch.autograd.Function):
|
|
|
354
351
|
x = x.unsqueeze(-1)
|
|
355
352
|
grad = grad.unsqueeze(-1)
|
|
356
353
|
|
|
357
|
-
grad_c =
|
|
354
|
+
grad_c = tsgucupy._torch_to_backend(grad.detach(), xp)
|
|
358
355
|
|
|
359
356
|
# Backprop rule: gradB = A^{-T} grad
|
|
360
357
|
if ctx.transpose_solve is not None:
|
|
@@ -369,7 +366,7 @@ class SparseSolveC4T(torch.autograd.Function):
|
|
|
369
366
|
# If the solver returns a tuple, we assume the first element is the gradient
|
|
370
367
|
gradB_c = gradB_c[0]
|
|
371
368
|
|
|
372
|
-
gradB =
|
|
369
|
+
gradB = tsgucupy._backend_to_torch(gradB_c)
|
|
373
370
|
|
|
374
371
|
# Ensure gradient dtype matches input dtype
|
|
375
372
|
if gradB.dtype != A.dtype:
|
{torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/indexed_matmul.py
RENAMED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import torch
|
|
2
|
+
from packaging.version import parse as parse_version
|
|
2
3
|
|
|
3
4
|
try:
|
|
4
5
|
import dgl.ops as dglops
|
|
@@ -73,7 +74,7 @@ def segment_mm(a: torch.Tensor, b: torch.Tensor, seglen_a: torch.Tensor) -> torc
|
|
|
73
74
|
>>> segment_mm(a, b, seglen_a).shape
|
|
74
75
|
torch.Size([18, 2])
|
|
75
76
|
"""
|
|
76
|
-
if torch.__version__ < (2
|
|
77
|
+
if parse_version(torch.__version__) < parse_version("2.4"):
|
|
77
78
|
raise NotImplementedError("PyTorch version is too old for nested tensors")
|
|
78
79
|
|
|
79
80
|
if dgl_installed:
|
|
@@ -177,7 +178,7 @@ def gather_mm(a: torch.Tensor, b: torch.Tensor, idx_b: torch.Tensor) -> torch.Te
|
|
|
177
178
|
tensor([[1., 2.],
|
|
178
179
|
[6., 8.]])
|
|
179
180
|
"""
|
|
180
|
-
if torch.__version__ < (2
|
|
181
|
+
if parse_version(torch.__version__) < parse_version("2.4"):
|
|
181
182
|
raise NotImplementedError("PyTorch version is too old for nested tensors")
|
|
182
183
|
|
|
183
184
|
if dgl_installed:
|
{torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/sparse_matmul.py
RENAMED
|
@@ -150,7 +150,7 @@ class SparseMatMul(torch.autograd.Function):
|
|
|
150
150
|
|
|
151
151
|
if ctx.batch_size is not None:
|
|
152
152
|
A = sparse_block_diag(*A)
|
|
153
|
-
B =
|
|
153
|
+
B = B.reshape(-1, B.size(-1))
|
|
154
154
|
|
|
155
155
|
x = torch.sparse.mm(A, B)
|
|
156
156
|
|
|
@@ -194,7 +194,7 @@ class SparseMatMul(torch.autograd.Function):
|
|
|
194
194
|
raise ValueError(f"Unsupported layout: {A.layout}")
|
|
195
195
|
|
|
196
196
|
if ctx.batch_size is not None:
|
|
197
|
-
grad_for_A =
|
|
197
|
+
grad_for_A = grad.reshape(-1, grad.size(-1))
|
|
198
198
|
else:
|
|
199
199
|
grad_for_A = grad
|
|
200
200
|
|
|
@@ -221,7 +221,7 @@ class SparseMatMul(torch.autograd.Function):
|
|
|
221
221
|
# -------- Only compute gradB if needed --------
|
|
222
222
|
if ctx.needs_input_grad[1]:
|
|
223
223
|
if ctx.batch_size is not None:
|
|
224
|
-
grad_for_B =
|
|
224
|
+
grad_for_B = grad.reshape(-1, grad.size(-1))
|
|
225
225
|
else:
|
|
226
226
|
grad_for_B = grad
|
|
227
227
|
|
{torchsparsegradutils-0.2.1 → torchsparsegradutils-0.2.2}/torchsparsegradutils/sparse_solve.py
RENAMED
|
@@ -171,7 +171,7 @@ class SparseTriangularSolve(torch.autograd.Function):
|
|
|
171
171
|
|
|
172
172
|
if ctx.batch_size is not None:
|
|
173
173
|
A = sparse_block_diag(*A)
|
|
174
|
-
B =
|
|
174
|
+
B = B.reshape(-1, B.size(-1))
|
|
175
175
|
|
|
176
176
|
if A.layout == torch.sparse_coo:
|
|
177
177
|
A = convert_coo_to_csr(A) # NOTE: triangular solve doesn't work with sparse coo
|
|
@@ -194,7 +194,7 @@ class SparseTriangularSolve(torch.autograd.Function):
|
|
|
194
194
|
@staticmethod
|
|
195
195
|
def backward(ctx, grad): # type: ignore[override]
|
|
196
196
|
if ctx.batch_size is not None:
|
|
197
|
-
grad =
|
|
197
|
+
grad = grad.reshape(-1, grad.size(-1))
|
|
198
198
|
|
|
199
199
|
A, x = ctx.saved_tensors
|
|
200
200
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import random
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pytest
|
|
6
|
+
import torch
|
|
7
|
+
|
|
8
|
+
SEED = 42
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _seed_unlocked() -> bool:
|
|
12
|
+
unlock = os.getenv("TSGU_UNLOCK_SEED", os.getenv("UNLOCK_SEED", "false"))
|
|
13
|
+
return unlock.lower() in {"1", "true", "yes", "on"}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _seed_all(seed: int = SEED) -> None:
|
|
17
|
+
random.seed(seed)
|
|
18
|
+
np.random.seed(seed)
|
|
19
|
+
torch.manual_seed(seed)
|
|
20
|
+
if torch.cuda.is_available():
|
|
21
|
+
torch.cuda.manual_seed_all(seed)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def pytest_configure(config):
|
|
25
|
+
if not _seed_unlocked():
|
|
26
|
+
_seed_all()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.fixture(autouse=True)
|
|
30
|
+
def seed_rng():
|
|
31
|
+
if _seed_unlocked():
|
|
32
|
+
yield
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
torch_state = torch.get_rng_state()
|
|
36
|
+
cuda_states = torch.cuda.get_rng_state_all() if torch.cuda.is_available() else None
|
|
37
|
+
random_state = random.getstate()
|
|
38
|
+
numpy_state = np.random.get_state()
|
|
39
|
+
|
|
40
|
+
_seed_all()
|
|
41
|
+
try:
|
|
42
|
+
yield
|
|
43
|
+
finally:
|
|
44
|
+
torch.set_rng_state(torch_state)
|
|
45
|
+
if cuda_states is not None:
|
|
46
|
+
torch.cuda.set_rng_state_all(cuda_states)
|
|
47
|
+
random.setstate(random_state)
|
|
48
|
+
np.random.set_state(numpy_state)
|