From 75c4fff0edb61ae634b73dcc50dc788874bbe6e6 Mon Sep 17 00:00:00 2001 From: ArturoAmorQ Date: Mon, 13 Feb 2023 15:55:04 +0100 Subject: [PATCH 1/6] ENH Let csr_row_norms support multi-thread --- sklearn/utils/sparsefuncs_fast.pyx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/sklearn/utils/sparsefuncs_fast.pyx b/sklearn/utils/sparsefuncs_fast.pyx index 9cbfcc1f7a3f6..1d7ad0eafe0f3 100644 --- a/sklearn/utils/sparsefuncs_fast.pyx +++ b/sklearn/utils/sparsefuncs_fast.pyx @@ -14,6 +14,8 @@ import numpy as np from cython cimport floating from numpy.math cimport isnan +from sklearn.utils._openmp_helpers import _openmp_effective_n_threads + cnp.import_array() ctypedef fused integral: @@ -27,13 +29,14 @@ def csr_row_norms(X): """Squared L2 norm of each row in CSR matrix X.""" if X.dtype not in [np.float32, np.float64]: X = X.astype(np.float64) - return _csr_row_norms(X.data, X.indices, X.indptr) + n_threads = _openmp_effective_n_threads() + return _sqeuclidean_row_norms_sparse(X.data, X.indptr, n_threads) -def _csr_row_norms( +def _sqeuclidean_row_norms_sparse( const floating[::1] X_data, - const integral[::1] X_indices, const integral[::1] X_indptr, + const integral[::1] n_threads, ): cdef: integral n_samples = X_indptr.shape[0] - 1 @@ -44,12 +47,11 @@ def _csr_row_norms( cdef floating[::1] norms = np.zeros(n_samples, dtype=dtype) - with nogil: - for i in range(n_samples): - for j in range(X_indptr[i], X_indptr[i + 1]): - norms[i] += X_data[j] * X_data[j] + for i in prange(n_samples, schedule='static', nogil=True, num_threads=n_threads): + for j in range(X_indptr[i], X_indptr[i + 1]): + squared_row_norms[i] += X_data[j] * X_data[j] - return np.asarray(norms) + return np.asarray(squared_row_norms) def csr_mean_variance_axis0(X, weights=None, return_sum_weights=False): From dc39a882adbf932086a3785de9caf5ebc9ab2e83 Mon Sep 17 00:00:00 2001 From: Arturo Amor <86408019+ArturoAmorQ@users.noreply.github.com> Date: Tue, 14 Feb 2023 16:07:51 +0100 Subject: [PATCH 2/6] Update sklearn/utils/sparsefuncs_fast.pyx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/utils/sparsefuncs_fast.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sklearn/utils/sparsefuncs_fast.pyx b/sklearn/utils/sparsefuncs_fast.pyx index 1d7ad0eafe0f3..7b90cc53cff92 100644 --- a/sklearn/utils/sparsefuncs_fast.pyx +++ b/sklearn/utils/sparsefuncs_fast.pyx @@ -29,7 +29,7 @@ def csr_row_norms(X): """Squared L2 norm of each row in CSR matrix X.""" if X.dtype not in [np.float32, np.float64]: X = X.astype(np.float64) - n_threads = _openmp_effective_n_threads() + n_threads = _openmp_effective_n_threads() return _sqeuclidean_row_norms_sparse(X.data, X.indptr, n_threads) From 03fe4592220f1739eb2692f865b12b23fa8b0860 Mon Sep 17 00:00:00 2001 From: Arturo Amor <86408019+ArturoAmorQ@users.noreply.github.com> Date: Tue, 14 Feb 2023 16:10:05 +0100 Subject: [PATCH 3/6] Update sklearn/utils/sparsefuncs_fast.pyx --- sklearn/utils/sparsefuncs_fast.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sklearn/utils/sparsefuncs_fast.pyx b/sklearn/utils/sparsefuncs_fast.pyx index 7b90cc53cff92..f4687644bc36e 100644 --- a/sklearn/utils/sparsefuncs_fast.pyx +++ b/sklearn/utils/sparsefuncs_fast.pyx @@ -36,7 +36,7 @@ def csr_row_norms(X): def _sqeuclidean_row_norms_sparse( const floating[::1] X_data, const integral[::1] X_indptr, - const integral[::1] n_threads, + const int n_threads, ): cdef: integral n_samples = X_indptr.shape[0] - 1 From f43f04dfbcda53ce25db7c81282145021242ec56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20du=20Boisberranger?= <34657725+jeremiedbb@users.noreply.github.com> Date: Tue, 14 Feb 2023 16:34:08 +0100 Subject: [PATCH 4/6] Update sklearn/utils/sparsefuncs_fast.pyx --- sklearn/utils/sparsefuncs_fast.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/sklearn/utils/sparsefuncs_fast.pyx b/sklearn/utils/sparsefuncs_fast.pyx index f4687644bc36e..8accdb91736a4 100644 --- a/sklearn/utils/sparsefuncs_fast.pyx +++ b/sklearn/utils/sparsefuncs_fast.pyx @@ -12,6 +12,7 @@ from libc.math cimport fabs, sqrt cimport numpy as cnp import numpy as np from cython cimport floating +from cython.parallel cimport prange from numpy.math cimport isnan from sklearn.utils._openmp_helpers import _openmp_effective_n_threads From 3c42a6e7d90f40b7fd4e1f63160fbfd2890dbf48 Mon Sep 17 00:00:00 2001 From: Arturo Amor <86408019+ArturoAmorQ@users.noreply.github.com> Date: Tue, 14 Feb 2023 16:46:47 +0100 Subject: [PATCH 5/6] Update sklearn/utils/sparsefuncs_fast.pyx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com> --- sklearn/utils/sparsefuncs_fast.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sklearn/utils/sparsefuncs_fast.pyx b/sklearn/utils/sparsefuncs_fast.pyx index 8accdb91736a4..7c3ff83aa84e1 100644 --- a/sklearn/utils/sparsefuncs_fast.pyx +++ b/sklearn/utils/sparsefuncs_fast.pyx @@ -46,7 +46,7 @@ def _sqeuclidean_row_norms_sparse( dtype = np.float32 if floating is float else np.float64 - cdef floating[::1] norms = np.zeros(n_samples, dtype=dtype) + cdef floating[::1] squared_row_norms = np.zeros(n_samples, dtype=dtype) for i in prange(n_samples, schedule='static', nogil=True, num_threads=n_threads): for j in range(X_indptr[i], X_indptr[i + 1]): From bfada88b7594378388b6417b750cb1fa41e1d12d Mon Sep 17 00:00:00 2001 From: Arturo Amor <86408019+ArturoAmorQ@users.noreply.github.com> Date: Tue, 14 Feb 2023 17:38:20 +0100 Subject: [PATCH 6/6] Update sklearn/utils/sparsefuncs_fast.pyx Co-authored-by: Vincent M --- sklearn/utils/sparsefuncs_fast.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sklearn/utils/sparsefuncs_fast.pyx b/sklearn/utils/sparsefuncs_fast.pyx index 7c3ff83aa84e1..4b975872c0e0a 100644 --- a/sklearn/utils/sparsefuncs_fast.pyx +++ b/sklearn/utils/sparsefuncs_fast.pyx @@ -37,7 +37,7 @@ def csr_row_norms(X): def _sqeuclidean_row_norms_sparse( const floating[::1] X_data, const integral[::1] X_indptr, - const int n_threads, + int n_threads, ): cdef: integral n_samples = X_indptr.shape[0] - 1