scm2cpp-lasso 0.13.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.13.0 → scm2cpp_lasso-0.13.1}/PKG-INFO +104 -4
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/README.md +103 -3
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/pyproject.toml +1 -1
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/setup.py +24 -1
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/__init__.py +1 -1
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/scm2cpp.hpp +31 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso.egg-info/PKG-INFO +104 -4
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/setup.cfg +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/__init__.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_accel_cublas.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_classifiers.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_derived_blas.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_derived_cublas.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_derived_loops.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_gpu_cuda.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_gramops_blas.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_gramops_loops.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_nmf_blas.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_nmf_cublas.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_nmf_loops.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/classifiers.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/classifiers.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/classifiers_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_blas/lasso_design_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_cublas/lasso_design_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/derived_loops/lasso_design_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/lasso_cov.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/lasso_cov.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/lasso_cov_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd_capi.cpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/scm2cpp-blas.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/scm2cpp-cublas.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/scm2cpp-cuda.hpp +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_libfind.py +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/batch_capi.cu +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso.egg-info/SOURCES.txt +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso.egg-info/dependency_links.txt +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso.egg-info/requires.txt +0 -0
- {scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scm2cpp-lasso
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.1
|
|
4
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
|
|
@@ -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,39 @@ 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
|
+
|
|
736
836
|
## The GPU build
|
|
737
837
|
|
|
738
838
|
Where the CUDA toolkit is at install time, `ParallelFastICA`,
|
|
@@ -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,39 @@ 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
|
+
|
|
718
818
|
## The GPU build
|
|
719
819
|
|
|
720
820
|
Where the CUDA toolkit is at install time, `ParallelFastICA`,
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scm2cpp-lasso"
|
|
7
|
-
version = "0.13.
|
|
7
|
+
version = "0.13.1"
|
|
8
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"
|
|
@@ -242,4 +242,27 @@ if _cuda is not None:
|
|
|
242
242
|
extra_compile_args=CXXFLAGS + ["-O3", "-fstrict-overflow"],
|
|
243
243
|
))
|
|
244
244
|
|
|
245
|
-
|
|
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.13.
|
|
54
|
+
__version__ = "0.13.1"
|
|
55
55
|
|
|
56
56
|
_BATCH = load_batch_lib()
|
|
57
57
|
_DP = ctypes.POINTER(ctypes.c_double)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
#include <iostream>
|
|
5
5
|
#include <vector>
|
|
6
|
+
#include <string>
|
|
6
7
|
#include <list>
|
|
7
8
|
#include <map>
|
|
8
9
|
#include <algorithm>
|
|
@@ -1459,6 +1460,36 @@ namespace scm2cpp {
|
|
|
1459
1460
|
std::size_t size() const { return n; }
|
|
1460
1461
|
};
|
|
1461
1462
|
|
|
1463
|
+
// A memo for a pure call: (memo-call M E KEY ...) is
|
|
1464
|
+
// memo_get(M, memo_key().add(KEY)...str(), [&]() { return E; })
|
|
1465
|
+
// M a hash table from the key's bytes to E's value (the translator's
|
|
1466
|
+
// (make-hash), an std::unordered_map<std::string, V>), so E runs once
|
|
1467
|
+
// per distinct key. A key is scalars by value and, through
|
|
1468
|
+
// add_range, the first N elements of an array -- the index set a
|
|
1469
|
+
// gather read, say. The bytes are the values' object representation,
|
|
1470
|
+
// so 0.0 and -0.0 are different keys (a miss, never a wrong hit).
|
|
1471
|
+
struct memo_key {
|
|
1472
|
+
std::string b;
|
|
1473
|
+
template<typename T> memo_key& add(const T& v) {
|
|
1474
|
+
b.append(reinterpret_cast<const char*>(&v), sizeof(T));
|
|
1475
|
+
return *this;
|
|
1476
|
+
}
|
|
1477
|
+
template<typename V> memo_key& add_range(const V& v, long n) {
|
|
1478
|
+
add(n);
|
|
1479
|
+
for (long i = 0; i < n; ++i) add(v[i]);
|
|
1480
|
+
return *this;
|
|
1481
|
+
}
|
|
1482
|
+
const std::string& str() const { return b; }
|
|
1483
|
+
};
|
|
1484
|
+
template<typename M, typename F>
|
|
1485
|
+
inline typename M::mapped_type memo_get(M& m, const std::string& k, F f) {
|
|
1486
|
+
auto it = m.find(k);
|
|
1487
|
+
if (it != m.end()) return it->second;
|
|
1488
|
+
typename M::mapped_type v = f();
|
|
1489
|
+
m.emplace(k, v);
|
|
1490
|
+
return v;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1462
1493
|
template<typename T, int N> struct integral_image {
|
|
1463
1494
|
std::vector<T> table; // padded with a zero border: dim[k]+1 per axis
|
|
1464
1495
|
int dim[N]; // extents of the source array
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scm2cpp-lasso
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.1
|
|
4
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
|
|
@@ -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,39 @@ 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
|
+
|
|
736
836
|
## The GPU build
|
|
737
837
|
|
|
738
838
|
Where the CUDA toolkit is at install time, `ParallelFastICA`,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_accel_cublas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_classifiers.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_derived_blas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_derived_cublas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_derived_loops.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_gpu_cuda.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_gramops_blas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_gramops_loops.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_nmf_blas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_nmf_cublas.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/_loader_nmf_loops.py
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/accel_cublas/accel.hpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/classifiers_capi.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gpu_cuda/gpu_capi.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_blas/gramops.hpp
RENAMED
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/gramops_loops/gramops.hpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/lasso_cov_capi.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd.hpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_blas/nmf_cd_capi.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_cublas/nmf_cd.hpp
RENAMED
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.cpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd.hpp
RENAMED
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/nmf_loops/nmf_cd_capi.cpp
RENAMED
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso/_generated/scm2cpp-cublas.hpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scm2cpp_lasso-0.13.0 → scm2cpp_lasso-0.13.1}/src/scm2cpp_lasso.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|