scm2cpp-lasso 0.12.0__tar.gz → 0.13.1__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.
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/PKG-INFO +119 -5
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/README.md +117 -3
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/pyproject.toml +3 -3
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/setup.py +46 -1
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/__init__.py +20 -7
- scm2cpp_lasso-0.13.1/src/scm2cpp_lasso/_generated/_loader_gpu_cuda.py +294 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_gramops_blas.py +3 -6
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_gramops_loops.py +3 -6
- scm2cpp_lasso-0.13.1/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.cpp +35 -0
- scm2cpp_lasso-0.13.1/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.hpp +3715 -0
- scm2cpp_lasso-0.13.1/src/scm2cpp_lasso/_generated/gpu_cuda/gpu_capi.cpp +289 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.hpp +36 -22
- {scm2cpp_lasso-0.12.0/src/scm2cpp_lasso/_generated/gramops_loops → scm2cpp_lasso-0.13.1/src/scm2cpp_lasso/_generated/gramops_blas}/gramops_capi.cpp +2 -2
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.hpp +170 -146
- {scm2cpp_lasso-0.12.0/src/scm2cpp_lasso/_generated/gramops_blas → scm2cpp_lasso-0.13.1/src/scm2cpp_lasso/_generated/gramops_loops}/gramops_capi.cpp +2 -2
- scm2cpp_lasso-0.13.1/src/scm2cpp_lasso/_generated/scm2cpp-cuda.hpp +285 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/scm2cpp.hpp +49 -7
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_libfind.py +12 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso.egg-info/PKG-INFO +119 -5
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso.egg-info/SOURCES.txt +5 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/setup.cfg +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/__init__.py +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader.py +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_accel_cublas.py +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_classifiers.py +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_derived_blas.py +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_derived_cublas.py +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_derived_loops.py +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_nmf_blas.py +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_nmf_cublas.py +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_nmf_loops.py +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel.hpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel_capi.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/classifiers.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/classifiers.hpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/classifiers_capi.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.hpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design_capi.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.hpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design_capi.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.hpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design_capi.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/lasso_cov.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/lasso_cov.hpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/lasso_cov_capi.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.hpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.hpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.hpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd_capi.cpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/scm2cpp-blas.hpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/scm2cpp-cublas.hpp +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/batch_capi.cu +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso.egg-info/dependency_links.txt +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso.egg-info/requires.txt +0 -0
- {scm2cpp_lasso-0.12.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso.egg-info/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scm2cpp-lasso
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: scikit-learn estimators (lasso, elastic net, ridge, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver included
|
|
3
|
+
Version: 0.13.1
|
|
4
|
+
Summary: scikit-learn estimators (lasso, elastic net, ridge, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included
|
|
5
5
|
Author: Hirotaka Niitsuma
|
|
6
6
|
License: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/niitsuma/scm2cpp
|
|
@@ -28,9 +28,19 @@ path. The solver is Scheme, translated to C++ by
|
|
|
28
28
|
$ pip install scm2cpp-lasso
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
On Linux x86_64 and macOS arm64 (macOS 14 or later) this installs a wheel: compiled, with
|
|
32
|
+
OpenBLAS inside, nothing to build. Elsewhere pip builds the sdist,
|
|
33
|
+
which needs a C++17 compiler and nothing else. The wheels carry no
|
|
34
|
+
GPU code (a wheel cannot know the device); for the GPU builds, install
|
|
35
|
+
from the sdist on a machine with `nvcc` on the path:
|
|
36
|
+
|
|
37
|
+
```console
|
|
38
|
+
$ pip install --no-binary scm2cpp-lasso scm2cpp-lasso
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The batched GPU solver, the cuBLAS variants and the `--cuda`
|
|
42
|
+
estimators are then built as well; without `nvcc` the package installs
|
|
43
|
+
and works exactly the same, minus those.
|
|
34
44
|
|
|
35
45
|
Three of a hundred candidate columns carry the signal; the solver is
|
|
36
46
|
asked which, and answers with them and nothing else:
|
|
@@ -89,6 +99,63 @@ at zero, and `lambda_grid()` walks down from it -- the construction
|
|
|
89
99
|
scikit-learn uses. If your columns differ wildly in scale, standardize
|
|
90
100
|
them first; this solver does not do it for you.
|
|
91
101
|
|
|
102
|
+
## Estimators at a glance
|
|
103
|
+
|
|
104
|
+
Every estimator, the scikit-learn estimator it reproduces, the Scheme
|
|
105
|
+
kernel under `examples/kernel-only/` it is translated from, the builds
|
|
106
|
+
it runs on, and whether Intel's sklearnex accelerates the scikit-learn
|
|
107
|
+
side. Builds: *loops* is the plain translation, *BLAS* / *cuBLAS* the
|
|
108
|
+
products handed to (cu)BLAS, *--cuda* the translator's GPU kernels
|
|
109
|
+
(`gpu_cuda/`), *GPU batch* the hand-written CUDA batch solver; the
|
|
110
|
+
package picks the fastest one present. None of the classes derives
|
|
111
|
+
from scikit-learn's `BaseEstimator` yet, so `clone`, `GridSearchCV`
|
|
112
|
+
and `check_estimator` do not apply to them.
|
|
113
|
+
|
|
114
|
+
| class | scikit-learn | Scheme kernel | builds | sklearnex accelerates |
|
|
115
|
+
|---|---|---|---|---|
|
|
116
|
+
| `CovLasso` | Lasso, ElasticNet, lasso_path(precompute=True) | `lasso-cov.scm` | CPU; GPU batch (fit_path_batch, bootstrap) | no |
|
|
117
|
+
| `CovLassoCV` | LassoCV, ElasticNetCV | `lasso-cov.scm` | CPU; GPU batch | no |
|
|
118
|
+
| `DerivedLasso` | lasso_path, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
|
|
119
|
+
| `CovMultiTaskLasso` | MultiTaskLasso, MultiTaskElasticNet | `lasso-cov.scm` | CPU | no |
|
|
120
|
+
| `CovMultiTaskLassoCV` | MultiTaskLassoCV, MultiTaskElasticNetCV | `lasso-cov.scm` | CPU; GPU batch | no |
|
|
121
|
+
| `CovGroupLasso` | (none; skglm GroupLasso) | `lasso-cov.scm` | CPU | - |
|
|
122
|
+
| `CovLogistic` | LogisticRegression(penalty='l1'), by majorization | `lasso-cov.scm` | CPU | no |
|
|
123
|
+
| `CovRidge` | Ridge(fit_intercept=False), a whole alpha path | `lasso-cov.scm` | CPU | Ridge |
|
|
124
|
+
| `CovBayesianRidge` | BayesianRidge | `lasso-cov.scm` | CPU | no |
|
|
125
|
+
| `CovARDRegression` | ARDRegression (n >= p) | `ard.scm` | loops / BLAS | no |
|
|
126
|
+
| `GramLars` | Lars | `lars.scm` | CPU | no |
|
|
127
|
+
| `GramLassoLars` | LassoLars | `lars.scm` | CPU | no |
|
|
128
|
+
| `GramLassoLarsIC` | LassoLarsIC | `lars.scm` | CPU; device Gram | no |
|
|
129
|
+
| `GramLarsCV` | LarsCV | `lars.scm` | CPU | no |
|
|
130
|
+
| `GramLassoLarsCV` | LassoLarsCV | `lars.scm` | CPU; device Gram | no |
|
|
131
|
+
| `GramOMP` | OrthogonalMatchingPursuit | `omp.scm` | loops / BLAS | no |
|
|
132
|
+
| `GramOMPCV` | OrthogonalMatchingPursuitCV | `omp.scm` | loops / BLAS | no |
|
|
133
|
+
| `LBFGSLogisticRegression` | LogisticRegression(solver='lbfgs') | `logistic-lbfgs.scm, lbfgs.scm` | loops / BLAS / --cuda | LogisticRegression |
|
|
134
|
+
| `LBFGSLogisticRegressionCV` | LogisticRegressionCV | `logistic-lbfgs.scm, lbfgs.scm` | loops / BLAS / --cuda | no |
|
|
135
|
+
| `LBFGSHuberRegressor` | HuberRegressor | `huber.scm, lbfgs.scm` | loops / BLAS / --cuda | no |
|
|
136
|
+
| `LBFGSPoissonRegressor` | PoissonRegressor | `glm.scm, lbfgs.scm` | loops / BLAS / --cuda | no |
|
|
137
|
+
| `LBFGSGammaRegressor` | GammaRegressor | `glm.scm, lbfgs.scm` | loops / BLAS / --cuda | no |
|
|
138
|
+
| `LBFGSTweedieRegressor` | TweedieRegressor | `glm.scm, lbfgs.scm` | loops / BLAS / --cuda | no |
|
|
139
|
+
| `LinearSVM` | LinearSVC(loss='hinge') | `svm-liblinear.scm` | CPU | no |
|
|
140
|
+
| `L1LinearSVM` | LinearSVC(penalty='l1', dual=False) | `svm-l1.scm` | CPU | no |
|
|
141
|
+
| `KernelSVM` | SVC | `svm-smo.scm` | CPU | SVC |
|
|
142
|
+
| `LinearSVR` | LinearSVR | `svr-liblinear.scm` | CPU | no |
|
|
143
|
+
| `KernelSVR` | SVR | `svm-smo.scm` | CPU | SVR |
|
|
144
|
+
| `L1LogisticRegression` | LogisticRegression(penalty='l1', solver='liblinear') | `logistic-l1.scm` | CPU | no |
|
|
145
|
+
| `SGDLinearClassifier` | SGDClassifier(shuffle=False) | `sgd.scm` | CPU | no |
|
|
146
|
+
| `SGDLinearRegressor` | SGDRegressor(shuffle=False) | `sgd.scm` | CPU | no |
|
|
147
|
+
| `SGDPerceptron` | Perceptron(shuffle=False) | `sgd.scm` | CPU | no |
|
|
148
|
+
| `LinearRANSAC` | RANSACRegressor (given subsets) | `ransac.scm` | CPU | no |
|
|
149
|
+
| `WeiszfeldTheilSen` | TheilSenRegressor | `theilsen.scm` | CPU | no |
|
|
150
|
+
| `CDNMF` | NMF(solver='cd') | `nmf-cd.scm (--derive)` | loops / BLAS / cuBLAS | no |
|
|
151
|
+
| `CDGraphicalLasso` | GraphicalLasso | `graphical-lasso.scm` | loops / BLAS | no |
|
|
152
|
+
| `EMGaussianMixture` | GaussianMixture(covariance_type='full') | `gmm.scm` | loops / BLAS / --cuda | no |
|
|
153
|
+
| `ParallelFastICA` | FastICA | `fastica.scm` | loops / BLAS / --cuda | no |
|
|
154
|
+
| `CovPCA` | PCA(svd_solver='covariance_eigh') | `pca.scm` | loops / BLAS / cuBLAS | PCA |
|
|
155
|
+
| `f_regression, f_classif` | f_regression, f_classif | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
156
|
+
| `SelectKBest, SelectPercentile` | SelectKBest, SelectPercentile | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
157
|
+
| `GramRFE` | RFE(Ridge), RFE(LinearRegression) | `rfe.scm` | loops / BLAS / cuBLAS | inside: Ridge |
|
|
158
|
+
|
|
92
159
|
## Two kernels: `CovLasso` and `DerivedLasso`
|
|
93
160
|
|
|
94
161
|
Everything above, and the cross-validation, bootstrap and GPU methods
|
|
@@ -733,6 +800,53 @@ estimators (`GramLassoLarsIC`, `GramLarsCV`, `GramLassoLarsCV`,
|
|
|
733
800
|
`GramLars`, `GramLassoLars`, `CovPCA`) form a large X'X on the device
|
|
734
801
|
when one answers. `SCM2CPP_NO_DEVICE=1` keeps everything on the CPU.
|
|
735
802
|
|
|
803
|
+
## Against Intel's sklearnex
|
|
804
|
+
|
|
805
|
+
sklearnex (scikit-learn-intelex 2026.2, oneDAL underneath) replaces
|
|
806
|
+
some scikit-learn estimators with its own. `bench/sklearnex-compare.py`
|
|
807
|
+
times the ones with a counterpart here, sklearnex's estimators
|
|
808
|
+
imported directly (not patched in) so that scikit-learn itself is
|
|
809
|
+
timed in the same process. The ratios are scikit-learn's or
|
|
810
|
+
sklearnex's time over the package's best (its CPU build, or the device
|
|
811
|
+
build where one answers); the load average was 8 to 11, so the times
|
|
812
|
+
move by some tens of percent.
|
|
813
|
+
|
|
814
|
+
| estimator, n x p | iterations (sk / sklearnex / ours) | vs scikit-learn, one core | vs sklearnex, one core | vs sklearnex, 20 cores |
|
|
815
|
+
|---|---|---|---|---|
|
|
816
|
+
| LogisticRegression, 200,000 x 100 | 6 / 12 / 6 | 10.6x (device) | 8.4x (device) | 4.4x (device); on the CPU 0.5x |
|
|
817
|
+
| Ridge (alpha 1), 200,000 x 200 | - | 2.1x | 1.2x | 0.3x |
|
|
818
|
+
| PCA (10 components), 100,000 x 50 | - | 1.5x | 2.4x | 1.7x |
|
|
819
|
+
| PCA (10 components), 50,000 x 500 | - | 1.1x | 1.4x | 0.5x |
|
|
820
|
+
| SVC (rbf), 5,000 x 20 | 4,858 / 7 / 4,882 | 1.2x | 1.4x | 0.5x |
|
|
821
|
+
| SVR (rbf), 5,000 x 20 | 12,821 / 10 / 12,824 | 1.3x | 1.4x | 0.4x |
|
|
822
|
+
| RFE(Ridge), 20 of 200 kept, 20,000 x 200 | - | 216x | 128x | 78x |
|
|
823
|
+
|
|
824
|
+
On one core the package is ahead everywhere. sklearnex uses every
|
|
825
|
+
core by default, and the package's kernels are single-threaded, so
|
|
826
|
+
with 20 cores sklearnex is faster on Ridge, the larger PCA and the
|
|
827
|
+
SVMs; what stays ahead is the device build (logistic regression) and
|
|
828
|
+
an algorithm that does less work (RFE: the Gram once, the Cholesky
|
|
829
|
+
factor downdated per drop, where scikit-learn refits). sklearnex is
|
|
830
|
+
not scikit-learn's arithmetic: its logistic regression takes 12
|
|
831
|
+
iterations to scikit-learn's 6 and its coefficients differ from
|
|
832
|
+
scikit-learn's by 6e-3, where the package's agree to 4e-15; its SVMs
|
|
833
|
+
report a different iteration count. This sklearnex accelerates no
|
|
834
|
+
lasso, so the lasso tables above stand against scikit-learn alone.
|
|
835
|
+
|
|
836
|
+
## The GPU build
|
|
837
|
+
|
|
838
|
+
Where the CUDA toolkit is at install time, `ParallelFastICA`,
|
|
839
|
+
`EMGaussianMixture`, `LBFGSLogisticRegression`,
|
|
840
|
+
`LBFGSLogisticRegressionCV`, `LBFGSHuberRegressor` and the `LBFGS*`
|
|
841
|
+
GLMs also get the same Scheme translated with `--cuda`
|
|
842
|
+
(`libscm2cpp_gpu.so`). Its loops are CUDA kernels and its products
|
|
843
|
+
cuBLAS, on arrays that stay on the device. The classes take it when a
|
|
844
|
+
device answers and the data has a million entries or more, and give
|
|
845
|
+
the CPU build's iterations and results to the last digits. Measured
|
|
846
|
+
against scikit-learn: 10-22x for the L-BFGS fits, 6.7x FastICA, 3x the
|
|
847
|
+
mixture and LogisticRegressionCV (the repository README's table).
|
|
848
|
+
`SCM2CPP_NO_DEVICE=1` keeps everything on the CPU.
|
|
849
|
+
|
|
736
850
|
## Logistic regression with L1
|
|
737
851
|
|
|
738
852
|
`CovLogistic` solves L1-penalized logistic regression by
|
|
@@ -10,9 +10,19 @@ path. The solver is Scheme, translated to C++ by
|
|
|
10
10
|
$ pip install scm2cpp-lasso
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
On Linux x86_64 and macOS arm64 (macOS 14 or later) this installs a wheel: compiled, with
|
|
14
|
+
OpenBLAS inside, nothing to build. Elsewhere pip builds the sdist,
|
|
15
|
+
which needs a C++17 compiler and nothing else. The wheels carry no
|
|
16
|
+
GPU code (a wheel cannot know the device); for the GPU builds, install
|
|
17
|
+
from the sdist on a machine with `nvcc` on the path:
|
|
18
|
+
|
|
19
|
+
```console
|
|
20
|
+
$ pip install --no-binary scm2cpp-lasso scm2cpp-lasso
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The batched GPU solver, the cuBLAS variants and the `--cuda`
|
|
24
|
+
estimators are then built as well; without `nvcc` the package installs
|
|
25
|
+
and works exactly the same, minus those.
|
|
16
26
|
|
|
17
27
|
Three of a hundred candidate columns carry the signal; the solver is
|
|
18
28
|
asked which, and answers with them and nothing else:
|
|
@@ -71,6 +81,63 @@ at zero, and `lambda_grid()` walks down from it -- the construction
|
|
|
71
81
|
scikit-learn uses. If your columns differ wildly in scale, standardize
|
|
72
82
|
them first; this solver does not do it for you.
|
|
73
83
|
|
|
84
|
+
## Estimators at a glance
|
|
85
|
+
|
|
86
|
+
Every estimator, the scikit-learn estimator it reproduces, the Scheme
|
|
87
|
+
kernel under `examples/kernel-only/` it is translated from, the builds
|
|
88
|
+
it runs on, and whether Intel's sklearnex accelerates the scikit-learn
|
|
89
|
+
side. Builds: *loops* is the plain translation, *BLAS* / *cuBLAS* the
|
|
90
|
+
products handed to (cu)BLAS, *--cuda* the translator's GPU kernels
|
|
91
|
+
(`gpu_cuda/`), *GPU batch* the hand-written CUDA batch solver; the
|
|
92
|
+
package picks the fastest one present. None of the classes derives
|
|
93
|
+
from scikit-learn's `BaseEstimator` yet, so `clone`, `GridSearchCV`
|
|
94
|
+
and `check_estimator` do not apply to them.
|
|
95
|
+
|
|
96
|
+
| class | scikit-learn | Scheme kernel | builds | sklearnex accelerates |
|
|
97
|
+
|---|---|---|---|---|
|
|
98
|
+
| `CovLasso` | Lasso, ElasticNet, lasso_path(precompute=True) | `lasso-cov.scm` | CPU; GPU batch (fit_path_batch, bootstrap) | no |
|
|
99
|
+
| `CovLassoCV` | LassoCV, ElasticNetCV | `lasso-cov.scm` | CPU; GPU batch | no |
|
|
100
|
+
| `DerivedLasso` | lasso_path, from the design | `lasso-design.scm (--derive)` | loops / BLAS / cuBLAS | no |
|
|
101
|
+
| `CovMultiTaskLasso` | MultiTaskLasso, MultiTaskElasticNet | `lasso-cov.scm` | CPU | no |
|
|
102
|
+
| `CovMultiTaskLassoCV` | MultiTaskLassoCV, MultiTaskElasticNetCV | `lasso-cov.scm` | CPU; GPU batch | no |
|
|
103
|
+
| `CovGroupLasso` | (none; skglm GroupLasso) | `lasso-cov.scm` | CPU | - |
|
|
104
|
+
| `CovLogistic` | LogisticRegression(penalty='l1'), by majorization | `lasso-cov.scm` | CPU | no |
|
|
105
|
+
| `CovRidge` | Ridge(fit_intercept=False), a whole alpha path | `lasso-cov.scm` | CPU | Ridge |
|
|
106
|
+
| `CovBayesianRidge` | BayesianRidge | `lasso-cov.scm` | CPU | no |
|
|
107
|
+
| `CovARDRegression` | ARDRegression (n >= p) | `ard.scm` | loops / BLAS | no |
|
|
108
|
+
| `GramLars` | Lars | `lars.scm` | CPU | no |
|
|
109
|
+
| `GramLassoLars` | LassoLars | `lars.scm` | CPU | no |
|
|
110
|
+
| `GramLassoLarsIC` | LassoLarsIC | `lars.scm` | CPU; device Gram | no |
|
|
111
|
+
| `GramLarsCV` | LarsCV | `lars.scm` | CPU | no |
|
|
112
|
+
| `GramLassoLarsCV` | LassoLarsCV | `lars.scm` | CPU; device Gram | no |
|
|
113
|
+
| `GramOMP` | OrthogonalMatchingPursuit | `omp.scm` | loops / BLAS | no |
|
|
114
|
+
| `GramOMPCV` | OrthogonalMatchingPursuitCV | `omp.scm` | loops / BLAS | no |
|
|
115
|
+
| `LBFGSLogisticRegression` | LogisticRegression(solver='lbfgs') | `logistic-lbfgs.scm, lbfgs.scm` | loops / BLAS / --cuda | LogisticRegression |
|
|
116
|
+
| `LBFGSLogisticRegressionCV` | LogisticRegressionCV | `logistic-lbfgs.scm, lbfgs.scm` | loops / BLAS / --cuda | no |
|
|
117
|
+
| `LBFGSHuberRegressor` | HuberRegressor | `huber.scm, lbfgs.scm` | loops / BLAS / --cuda | no |
|
|
118
|
+
| `LBFGSPoissonRegressor` | PoissonRegressor | `glm.scm, lbfgs.scm` | loops / BLAS / --cuda | no |
|
|
119
|
+
| `LBFGSGammaRegressor` | GammaRegressor | `glm.scm, lbfgs.scm` | loops / BLAS / --cuda | no |
|
|
120
|
+
| `LBFGSTweedieRegressor` | TweedieRegressor | `glm.scm, lbfgs.scm` | loops / BLAS / --cuda | no |
|
|
121
|
+
| `LinearSVM` | LinearSVC(loss='hinge') | `svm-liblinear.scm` | CPU | no |
|
|
122
|
+
| `L1LinearSVM` | LinearSVC(penalty='l1', dual=False) | `svm-l1.scm` | CPU | no |
|
|
123
|
+
| `KernelSVM` | SVC | `svm-smo.scm` | CPU | SVC |
|
|
124
|
+
| `LinearSVR` | LinearSVR | `svr-liblinear.scm` | CPU | no |
|
|
125
|
+
| `KernelSVR` | SVR | `svm-smo.scm` | CPU | SVR |
|
|
126
|
+
| `L1LogisticRegression` | LogisticRegression(penalty='l1', solver='liblinear') | `logistic-l1.scm` | CPU | no |
|
|
127
|
+
| `SGDLinearClassifier` | SGDClassifier(shuffle=False) | `sgd.scm` | CPU | no |
|
|
128
|
+
| `SGDLinearRegressor` | SGDRegressor(shuffle=False) | `sgd.scm` | CPU | no |
|
|
129
|
+
| `SGDPerceptron` | Perceptron(shuffle=False) | `sgd.scm` | CPU | no |
|
|
130
|
+
| `LinearRANSAC` | RANSACRegressor (given subsets) | `ransac.scm` | CPU | no |
|
|
131
|
+
| `WeiszfeldTheilSen` | TheilSenRegressor | `theilsen.scm` | CPU | no |
|
|
132
|
+
| `CDNMF` | NMF(solver='cd') | `nmf-cd.scm (--derive)` | loops / BLAS / cuBLAS | no |
|
|
133
|
+
| `CDGraphicalLasso` | GraphicalLasso | `graphical-lasso.scm` | loops / BLAS | no |
|
|
134
|
+
| `EMGaussianMixture` | GaussianMixture(covariance_type='full') | `gmm.scm` | loops / BLAS / --cuda | no |
|
|
135
|
+
| `ParallelFastICA` | FastICA | `fastica.scm` | loops / BLAS / --cuda | no |
|
|
136
|
+
| `CovPCA` | PCA(svd_solver='covariance_eigh') | `pca.scm` | loops / BLAS / cuBLAS | PCA |
|
|
137
|
+
| `f_regression, f_classif` | f_regression, f_classif | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
138
|
+
| `SelectKBest, SelectPercentile` | SelectKBest, SelectPercentile | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
139
|
+
| `GramRFE` | RFE(Ridge), RFE(LinearRegression) | `rfe.scm` | loops / BLAS / cuBLAS | inside: Ridge |
|
|
140
|
+
|
|
74
141
|
## Two kernels: `CovLasso` and `DerivedLasso`
|
|
75
142
|
|
|
76
143
|
Everything above, and the cross-validation, bootstrap and GPU methods
|
|
@@ -715,6 +782,53 @@ estimators (`GramLassoLarsIC`, `GramLarsCV`, `GramLassoLarsCV`,
|
|
|
715
782
|
`GramLars`, `GramLassoLars`, `CovPCA`) form a large X'X on the device
|
|
716
783
|
when one answers. `SCM2CPP_NO_DEVICE=1` keeps everything on the CPU.
|
|
717
784
|
|
|
785
|
+
## Against Intel's sklearnex
|
|
786
|
+
|
|
787
|
+
sklearnex (scikit-learn-intelex 2026.2, oneDAL underneath) replaces
|
|
788
|
+
some scikit-learn estimators with its own. `bench/sklearnex-compare.py`
|
|
789
|
+
times the ones with a counterpart here, sklearnex's estimators
|
|
790
|
+
imported directly (not patched in) so that scikit-learn itself is
|
|
791
|
+
timed in the same process. The ratios are scikit-learn's or
|
|
792
|
+
sklearnex's time over the package's best (its CPU build, or the device
|
|
793
|
+
build where one answers); the load average was 8 to 11, so the times
|
|
794
|
+
move by some tens of percent.
|
|
795
|
+
|
|
796
|
+
| estimator, n x p | iterations (sk / sklearnex / ours) | vs scikit-learn, one core | vs sklearnex, one core | vs sklearnex, 20 cores |
|
|
797
|
+
|---|---|---|---|---|
|
|
798
|
+
| LogisticRegression, 200,000 x 100 | 6 / 12 / 6 | 10.6x (device) | 8.4x (device) | 4.4x (device); on the CPU 0.5x |
|
|
799
|
+
| Ridge (alpha 1), 200,000 x 200 | - | 2.1x | 1.2x | 0.3x |
|
|
800
|
+
| PCA (10 components), 100,000 x 50 | - | 1.5x | 2.4x | 1.7x |
|
|
801
|
+
| PCA (10 components), 50,000 x 500 | - | 1.1x | 1.4x | 0.5x |
|
|
802
|
+
| SVC (rbf), 5,000 x 20 | 4,858 / 7 / 4,882 | 1.2x | 1.4x | 0.5x |
|
|
803
|
+
| SVR (rbf), 5,000 x 20 | 12,821 / 10 / 12,824 | 1.3x | 1.4x | 0.4x |
|
|
804
|
+
| RFE(Ridge), 20 of 200 kept, 20,000 x 200 | - | 216x | 128x | 78x |
|
|
805
|
+
|
|
806
|
+
On one core the package is ahead everywhere. sklearnex uses every
|
|
807
|
+
core by default, and the package's kernels are single-threaded, so
|
|
808
|
+
with 20 cores sklearnex is faster on Ridge, the larger PCA and the
|
|
809
|
+
SVMs; what stays ahead is the device build (logistic regression) and
|
|
810
|
+
an algorithm that does less work (RFE: the Gram once, the Cholesky
|
|
811
|
+
factor downdated per drop, where scikit-learn refits). sklearnex is
|
|
812
|
+
not scikit-learn's arithmetic: its logistic regression takes 12
|
|
813
|
+
iterations to scikit-learn's 6 and its coefficients differ from
|
|
814
|
+
scikit-learn's by 6e-3, where the package's agree to 4e-15; its SVMs
|
|
815
|
+
report a different iteration count. This sklearnex accelerates no
|
|
816
|
+
lasso, so the lasso tables above stand against scikit-learn alone.
|
|
817
|
+
|
|
818
|
+
## The GPU build
|
|
819
|
+
|
|
820
|
+
Where the CUDA toolkit is at install time, `ParallelFastICA`,
|
|
821
|
+
`EMGaussianMixture`, `LBFGSLogisticRegression`,
|
|
822
|
+
`LBFGSLogisticRegressionCV`, `LBFGSHuberRegressor` and the `LBFGS*`
|
|
823
|
+
GLMs also get the same Scheme translated with `--cuda`
|
|
824
|
+
(`libscm2cpp_gpu.so`). Its loops are CUDA kernels and its products
|
|
825
|
+
cuBLAS, on arrays that stay on the device. The classes take it when a
|
|
826
|
+
device answers and the data has a million entries or more, and give
|
|
827
|
+
the CPU build's iterations and results to the last digits. Measured
|
|
828
|
+
against scikit-learn: 10-22x for the L-BFGS fits, 6.7x FastICA, 3x the
|
|
829
|
+
mixture and LogisticRegressionCV (the repository README's table).
|
|
830
|
+
`SCM2CPP_NO_DEVICE=1` keeps everything on the CPU.
|
|
831
|
+
|
|
718
832
|
## Logistic regression with L1
|
|
719
833
|
|
|
720
834
|
`CovLogistic` solves L1-penalized logistic regression by
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scm2cpp-lasso"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "scikit-learn estimators (lasso, elastic net, ridge, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver included"
|
|
7
|
+
version = "0.13.1"
|
|
8
|
+
description = "scikit-learn estimators (lasso, elastic net, ridge, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
11
11
|
license = {text = "MIT"}
|
|
@@ -31,4 +31,4 @@ package-dir = {"" = "src"}
|
|
|
31
31
|
where = ["src"]
|
|
32
32
|
|
|
33
33
|
[tool.setuptools.package-data]
|
|
34
|
-
scm2cpp_lasso = ["_generated/*.hpp", "_generated/*.cpp", "_generated/derived_*/*.hpp", "_generated/derived_*/*.cpp", "_generated/nmf_*/*.hpp", "_generated/nmf_*/*.cpp", "_generated/gramops_*/*.hpp", "_generated/gramops_*/*.cpp", "_generated/accel_*/*.hpp", "_generated/accel_*/*.cpp", "*.cu"]
|
|
34
|
+
scm2cpp_lasso = ["_generated/*.hpp", "_generated/*.cpp", "_generated/derived_*/*.hpp", "_generated/derived_*/*.cpp", "_generated/nmf_*/*.hpp", "_generated/nmf_*/*.cpp", "_generated/gramops_*/*.hpp", "_generated/gramops_*/*.cpp", "_generated/accel_*/*.hpp", "_generated/accel_*/*.cpp", "_generated/gpu_*/*.hpp", "_generated/gpu_*/*.cpp", "*.cu"]
|
|
@@ -120,6 +120,28 @@ class BuildWithCuda(build_ext):
|
|
|
120
120
|
except (subprocess.CalledProcessError, OSError) as exc:
|
|
121
121
|
print(f"scm2cpp_lasso: no CUDA batch path ({exc}); "
|
|
122
122
|
"the CPU solver is unaffected", file=sys.stderr)
|
|
123
|
+
# the --cuda translation (kernels + device-resident cuBLAS):
|
|
124
|
+
# FastICA, the mixture, the L-BFGS fits
|
|
125
|
+
gpu = GEN / "gpu_cuda" / "gpu_capi.cpp"
|
|
126
|
+
if gpu.exists():
|
|
127
|
+
out2 = Path(self.build_lib) / "scm2cpp_lasso" / "libscm2cpp_gpu.so"
|
|
128
|
+
# the installed device's architecture when one answers
|
|
129
|
+
arch = []
|
|
130
|
+
try:
|
|
131
|
+
if subprocess.run(["nvidia-smi"], capture_output=True).returncode == 0:
|
|
132
|
+
arch = ["-arch=native"]
|
|
133
|
+
except OSError:
|
|
134
|
+
pass
|
|
135
|
+
cmd2 = [nvcc, "-O3", "-std=c++17", "-shared", "-x", "cu", *arch,
|
|
136
|
+
"-Xcompiler", "-fPIC", "-I", str(GEN / "gpu_cuda"), "-I", str(GEN),
|
|
137
|
+
str(gpu), "-o", str(out2), "-lcublas",
|
|
138
|
+
"-Wno-deprecated-gpu-targets", "-diag-suppress", "174,177,550"]
|
|
139
|
+
try:
|
|
140
|
+
subprocess.run(cmd2, check=True)
|
|
141
|
+
print("scm2cpp_lasso: built the --cuda estimators")
|
|
142
|
+
except (subprocess.CalledProcessError, OSError) as exc:
|
|
143
|
+
print(f"scm2cpp_lasso: no --cuda estimators ({exc}); "
|
|
144
|
+
"the CPU paths are unaffected", file=sys.stderr)
|
|
123
145
|
|
|
124
146
|
|
|
125
147
|
# The cuBLAS variant of the derived kernel: host C++ against the CUDA
|
|
@@ -220,4 +242,27 @@ if _cuda is not None:
|
|
|
220
242
|
extra_compile_args=CXXFLAGS + ["-O3", "-fstrict-overflow"],
|
|
221
243
|
))
|
|
222
244
|
|
|
223
|
-
|
|
245
|
+
# A wheel is tagged py3-none-<platform>: the extensions are shared
|
|
246
|
+
# libraries the package loads through ctypes, using no Python API, so
|
|
247
|
+
# one build serves every Python on that platform.
|
|
248
|
+
try:
|
|
249
|
+
from setuptools.command.bdist_wheel import bdist_wheel
|
|
250
|
+
except ImportError: # setuptools before 70.1
|
|
251
|
+
try:
|
|
252
|
+
from wheel.bdist_wheel import bdist_wheel
|
|
253
|
+
except ImportError:
|
|
254
|
+
bdist_wheel = None
|
|
255
|
+
|
|
256
|
+
cmdclass = {"build_ext": BuildWithCuda}
|
|
257
|
+
if bdist_wheel is not None:
|
|
258
|
+
class PlatformWheel(bdist_wheel):
|
|
259
|
+
def finalize_options(self):
|
|
260
|
+
super().finalize_options()
|
|
261
|
+
self.root_is_pure = False
|
|
262
|
+
|
|
263
|
+
def get_tag(self):
|
|
264
|
+
return ("py3", "none", super().get_tag()[2])
|
|
265
|
+
|
|
266
|
+
cmdclass["bdist_wheel"] = PlatformWheel
|
|
267
|
+
|
|
268
|
+
setup(ext_modules=extensions, cmdclass=cmdclass)
|
|
@@ -51,7 +51,7 @@ __all__ = ["CovLasso", "CovRidge", "CovBayesianRidge", "CovLogistic", "CovGroupL
|
|
|
51
51
|
"SelectPercentile", "GramRFE",
|
|
52
52
|
"CovMultiTaskLasso", "CovMultiTaskLassoCV", "DerivedLasso",
|
|
53
53
|
"cuda_available", "derived_backend", "kernel"]
|
|
54
|
-
__version__ = "0.
|
|
54
|
+
__version__ = "0.13.1"
|
|
55
55
|
|
|
56
56
|
_BATCH = load_batch_lib()
|
|
57
57
|
_DP = ctypes.POINTER(ctypes.c_double)
|
|
@@ -1350,7 +1350,7 @@ class LBFGSLogisticRegression:
|
|
|
1350
1350
|
k = nc if multi else 1
|
|
1351
1351
|
coef = np.zeros(k * (p + 1))
|
|
1352
1352
|
out = np.zeros(2)
|
|
1353
|
-
it =
|
|
1353
|
+
it = _gpu_or_cpu(n * p, getattr(self, "backend", None)).logistic_lbfgs(
|
|
1354
1354
|
X, yi.astype(np.float64), coef, out, float(self.C), int(self.max_iter),
|
|
1355
1355
|
float(self.tol), multi, 1 if self.fit_intercept else 0, n, p, k)
|
|
1356
1356
|
self.coef_ = coef[:k * p].reshape(k, p).copy()
|
|
@@ -1418,7 +1418,7 @@ class _LBFGSGLM:
|
|
|
1418
1418
|
coef = np.zeros(p + 1)
|
|
1419
1419
|
out = np.zeros(2)
|
|
1420
1420
|
fam, power = self._family_power()
|
|
1421
|
-
it =
|
|
1421
|
+
it = _gpu_or_cpu(n * p, getattr(self, "backend", None)).glm(X, y, coef, out, fam, float(power), float(self.alpha),
|
|
1422
1422
|
int(self.max_iter), float(self.tol),
|
|
1423
1423
|
1 if self.fit_intercept else 0, n, p)
|
|
1424
1424
|
self.coef_, self.intercept_ = coef[:p].copy(), float(coef[p])
|
|
@@ -1499,7 +1499,7 @@ class LBFGSLogisticRegressionCV:
|
|
|
1499
1499
|
|
|
1500
1500
|
def _path(self, X, yi, Cs, coef, multi, k):
|
|
1501
1501
|
n, p = X.shape
|
|
1502
|
-
lib =
|
|
1502
|
+
lib = _gpu_or_cpu(n * p, getattr(self, "backend", None))
|
|
1503
1503
|
coefs, iters = [], []
|
|
1504
1504
|
out = np.zeros(2)
|
|
1505
1505
|
for C in Cs:
|
|
@@ -1582,7 +1582,7 @@ class LBFGSHuberRegressor:
|
|
|
1582
1582
|
coef = np.zeros(p + 2)
|
|
1583
1583
|
coef[-1] = 1.0
|
|
1584
1584
|
out = np.zeros(2)
|
|
1585
|
-
it =
|
|
1585
|
+
it = _gpu_or_cpu(n * p, getattr(self, "backend", None)).huber(
|
|
1586
1586
|
X, y, coef, out, float(self.epsilon), float(self.alpha), int(self.max_iter),
|
|
1587
1587
|
float(self.tol), 1 if self.fit_intercept else 0, n, p)
|
|
1588
1588
|
self.coef_ = coef[:p].copy()
|
|
@@ -1643,7 +1643,7 @@ class EMGaussianMixture:
|
|
|
1643
1643
|
self.precisions_cholesky_ = np.zeros((k, p, p))
|
|
1644
1644
|
labels = np.zeros(n)
|
|
1645
1645
|
out = np.zeros(2)
|
|
1646
|
-
it =
|
|
1646
|
+
it = _gpu_or_cpu(n * p, getattr(self, "backend", None)).gmm(X, resp, self.weights_, self.means_,
|
|
1647
1647
|
self.precisions_cholesky_, labels, out,
|
|
1648
1648
|
int(self.max_iter), float(self.tol),
|
|
1649
1649
|
float(self.reg_covar), n, p, k)
|
|
@@ -1744,7 +1744,7 @@ class ParallelFastICA:
|
|
|
1744
1744
|
w0 = np.ascontiguousarray(w0)
|
|
1745
1745
|
self.components_ = np.zeros((k, p)); self.whitening_ = np.zeros((k, p))
|
|
1746
1746
|
self._unmixing = np.zeros((k, k)); self.mean_ = np.zeros(p)
|
|
1747
|
-
self.n_iter_ =
|
|
1747
|
+
self.n_iter_ = _gpu_or_cpu(n * p, getattr(self, "backend", None)).fastica(
|
|
1748
1748
|
X, w0, self.components_, self.whitening_, self._unmixing, self.mean_,
|
|
1749
1749
|
int(self.max_iter), float(self.tol), n, p, k)
|
|
1750
1750
|
self.mixing_ = np.linalg.pinv(self.components_)
|
|
@@ -1803,6 +1803,19 @@ class CovARDRegression:
|
|
|
1803
1803
|
return np.ascontiguousarray(X, dtype=np.float64) @ self.coef_ + self.intercept_
|
|
1804
1804
|
|
|
1805
1805
|
|
|
1806
|
+
def _gpu_or_cpu(size, backend=None):
|
|
1807
|
+
"""The --cuda translation (kernels and device-resident cuBLAS) when it
|
|
1808
|
+
was built, a device answers, the backend allows it and the problem has
|
|
1809
|
+
at least a million entries; the CPU library otherwise."""
|
|
1810
|
+
import os
|
|
1811
|
+
from ._libfind import gpu_built
|
|
1812
|
+
if (backend in (None, "cuda") and size >= 1e6 and not os.environ.get("SCM2CPP_NO_DEVICE")
|
|
1813
|
+
and gpu_built() and cuda_available()):
|
|
1814
|
+
import importlib
|
|
1815
|
+
return importlib.import_module(f"{__name__}._generated._loader_gpu_cuda")
|
|
1816
|
+
return _gramops_kernels()
|
|
1817
|
+
|
|
1818
|
+
|
|
1806
1819
|
def _accel(work):
|
|
1807
1820
|
"""The --cublas build of the selection and Gram products, when it was
|
|
1808
1821
|
built, a device answers, and WORK (flops) is large enough to pay for
|