scm2cpp-learn 0.18.0__tar.gz → 0.20.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {scm2cpp_learn-0.18.0/src/scm2cpp_learn.egg-info → scm2cpp_learn-0.20.0}/PKG-INFO +146 -6
- scm2cpp_learn-0.18.0/PKG-INFO → scm2cpp_learn-0.20.0/README.md +144 -22
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/pyproject.toml +2 -2
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/__init__.py +654 -20
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_compat.py +70 -2
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_accel_cublas.py +12 -0
- scm2cpp_learn-0.18.0/src/scm2cpp_learn/_generated/_loader_gramops_loops.py → scm2cpp_learn-0.20.0/src/scm2cpp_learn/_generated/_loader_gramops_blas.py +149 -24
- scm2cpp_learn-0.18.0/src/scm2cpp_learn/_generated/_loader_gramops_blas.py → scm2cpp_learn-0.20.0/src/scm2cpp_learn/_generated/_loader_gramops_loops.py +168 -5
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/accel_cublas/accel.cpp +2 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/accel_cublas/accel.hpp +89 -17
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/accel_cublas/accel_capi.cpp +6 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/classifiers.hpp +18 -18
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_blas/lasso_design.hpp +12 -12
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_cublas/lasso_design.hpp +13 -13
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_loops/lasso_design.hpp +24 -24
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_blas/gramops.cpp +17 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_blas/gramops.hpp +1274 -30
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_blas/gramops_capi.cpp +53 -2
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_loops/gramops.cpp +17 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_loops/gramops.hpp +1700 -384
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_loops/gramops_capi.cpp +53 -2
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_blas/nmf_cd.hpp +13 -13
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_cublas/nmf_cd.hpp +17 -17
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_loops/nmf_cd.hpp +29 -29
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/scm2cpp-blas.hpp +18 -0
- scm2cpp_learn-0.18.0/README.md → scm2cpp_learn-0.20.0/src/scm2cpp_learn.egg-info/PKG-INFO +162 -4
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/setup.cfg +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/setup.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/__init__.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_classifiers.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_derived_blas.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_derived_cublas.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_derived_loops.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_gpu_cuda.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_nmf_blas.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_nmf_cublas.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_nmf_loops.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/classifiers.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/classifiers_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_blas/lasso_design.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_blas/lasso_design_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_cublas/lasso_design.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_cublas/lasso_design_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_loops/lasso_design.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_loops/lasso_design_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gpu_cuda/gpu.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gpu_cuda/gpu.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gpu_cuda/gpu_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/lasso_cov.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/lasso_cov.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/lasso_cov_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_blas/nmf_cd.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_blas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_cublas/nmf_cd.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_cublas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_loops/nmf_cd.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_loops/nmf_cd_capi.cpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/scm2cpp-cublas.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/scm2cpp-cuda.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/scm2cpp.hpp +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_libfind.py +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/batch_capi.cu +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn.egg-info/SOURCES.txt +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn.egg-info/dependency_links.txt +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn.egg-info/requires.txt +0 -0
- {scm2cpp_learn-0.18.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn.egg-info/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scm2cpp-learn
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, TruncatedSVD, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included
|
|
3
|
+
Version: 0.20.0
|
|
4
|
+
Summary: scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, TruncatedSVD, PLS, CCA, 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
|
|
@@ -206,9 +206,10 @@ package picks the fastest one present.
|
|
|
206
206
|
|
|
207
207
|
| class | scikit-learn | Scheme kernel | builds | sklearnex accelerates |
|
|
208
208
|
|---|---|---|---|---|
|
|
209
|
-
| `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
210
|
-
| `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
211
|
-
| `GramRidge` | Ridge, fit(X, y) with the intercept, one or many targets | `gram.scm` (Cholesky; dposv) | loops / BLAS | Ridge |
|
|
209
|
+
| `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept, dense or sparse X | `lasso-cov.scm` | CPU | no |
|
|
210
|
+
| `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept, dense or sparse X | `lasso-cov.scm` | CPU | no |
|
|
211
|
+
| `GramRidge` | Ridge, fit(X, y) with the intercept, one or many targets, dense or sparse X | `gram.scm` (Cholesky; dposv) | loops / BLAS | Ridge |
|
|
212
|
+
| `GramLinearRegression` | LinearRegression, dense or sparse X, sample_weight | `linreg.scm` (Cholesky; dposv, dpocon) | loops / BLAS | no |
|
|
212
213
|
| `GramRidgeCV` | RidgeCV (cv=None), leave-one-out over every alpha from one eigenproblem | `ridge-gcv.scm` | loops / BLAS | no |
|
|
213
214
|
| `GramMultiTaskLasso` | MultiTaskLasso, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
214
215
|
| `GramMultiTaskElasticNet` | MultiTaskElasticNet, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
@@ -256,7 +257,9 @@ package picks the fastest one present.
|
|
|
256
257
|
| `CovPCA` | PCA(svd_solver='covariance_eigh') | `pca.scm` | loops / BLAS / cuBLAS | PCA |
|
|
257
258
|
| `GramKernelPCA` | KernelPCA (no inverse_transform) | `kernel-pca.scm` | loops / BLAS | no |
|
|
258
259
|
| `GramLDA` | LinearDiscriminantAnalysis (svd, lsqr, eigen) | `lda.scm` | loops / BLAS | no |
|
|
259
|
-
| `GramTruncatedSVD` | TruncatedSVD on dense X (exact, as arpack) | `truncated-svd.scm` | loops / BLAS | no |
|
|
260
|
+
| `GramTruncatedSVD` | TruncatedSVD on dense or sparse X (exact, as arpack) | `truncated-svd.scm`, `sparse.scm` | loops / BLAS | no |
|
|
261
|
+
| `GramPLSRegression`, `GramPLSCanonical`, `GramCCA`, `GramPLSSVD` | PLSRegression, PLSCanonical, CCA, PLSSVD | `pls.scm` | loops / BLAS | no |
|
|
262
|
+
| `GramFactorAnalysis` | FactorAnalysis (exact, as svd_method='lapack'; rotations) | `fa.scm` | loops / BLAS | no |
|
|
260
263
|
| `f_regression, f_classif` | f_regression, f_classif | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
261
264
|
| `SelectKBest, SelectPercentile` | SelectKBest, SelectPercentile | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
262
265
|
| `GramRFE` | RFE(Ridge), RFE(LinearRegression) | `rfe.scm` | loops / BLAS / cuBLAS | inside: Ridge |
|
|
@@ -714,6 +717,143 @@ The exact route costs O(n p^2 + p^3); with few components of many
|
|
|
714
717
|
features (2,000 here) the randomized one does less work, and on one core
|
|
715
718
|
it is faster, at its accuracy. Sparse X is not taken yet.
|
|
716
719
|
|
|
720
|
+
## PLS and CCA: `GramPLSRegression`, `GramPLSCanonical`, `GramCCA`, `GramPLSSVD`
|
|
721
|
+
|
|
722
|
+
scikit-learn's `cross_decomposition` estimators over the cross products
|
|
723
|
+
(`examples/kernel-only/pls.scm`). NIPALS multiplies the blocks only by
|
|
724
|
+
weight vectors, and each such product is one of Cxx = X'X, Cxy = X'Y,
|
|
725
|
+
Cyy = Y'Y times a vector: the Y score is Y c for a coefficient vector c,
|
|
726
|
+
so X'(Y c) = Cxy c. The deflations are rank-one updates of the three
|
|
727
|
+
matrices (with a = Cxx w, b = Cxy'w and s2 = w'Cxx w, regression mode is
|
|
728
|
+
Cxx -= a a'/s2, Cxy -= a b'/s2, Cyy -= b b'/s2). So X and Y are read
|
|
729
|
+
once, for the three products (dsyrk and dgemm), and every power
|
|
730
|
+
iteration after that costs O(p^2 + pq + q^2) where scikit-learn's costs
|
|
731
|
+
O(n(p + q)). CCA's mode B takes pinv(X) y = Cxx^+ X'y, Cxx^+ from its
|
|
732
|
+
eigenproblem; PLSSVD is the SVD of Cxy.
|
|
733
|
+
|
|
734
|
+
```python
|
|
735
|
+
from scm2cpp_learn import GramPLSRegression, GramCCA
|
|
736
|
+
pls = GramPLSRegression(n_components=5).fit(X, Y)
|
|
737
|
+
pls.predict(X), pls.transform(X), pls.x_scores_
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
Weights, loadings, rotations, coefficients, scores and transforms agree
|
|
741
|
+
with scikit-learn's to 1e-13, with the same iteration counts. One cut
|
|
742
|
+
differs: a deflated block loses a rank exactly, which its SVD shows as a
|
|
743
|
+
singular value near eps but its Gram as an eigenvalue near eps
|
|
744
|
+
lam_max, so mode B's pinv also drops eigenvalues under 1e3 eps lam_max
|
|
745
|
+
(singular values under about 5e-7 of the largest, where scikit-learn's
|
|
746
|
+
cut is 2.2e-10). Measured (`bench/eigen-compare.py`, the MKL build, best
|
|
747
|
+
of three):
|
|
748
|
+
|
|
749
|
+
| case | scikit-learn | package | ratio, one core | ratio, 20 cores |
|
|
750
|
+
|---|---|---|---|---|
|
|
751
|
+
| PLSRegression, 200,000 x 100 -> 5, 5 components | 5.64 s | 0.26 s | 21x | 19x |
|
|
752
|
+
| PLSCanonical, 200,000 x 100 -> 5, 5 components | 5.63 s | 0.14 s | 40x | 59x |
|
|
753
|
+
| CCA, 200,000 x 100 -> 5, 5 components | 31.9 s | 0.14 s | 220x | 190x |
|
|
754
|
+
| PLSSVD, 200,000 x 100 -> 5, 5 components | 0.28 s | 0.14 s | 2.0x | 4.0x |
|
|
755
|
+
| PLSRegression, 50,000 x 500 -> 10, 10 components | 45.5 s | 0.75 s | 61x | 57x |
|
|
756
|
+
| PLSCanonical, 50,000 x 500 -> 10, 10 components | 45.3 s | 0.60 s | 76x | 100x |
|
|
757
|
+
| CCA, 50,000 x 500 -> 10, 10 components | 132 s | 1.21 s | 109x | 151x |
|
|
758
|
+
| PLSSVD, 50,000 x 500 -> 10, 10 components | 0.34 s | 0.34 s | 1.0x | 3.4x |
|
|
759
|
+
|
|
760
|
+
PLSSVD is one SVD of X'Y on both sides, so only the product differs.
|
|
761
|
+
|
|
762
|
+
## Factor analysis: `GramFactorAnalysis`
|
|
763
|
+
|
|
764
|
+
scikit-learn's `FactorAnalysis` over the covariance
|
|
765
|
+
(`examples/kernel-only/fa.scm`). Every iteration of scikit-learn's takes
|
|
766
|
+
the SVD of the n x p matrix Xc / (sqrt(psi) sqrt(n)); its squared
|
|
767
|
+
singular values and right singular vectors are the eigenpairs of
|
|
768
|
+
D^-1 C D^-1, C = Xc'Xc / n and D = diag(sqrt psi). So C is formed once
|
|
769
|
+
(dsyrk) and each iteration is the top `n_components` eigenpairs of a
|
|
770
|
+
p x p matrix (dsyevr), then scikit-learn's own updates of the
|
|
771
|
+
components, the log-likelihood and psi. The eigenproblem is exact: what
|
|
772
|
+
`svd_method="lapack"` computes, which the fit matches to 1e-13 with the
|
|
773
|
+
same iterations; scikit-learn's default `"randomized"` approximates it
|
|
774
|
+
(here to 1e-6 in psi). Rotations (varimax, quartimax), `transform`,
|
|
775
|
+
`score`, `get_covariance` and `get_precision` are scikit-learn's.
|
|
776
|
+
|
|
777
|
+
```python
|
|
778
|
+
from scm2cpp_learn import GramFactorAnalysis
|
|
779
|
+
fa = GramFactorAnalysis(n_components=10).fit(X)
|
|
780
|
+
fa.components_, fa.noise_variance_, fa.transform(X)
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
Measured (`bench/eigen-compare.py`, the MKL build, best of two; load
|
|
784
|
+
average 10 to 16 from other jobs):
|
|
785
|
+
|
|
786
|
+
| case | scikit-learn | package | ratio, one core | ratio, 20 cores |
|
|
787
|
+
|---|---|---|---|---|
|
|
788
|
+
| FactorAnalysis(randomized), 200,000 x 100, 10 factors | 7.06 s | 0.11 s | 62x | 56x |
|
|
789
|
+
| FactorAnalysis(lapack), 200,000 x 100, 10 factors | 28.4 s | 0.10 s | 286x | 219x |
|
|
790
|
+
| FactorAnalysis(randomized), 50,000 x 500, 20 factors | 4.37 s | 0.33 s | 13x | 28x |
|
|
791
|
+
| FactorAnalysis(lapack), 50,000 x 500, 20 factors | 22.0 s | 0.33 s | 67x | 106x |
|
|
792
|
+
|
|
793
|
+
## Least squares: `GramLinearRegression`
|
|
794
|
+
|
|
795
|
+
scikit-learn's `LinearRegression` over the Gram matrix
|
|
796
|
+
(`examples/kernel-only/linreg.scm`): Xc'Xc and Xc'y in one pass, then
|
|
797
|
+
the normal equations of the column-scaled Gram by Cholesky (dposv),
|
|
798
|
+
where scikit-learn runs LAPACK's gelsd on the n x p design. The normal
|
|
799
|
+
equations square the condition number, so the answer is taken only
|
|
800
|
+
when the scaled Gram's condition (dpocon's estimate) is at most 1e6,
|
|
801
|
+
which bounds the relative error near 1e-10, and the design has full
|
|
802
|
+
rank at `tol`; otherwise, and for `positive=True`, the fit is
|
|
803
|
+
scikit-learn's own (gelsd, or nnls). `rank_` and `singular_` come from
|
|
804
|
+
the Gram's eigenvalues when first read. A sparse X is taken (below).
|
|
805
|
+
|
|
806
|
+
Measured (`bench/eigen-compare.py`, as above):
|
|
807
|
+
|
|
808
|
+
| case | scikit-learn | package | ratio, one core | ratio, 20 cores |
|
|
809
|
+
|---|---|---|---|---|
|
|
810
|
+
| LinearRegression, 500,000 x 100 | 7.25 s | 0.39 s | 19x | 19x |
|
|
811
|
+
| LinearRegression, 200,000 x 500 | 10.9 s | 1.15 s | 9.5x | 50x |
|
|
812
|
+
| LinearRegression, 200,000 x 100, 10 targets | 2.83 s | 0.17 s | 17x | 18x |
|
|
813
|
+
| LinearRegression, 20,000 x 2,000 | 12.3 s | 1.41 s | 8.7x | 123x |
|
|
814
|
+
|
|
815
|
+
The coefficients agree to 1e-13.
|
|
816
|
+
|
|
817
|
+
## Sparse X
|
|
818
|
+
|
|
819
|
+
`GramLasso`, `GramElasticNet`, `GramRidge`, `GramLinearRegression` and
|
|
820
|
+
`GramTruncatedSVD` take a scipy.sparse X (any format; CSR reaches the
|
|
821
|
+
kernels). X'X is formed by `examples/kernel-only/sparse.scm`'s
|
|
822
|
+
`csr-gram` -- each row's outer product into the upper triangle, rows in
|
|
823
|
+
order, blocks of rows on threads into their own G's -- and X'y and X B
|
|
824
|
+
by `csr-mm`; the intercept is the n xm xm' correction, as scikit-learn's
|
|
825
|
+
sparse coordinate descent keeps X uncentred too. After X'X the fits are
|
|
826
|
+
the dense ones, so the answers equal the dense X's to 1e-15 and are
|
|
827
|
+
exact: scikit-learn's sparse Ridge and LinearRegression are iterative
|
|
828
|
+
(sparse_cg, lsqr) and agree with its own dense answers only to their
|
|
829
|
+
tolerance (1e-5 and 1e-7 here).
|
|
830
|
+
|
|
831
|
+
Measured (`bench/sparse-compare.py`, the MKL build, best of two; load
|
|
832
|
+
average 10 to 29):
|
|
833
|
+
|
|
834
|
+
| case | scikit-learn | package | ratio, one core | ratio, 20 cores |
|
|
835
|
+
|---|---|---|---|---|
|
|
836
|
+
| Lasso, 200,000 x 200, 5% dense | 0.16 s | 0.067 s | 2.4x | 2.6x |
|
|
837
|
+
| ElasticNet, 200,000 x 200, 5% dense | 0.16 s | 0.059 s | 2.6x | 3.4x |
|
|
838
|
+
| Ridge, 200,000 x 200, 5% dense | 0.056 s | 0.064 s | 0.9x | 0.9x |
|
|
839
|
+
| LinearRegression, 200,000 x 200, 5% dense | 0.074 s | 0.076 s | 1.0x | 1.3x |
|
|
840
|
+
| TruncatedSVD (randomized), 200,000 x 200, 5% dense | 0.86 s | 0.11 s | 8.1x | 6.2x |
|
|
841
|
+
| TruncatedSVD (arpack), 200,000 x 200, 5% dense | 1.54 s | 0.11 s | 15x | 13x |
|
|
842
|
+
| Lasso, 100,000 x 1,000, 1% dense | 0.14 s | 0.069 s | 2.1x | 3.0x |
|
|
843
|
+
| Ridge, 100,000 x 1,000, 1% dense | 0.043 s | 0.082 s | 0.5x | 0.6x |
|
|
844
|
+
| TruncatedSVD (arpack), 100,000 x 1,000, 1% dense | 1.41 s | 0.16 s | 8.7x | 8.7x |
|
|
845
|
+
| Lasso, 50,000 x 2,000, 0.5% dense | 0.11 s | 0.15 s | 0.7x | 1.2x |
|
|
846
|
+
| Ridge, 50,000 x 2,000, 0.5% dense | 0.024 s | 0.23 s | 0.1x | 0.2x |
|
|
847
|
+
| TruncatedSVD (randomized), 50,000 x 2,000, 0.5% dense | 0.16 s | 1.49 s | 0.1x | 0.6x |
|
|
848
|
+
|
|
849
|
+
The Gram route pays p^2 memory and p^3 for the solve or the
|
|
850
|
+
eigenproblem whatever the sparsity, where scikit-learn's iterative
|
|
851
|
+
sparse solvers pay a few passes over the nonzeros. So it wins for
|
|
852
|
+
moderate p (a few hundred) and for TruncatedSVD against arpack, and
|
|
853
|
+
loses for p in the thousands with few nonzeros per row: there, Ridge
|
|
854
|
+
and LinearRegression are better left to scikit-learn's sparse solvers
|
|
855
|
+
(at their tolerance), and the randomized TruncatedSVD to scikit-learn.
|
|
856
|
+
|
|
717
857
|
## Bayesian ridge
|
|
718
858
|
|
|
719
859
|
`CovBayesianRidge` is scikit-learn's `BayesianRidge` -- the same model,
|
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: scm2cpp-learn
|
|
3
|
-
Version: 0.18.0
|
|
4
|
-
Summary: scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, TruncatedSVD, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included
|
|
5
|
-
Author: Hirotaka Niitsuma
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/niitsuma/scm2cpp
|
|
8
|
-
Project-URL: Source, https://github.com/niitsuma/scm2cpp/tree/master/python/scm2cpp-learn
|
|
9
|
-
Keywords: scikit-learn,lasso,elastic-net,ridge,svm,logistic-regression,pca,lda,coordinate-descent,lapack,cuda,compiler
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: C++
|
|
13
|
-
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
14
|
-
Classifier: Intended Audience :: Science/Research
|
|
15
|
-
Requires-Python: >=3.8
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
Requires-Dist: numpy>=1.17
|
|
18
|
-
|
|
19
1
|
# scm2cpp-learn
|
|
20
2
|
|
|
21
3
|
[](https://colab.research.google.com/github/niitsuma/scm2cpp/blob/master/notebooks/compare-sklearn.ipynb)
|
|
@@ -206,9 +188,10 @@ package picks the fastest one present.
|
|
|
206
188
|
|
|
207
189
|
| class | scikit-learn | Scheme kernel | builds | sklearnex accelerates |
|
|
208
190
|
|---|---|---|---|---|
|
|
209
|
-
| `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
210
|
-
| `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
211
|
-
| `GramRidge` | Ridge, fit(X, y) with the intercept, one or many targets | `gram.scm` (Cholesky; dposv) | loops / BLAS | Ridge |
|
|
191
|
+
| `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept, dense or sparse X | `lasso-cov.scm` | CPU | no |
|
|
192
|
+
| `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept, dense or sparse X | `lasso-cov.scm` | CPU | no |
|
|
193
|
+
| `GramRidge` | Ridge, fit(X, y) with the intercept, one or many targets, dense or sparse X | `gram.scm` (Cholesky; dposv) | loops / BLAS | Ridge |
|
|
194
|
+
| `GramLinearRegression` | LinearRegression, dense or sparse X, sample_weight | `linreg.scm` (Cholesky; dposv, dpocon) | loops / BLAS | no |
|
|
212
195
|
| `GramRidgeCV` | RidgeCV (cv=None), leave-one-out over every alpha from one eigenproblem | `ridge-gcv.scm` | loops / BLAS | no |
|
|
213
196
|
| `GramMultiTaskLasso` | MultiTaskLasso, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
214
197
|
| `GramMultiTaskElasticNet` | MultiTaskElasticNet, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
@@ -256,7 +239,9 @@ package picks the fastest one present.
|
|
|
256
239
|
| `CovPCA` | PCA(svd_solver='covariance_eigh') | `pca.scm` | loops / BLAS / cuBLAS | PCA |
|
|
257
240
|
| `GramKernelPCA` | KernelPCA (no inverse_transform) | `kernel-pca.scm` | loops / BLAS | no |
|
|
258
241
|
| `GramLDA` | LinearDiscriminantAnalysis (svd, lsqr, eigen) | `lda.scm` | loops / BLAS | no |
|
|
259
|
-
| `GramTruncatedSVD` | TruncatedSVD on dense X (exact, as arpack) | `truncated-svd.scm` | loops / BLAS | no |
|
|
242
|
+
| `GramTruncatedSVD` | TruncatedSVD on dense or sparse X (exact, as arpack) | `truncated-svd.scm`, `sparse.scm` | loops / BLAS | no |
|
|
243
|
+
| `GramPLSRegression`, `GramPLSCanonical`, `GramCCA`, `GramPLSSVD` | PLSRegression, PLSCanonical, CCA, PLSSVD | `pls.scm` | loops / BLAS | no |
|
|
244
|
+
| `GramFactorAnalysis` | FactorAnalysis (exact, as svd_method='lapack'; rotations) | `fa.scm` | loops / BLAS | no |
|
|
260
245
|
| `f_regression, f_classif` | f_regression, f_classif | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
261
246
|
| `SelectKBest, SelectPercentile` | SelectKBest, SelectPercentile | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
262
247
|
| `GramRFE` | RFE(Ridge), RFE(LinearRegression) | `rfe.scm` | loops / BLAS / cuBLAS | inside: Ridge |
|
|
@@ -714,6 +699,143 @@ The exact route costs O(n p^2 + p^3); with few components of many
|
|
|
714
699
|
features (2,000 here) the randomized one does less work, and on one core
|
|
715
700
|
it is faster, at its accuracy. Sparse X is not taken yet.
|
|
716
701
|
|
|
702
|
+
## PLS and CCA: `GramPLSRegression`, `GramPLSCanonical`, `GramCCA`, `GramPLSSVD`
|
|
703
|
+
|
|
704
|
+
scikit-learn's `cross_decomposition` estimators over the cross products
|
|
705
|
+
(`examples/kernel-only/pls.scm`). NIPALS multiplies the blocks only by
|
|
706
|
+
weight vectors, and each such product is one of Cxx = X'X, Cxy = X'Y,
|
|
707
|
+
Cyy = Y'Y times a vector: the Y score is Y c for a coefficient vector c,
|
|
708
|
+
so X'(Y c) = Cxy c. The deflations are rank-one updates of the three
|
|
709
|
+
matrices (with a = Cxx w, b = Cxy'w and s2 = w'Cxx w, regression mode is
|
|
710
|
+
Cxx -= a a'/s2, Cxy -= a b'/s2, Cyy -= b b'/s2). So X and Y are read
|
|
711
|
+
once, for the three products (dsyrk and dgemm), and every power
|
|
712
|
+
iteration after that costs O(p^2 + pq + q^2) where scikit-learn's costs
|
|
713
|
+
O(n(p + q)). CCA's mode B takes pinv(X) y = Cxx^+ X'y, Cxx^+ from its
|
|
714
|
+
eigenproblem; PLSSVD is the SVD of Cxy.
|
|
715
|
+
|
|
716
|
+
```python
|
|
717
|
+
from scm2cpp_learn import GramPLSRegression, GramCCA
|
|
718
|
+
pls = GramPLSRegression(n_components=5).fit(X, Y)
|
|
719
|
+
pls.predict(X), pls.transform(X), pls.x_scores_
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
Weights, loadings, rotations, coefficients, scores and transforms agree
|
|
723
|
+
with scikit-learn's to 1e-13, with the same iteration counts. One cut
|
|
724
|
+
differs: a deflated block loses a rank exactly, which its SVD shows as a
|
|
725
|
+
singular value near eps but its Gram as an eigenvalue near eps
|
|
726
|
+
lam_max, so mode B's pinv also drops eigenvalues under 1e3 eps lam_max
|
|
727
|
+
(singular values under about 5e-7 of the largest, where scikit-learn's
|
|
728
|
+
cut is 2.2e-10). Measured (`bench/eigen-compare.py`, the MKL build, best
|
|
729
|
+
of three):
|
|
730
|
+
|
|
731
|
+
| case | scikit-learn | package | ratio, one core | ratio, 20 cores |
|
|
732
|
+
|---|---|---|---|---|
|
|
733
|
+
| PLSRegression, 200,000 x 100 -> 5, 5 components | 5.64 s | 0.26 s | 21x | 19x |
|
|
734
|
+
| PLSCanonical, 200,000 x 100 -> 5, 5 components | 5.63 s | 0.14 s | 40x | 59x |
|
|
735
|
+
| CCA, 200,000 x 100 -> 5, 5 components | 31.9 s | 0.14 s | 220x | 190x |
|
|
736
|
+
| PLSSVD, 200,000 x 100 -> 5, 5 components | 0.28 s | 0.14 s | 2.0x | 4.0x |
|
|
737
|
+
| PLSRegression, 50,000 x 500 -> 10, 10 components | 45.5 s | 0.75 s | 61x | 57x |
|
|
738
|
+
| PLSCanonical, 50,000 x 500 -> 10, 10 components | 45.3 s | 0.60 s | 76x | 100x |
|
|
739
|
+
| CCA, 50,000 x 500 -> 10, 10 components | 132 s | 1.21 s | 109x | 151x |
|
|
740
|
+
| PLSSVD, 50,000 x 500 -> 10, 10 components | 0.34 s | 0.34 s | 1.0x | 3.4x |
|
|
741
|
+
|
|
742
|
+
PLSSVD is one SVD of X'Y on both sides, so only the product differs.
|
|
743
|
+
|
|
744
|
+
## Factor analysis: `GramFactorAnalysis`
|
|
745
|
+
|
|
746
|
+
scikit-learn's `FactorAnalysis` over the covariance
|
|
747
|
+
(`examples/kernel-only/fa.scm`). Every iteration of scikit-learn's takes
|
|
748
|
+
the SVD of the n x p matrix Xc / (sqrt(psi) sqrt(n)); its squared
|
|
749
|
+
singular values and right singular vectors are the eigenpairs of
|
|
750
|
+
D^-1 C D^-1, C = Xc'Xc / n and D = diag(sqrt psi). So C is formed once
|
|
751
|
+
(dsyrk) and each iteration is the top `n_components` eigenpairs of a
|
|
752
|
+
p x p matrix (dsyevr), then scikit-learn's own updates of the
|
|
753
|
+
components, the log-likelihood and psi. The eigenproblem is exact: what
|
|
754
|
+
`svd_method="lapack"` computes, which the fit matches to 1e-13 with the
|
|
755
|
+
same iterations; scikit-learn's default `"randomized"` approximates it
|
|
756
|
+
(here to 1e-6 in psi). Rotations (varimax, quartimax), `transform`,
|
|
757
|
+
`score`, `get_covariance` and `get_precision` are scikit-learn's.
|
|
758
|
+
|
|
759
|
+
```python
|
|
760
|
+
from scm2cpp_learn import GramFactorAnalysis
|
|
761
|
+
fa = GramFactorAnalysis(n_components=10).fit(X)
|
|
762
|
+
fa.components_, fa.noise_variance_, fa.transform(X)
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
Measured (`bench/eigen-compare.py`, the MKL build, best of two; load
|
|
766
|
+
average 10 to 16 from other jobs):
|
|
767
|
+
|
|
768
|
+
| case | scikit-learn | package | ratio, one core | ratio, 20 cores |
|
|
769
|
+
|---|---|---|---|---|
|
|
770
|
+
| FactorAnalysis(randomized), 200,000 x 100, 10 factors | 7.06 s | 0.11 s | 62x | 56x |
|
|
771
|
+
| FactorAnalysis(lapack), 200,000 x 100, 10 factors | 28.4 s | 0.10 s | 286x | 219x |
|
|
772
|
+
| FactorAnalysis(randomized), 50,000 x 500, 20 factors | 4.37 s | 0.33 s | 13x | 28x |
|
|
773
|
+
| FactorAnalysis(lapack), 50,000 x 500, 20 factors | 22.0 s | 0.33 s | 67x | 106x |
|
|
774
|
+
|
|
775
|
+
## Least squares: `GramLinearRegression`
|
|
776
|
+
|
|
777
|
+
scikit-learn's `LinearRegression` over the Gram matrix
|
|
778
|
+
(`examples/kernel-only/linreg.scm`): Xc'Xc and Xc'y in one pass, then
|
|
779
|
+
the normal equations of the column-scaled Gram by Cholesky (dposv),
|
|
780
|
+
where scikit-learn runs LAPACK's gelsd on the n x p design. The normal
|
|
781
|
+
equations square the condition number, so the answer is taken only
|
|
782
|
+
when the scaled Gram's condition (dpocon's estimate) is at most 1e6,
|
|
783
|
+
which bounds the relative error near 1e-10, and the design has full
|
|
784
|
+
rank at `tol`; otherwise, and for `positive=True`, the fit is
|
|
785
|
+
scikit-learn's own (gelsd, or nnls). `rank_` and `singular_` come from
|
|
786
|
+
the Gram's eigenvalues when first read. A sparse X is taken (below).
|
|
787
|
+
|
|
788
|
+
Measured (`bench/eigen-compare.py`, as above):
|
|
789
|
+
|
|
790
|
+
| case | scikit-learn | package | ratio, one core | ratio, 20 cores |
|
|
791
|
+
|---|---|---|---|---|
|
|
792
|
+
| LinearRegression, 500,000 x 100 | 7.25 s | 0.39 s | 19x | 19x |
|
|
793
|
+
| LinearRegression, 200,000 x 500 | 10.9 s | 1.15 s | 9.5x | 50x |
|
|
794
|
+
| LinearRegression, 200,000 x 100, 10 targets | 2.83 s | 0.17 s | 17x | 18x |
|
|
795
|
+
| LinearRegression, 20,000 x 2,000 | 12.3 s | 1.41 s | 8.7x | 123x |
|
|
796
|
+
|
|
797
|
+
The coefficients agree to 1e-13.
|
|
798
|
+
|
|
799
|
+
## Sparse X
|
|
800
|
+
|
|
801
|
+
`GramLasso`, `GramElasticNet`, `GramRidge`, `GramLinearRegression` and
|
|
802
|
+
`GramTruncatedSVD` take a scipy.sparse X (any format; CSR reaches the
|
|
803
|
+
kernels). X'X is formed by `examples/kernel-only/sparse.scm`'s
|
|
804
|
+
`csr-gram` -- each row's outer product into the upper triangle, rows in
|
|
805
|
+
order, blocks of rows on threads into their own G's -- and X'y and X B
|
|
806
|
+
by `csr-mm`; the intercept is the n xm xm' correction, as scikit-learn's
|
|
807
|
+
sparse coordinate descent keeps X uncentred too. After X'X the fits are
|
|
808
|
+
the dense ones, so the answers equal the dense X's to 1e-15 and are
|
|
809
|
+
exact: scikit-learn's sparse Ridge and LinearRegression are iterative
|
|
810
|
+
(sparse_cg, lsqr) and agree with its own dense answers only to their
|
|
811
|
+
tolerance (1e-5 and 1e-7 here).
|
|
812
|
+
|
|
813
|
+
Measured (`bench/sparse-compare.py`, the MKL build, best of two; load
|
|
814
|
+
average 10 to 29):
|
|
815
|
+
|
|
816
|
+
| case | scikit-learn | package | ratio, one core | ratio, 20 cores |
|
|
817
|
+
|---|---|---|---|---|
|
|
818
|
+
| Lasso, 200,000 x 200, 5% dense | 0.16 s | 0.067 s | 2.4x | 2.6x |
|
|
819
|
+
| ElasticNet, 200,000 x 200, 5% dense | 0.16 s | 0.059 s | 2.6x | 3.4x |
|
|
820
|
+
| Ridge, 200,000 x 200, 5% dense | 0.056 s | 0.064 s | 0.9x | 0.9x |
|
|
821
|
+
| LinearRegression, 200,000 x 200, 5% dense | 0.074 s | 0.076 s | 1.0x | 1.3x |
|
|
822
|
+
| TruncatedSVD (randomized), 200,000 x 200, 5% dense | 0.86 s | 0.11 s | 8.1x | 6.2x |
|
|
823
|
+
| TruncatedSVD (arpack), 200,000 x 200, 5% dense | 1.54 s | 0.11 s | 15x | 13x |
|
|
824
|
+
| Lasso, 100,000 x 1,000, 1% dense | 0.14 s | 0.069 s | 2.1x | 3.0x |
|
|
825
|
+
| Ridge, 100,000 x 1,000, 1% dense | 0.043 s | 0.082 s | 0.5x | 0.6x |
|
|
826
|
+
| TruncatedSVD (arpack), 100,000 x 1,000, 1% dense | 1.41 s | 0.16 s | 8.7x | 8.7x |
|
|
827
|
+
| Lasso, 50,000 x 2,000, 0.5% dense | 0.11 s | 0.15 s | 0.7x | 1.2x |
|
|
828
|
+
| Ridge, 50,000 x 2,000, 0.5% dense | 0.024 s | 0.23 s | 0.1x | 0.2x |
|
|
829
|
+
| TruncatedSVD (randomized), 50,000 x 2,000, 0.5% dense | 0.16 s | 1.49 s | 0.1x | 0.6x |
|
|
830
|
+
|
|
831
|
+
The Gram route pays p^2 memory and p^3 for the solve or the
|
|
832
|
+
eigenproblem whatever the sparsity, where scikit-learn's iterative
|
|
833
|
+
sparse solvers pay a few passes over the nonzeros. So it wins for
|
|
834
|
+
moderate p (a few hundred) and for TruncatedSVD against arpack, and
|
|
835
|
+
loses for p in the thousands with few nonzeros per row: there, Ridge
|
|
836
|
+
and LinearRegression are better left to scikit-learn's sparse solvers
|
|
837
|
+
(at their tolerance), and the randomized TruncatedSVD to scikit-learn.
|
|
838
|
+
|
|
717
839
|
## Bayesian ridge
|
|
718
840
|
|
|
719
841
|
`CovBayesianRidge` is scikit-learn's `BayesianRidge` -- the same model,
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scm2cpp-learn"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, TruncatedSVD, graphical lasso, RANSAC, SGD, OMP, LARS) translated from Scheme to C++ by scm2cpp; GPU batch solver and CUDA kernels included"
|
|
7
|
+
version = "0.20.0"
|
|
8
|
+
description = "scikit-learn estimators (lasso, elastic net, ridge, RidgeCV, ARD, SVM, SVR, logistic regression, GLMs, Huber, Theil-Sen, F-score selection, RFE, NMF, Gaussian mixture, FastICA, PCA, KernelPCA, LDA, TruncatedSVD, PLS, CCA, 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"}
|