scm2cpp-learn 0.19.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.19.0 → scm2cpp_learn-0.20.0}/PKG-INFO +102 -5
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/README.md +101 -4
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/pyproject.toml +1 -1
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/__init__.py +399 -11
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_compat.py +70 -2
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_accel_cublas.py +12 -0
- scm2cpp_learn-0.19.0/src/scm2cpp_learn/_generated/_loader_gramops_loops.py → scm2cpp_learn-0.20.0/src/scm2cpp_learn/_generated/_loader_gramops_blas.py +65 -20
- scm2cpp_learn-0.19.0/src/scm2cpp_learn/_generated/_loader_gramops_blas.py → scm2cpp_learn-0.20.0/src/scm2cpp_learn/_generated/_loader_gramops_loops.py +84 -1
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/accel_cublas/accel.cpp +2 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/accel_cublas/accel.hpp +89 -17
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/accel_cublas/accel_capi.cpp +6 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/classifiers.hpp +18 -18
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_blas/lasso_design.hpp +12 -12
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_cublas/lasso_design.hpp +13 -13
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_loops/lasso_design.hpp +24 -24
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_blas/gramops.cpp +8 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_blas/gramops.hpp +453 -21
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_blas/gramops_capi.cpp +24 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_loops/gramops.cpp +8 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_loops/gramops.hpp +854 -422
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gramops_loops/gramops_capi.cpp +24 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_blas/nmf_cd.hpp +13 -13
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_cublas/nmf_cd.hpp +17 -17
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_loops/nmf_cd.hpp +29 -29
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/scm2cpp-blas.hpp +18 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn.egg-info/PKG-INFO +102 -5
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/setup.cfg +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/setup.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/__init__.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_classifiers.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_derived_blas.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_derived_cublas.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_derived_loops.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_gpu_cuda.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_nmf_blas.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_nmf_cublas.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/_loader_nmf_loops.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/classifiers.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/classifiers_capi.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_blas/lasso_design.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_blas/lasso_design_capi.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_cublas/lasso_design.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_cublas/lasso_design_capi.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_loops/lasso_design.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/derived_loops/lasso_design_capi.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gpu_cuda/gpu.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gpu_cuda/gpu.hpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/gpu_cuda/gpu_capi.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/lasso_cov.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/lasso_cov.hpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/lasso_cov_capi.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_blas/nmf_cd.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_blas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_cublas/nmf_cd.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_cublas/nmf_cd_capi.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_loops/nmf_cd.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/nmf_loops/nmf_cd_capi.cpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/scm2cpp-cublas.hpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/scm2cpp-cuda.hpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_generated/scm2cpp.hpp +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/_libfind.py +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn/batch_capi.cu +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn.egg-info/SOURCES.txt +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn.egg-info/dependency_links.txt +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn.egg-info/requires.txt +0 -0
- {scm2cpp_learn-0.19.0 → scm2cpp_learn-0.20.0}/src/scm2cpp_learn.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scm2cpp-learn
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.20.0
|
|
4
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
|
|
@@ -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,8 +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 |
|
|
260
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 |
|
|
261
263
|
| `f_regression, f_classif` | f_regression, f_classif | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
262
264
|
| `SelectKBest, SelectPercentile` | SelectKBest, SelectPercentile | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
263
265
|
| `GramRFE` | RFE(Ridge), RFE(LinearRegression) | `rfe.scm` | loops / BLAS / cuBLAS | inside: Ridge |
|
|
@@ -757,6 +759,101 @@ of three):
|
|
|
757
759
|
|
|
758
760
|
PLSSVD is one SVD of X'Y on both sides, so only the product differs.
|
|
759
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
|
+
|
|
760
857
|
## Bayesian ridge
|
|
761
858
|
|
|
762
859
|
`CovBayesianRidge` is scikit-learn's `BayesianRidge` -- the same model,
|
|
@@ -188,9 +188,10 @@ package picks the fastest one present.
|
|
|
188
188
|
|
|
189
189
|
| class | scikit-learn | Scheme kernel | builds | sklearnex accelerates |
|
|
190
190
|
|---|---|---|---|---|
|
|
191
|
-
| `GramLasso` | Lasso(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
192
|
-
| `GramElasticNet` | ElasticNet(precompute=True), fit(X, y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
193
|
-
| `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 |
|
|
194
195
|
| `GramRidgeCV` | RidgeCV (cv=None), leave-one-out over every alpha from one eigenproblem | `ridge-gcv.scm` | loops / BLAS | no |
|
|
195
196
|
| `GramMultiTaskLasso` | MultiTaskLasso, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
196
197
|
| `GramMultiTaskElasticNet` | MultiTaskElasticNet, fit(X, Y) with the intercept | `lasso-cov.scm` | CPU | no |
|
|
@@ -238,8 +239,9 @@ package picks the fastest one present.
|
|
|
238
239
|
| `CovPCA` | PCA(svd_solver='covariance_eigh') | `pca.scm` | loops / BLAS / cuBLAS | PCA |
|
|
239
240
|
| `GramKernelPCA` | KernelPCA (no inverse_transform) | `kernel-pca.scm` | loops / BLAS | no |
|
|
240
241
|
| `GramLDA` | LinearDiscriminantAnalysis (svd, lsqr, eigen) | `lda.scm` | loops / BLAS | no |
|
|
241
|
-
| `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 |
|
|
242
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 |
|
|
243
245
|
| `f_regression, f_classif` | f_regression, f_classif | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
244
246
|
| `SelectKBest, SelectPercentile` | SelectKBest, SelectPercentile | `fscore.scm` | loops / BLAS / cuBLAS | no |
|
|
245
247
|
| `GramRFE` | RFE(Ridge), RFE(LinearRegression) | `rfe.scm` | loops / BLAS / cuBLAS | inside: Ridge |
|
|
@@ -739,6 +741,101 @@ of three):
|
|
|
739
741
|
|
|
740
742
|
PLSSVD is one SVD of X'Y on both sides, so only the product differs.
|
|
741
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
|
+
|
|
742
839
|
## Bayesian ridge
|
|
743
840
|
|
|
744
841
|
`CovBayesianRidge` is scikit-learn's `BayesianRidge` -- the same model,
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scm2cpp-learn"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.20.0"
|
|
8
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"
|