scikit-learn-intelex 2024.0.1__py312-none-manylinux1_x86_64.whl → 2024.2.0__py312-none-manylinux1_x86_64.whl

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.

Potentially problematic release.


This version of scikit-learn-intelex might be problematic. Click here for more details.

Files changed (78) hide show
  1. {scikit_learn_intelex-2024.0.1.dist-info → scikit_learn_intelex-2024.2.0.dist-info}/METADATA +2 -2
  2. scikit_learn_intelex-2024.2.0.dist-info/RECORD +101 -0
  3. sklearnex/__init__.py +3 -1
  4. sklearnex/__main__.py +0 -1
  5. sklearnex/_utils.py +15 -1
  6. sklearnex/basic_statistics/__init__.py +0 -1
  7. sklearnex/cluster/__init__.py +0 -1
  8. sklearnex/cluster/dbscan.py +2 -1
  9. sklearnex/cluster/k_means.py +0 -1
  10. sklearnex/cluster/tests/test_dbscan.py +0 -1
  11. sklearnex/cluster/tests/test_kmeans.py +0 -1
  12. sklearnex/covariance/__init__.py +19 -0
  13. sklearnex/covariance/incremental_covariance.py +130 -0
  14. sklearnex/covariance/tests/test_incremental_covariance.py +143 -0
  15. sklearnex/decomposition/__init__.py +0 -1
  16. sklearnex/decomposition/pca.py +0 -1
  17. sklearnex/decomposition/tests/test_pca.py +0 -1
  18. sklearnex/dispatcher.py +35 -1
  19. sklearnex/ensemble/__init__.py +0 -1
  20. sklearnex/ensemble/_forest.py +17 -2
  21. sklearnex/ensemble/tests/test_forest.py +0 -1
  22. sklearnex/glob/__main__.py +0 -1
  23. sklearnex/glob/dispatcher.py +0 -1
  24. sklearnex/linear_model/__init__.py +1 -3
  25. sklearnex/linear_model/coordinate_descent.py +0 -1
  26. sklearnex/linear_model/linear.py +9 -1
  27. sklearnex/linear_model/logistic_path.py +0 -1
  28. sklearnex/linear_model/logistic_regression.py +333 -0
  29. sklearnex/linear_model/ridge.py +0 -1
  30. sklearnex/linear_model/tests/test_linear.py +8 -3
  31. sklearnex/linear_model/tests/test_logreg.py +70 -6
  32. sklearnex/manifold/__init__.py +0 -1
  33. sklearnex/manifold/t_sne.py +0 -1
  34. sklearnex/manifold/tests/test_tsne.py +0 -1
  35. sklearnex/metrics/__init__.py +0 -1
  36. sklearnex/metrics/pairwise.py +0 -1
  37. sklearnex/metrics/ranking.py +0 -1
  38. sklearnex/metrics/tests/test_metrics.py +0 -1
  39. sklearnex/model_selection/__init__.py +0 -1
  40. sklearnex/model_selection/split.py +0 -1
  41. sklearnex/model_selection/tests/test_model_selection.py +0 -1
  42. sklearnex/neighbors/__init__.py +1 -2
  43. sklearnex/neighbors/_lof.py +167 -0
  44. sklearnex/neighbors/common.py +1 -2
  45. sklearnex/neighbors/knn_classification.py +5 -4
  46. sklearnex/neighbors/knn_regression.py +5 -4
  47. sklearnex/neighbors/knn_unsupervised.py +4 -3
  48. sklearnex/neighbors/tests/test_neighbors.py +12 -12
  49. sklearnex/preview/__init__.py +1 -2
  50. sklearnex/preview/cluster/__init__.py +0 -1
  51. sklearnex/preview/cluster/k_means.py +2 -1
  52. sklearnex/preview/covariance/__init__.py +19 -0
  53. sklearnex/preview/covariance/covariance.py +132 -0
  54. sklearnex/preview/covariance/tests/test_covariance.py +53 -0
  55. sklearnex/preview/decomposition/__init__.py +0 -1
  56. sklearnex/preview/decomposition/pca.py +43 -45
  57. sklearnex/preview/decomposition/tests/test_preview_pca.py +7 -3
  58. sklearnex/spmd/__init__.py +1 -0
  59. sklearnex/spmd/covariance/__init__.py +19 -0
  60. sklearnex/spmd/covariance/covariance.py +21 -0
  61. sklearnex/spmd/linear_model/__init__.py +2 -1
  62. sklearnex/spmd/linear_model/logistic_regression.py +21 -0
  63. sklearnex/svm/__init__.py +0 -1
  64. sklearnex/svm/nusvc.py +4 -0
  65. sklearnex/svm/nusvr.py +2 -0
  66. sklearnex/svm/svc.py +5 -1
  67. sklearnex/svm/svr.py +2 -0
  68. sklearnex/svm/tests/test_svm.py +0 -1
  69. sklearnex/tests/test_memory_usage.py +1 -4
  70. sklearnex/tests/test_monkeypatch.py +46 -16
  71. sklearnex/tests/test_n_jobs_support.py +93 -0
  72. sklearnex/tests/test_patching.py +19 -5
  73. sklearnex/utils/validation.py +0 -1
  74. scikit_learn_intelex-2024.0.1.dist-info/RECORD +0 -90
  75. sklearnex/neighbors/lof.py +0 -437
  76. {scikit_learn_intelex-2024.0.1.dist-info → scikit_learn_intelex-2024.2.0.dist-info}/LICENSE.txt +0 -0
  77. {scikit_learn_intelex-2024.0.1.dist-info → scikit_learn_intelex-2024.2.0.dist-info}/WHEEL +0 -0
  78. {scikit_learn_intelex-2024.0.1.dist-info → scikit_learn_intelex-2024.2.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ===============================================================================
3
2
  # Copyright 2023 Intel Corporation
4
3
  #
@@ -24,11 +23,12 @@ from sklearn.base import BaseEstimator
24
23
  from sklearn.utils.extmath import stable_cumsum
25
24
  from sklearn.utils.validation import check_array, check_is_fitted
26
25
 
26
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
27
27
  from daal4py.sklearn._utils import sklearn_check_version
28
28
  from onedal.utils import _check_array
29
29
 
30
30
  from ..._device_offload import dispatch
31
- from ..._utils import PatchingConditionsChain
31
+ from ..._utils import PatchingConditionsChain, register_hyperparameters
32
32
 
33
33
  if sklearn_check_version("1.1") and not sklearn_check_version("1.2"):
34
34
  from sklearn.utils import check_scalar
@@ -39,10 +39,15 @@ else:
39
39
 
40
40
  from sklearn.decomposition import PCA as sklearn_PCA
41
41
 
42
+ from onedal.common.hyperparameters import get_hyperparameters
42
43
  from onedal.decomposition import PCA as onedal_PCA
43
44
 
44
45
 
46
+ @register_hyperparameters({"fit": get_hyperparameters("covariance", "compute")})
47
+ @control_n_jobs(decorated_methods=["fit", "transform"])
45
48
  class PCA(sklearn_PCA):
49
+ __doc__ = sklearn_PCA.__doc__
50
+
46
51
  if sklearn_check_version("1.2"):
47
52
  _parameter_constraints: dict = {**sklearn_PCA._parameter_constraints}
48
53
 
@@ -99,23 +104,22 @@ class PCA(sklearn_PCA):
99
104
  min_val=1,
100
105
  target_type=numbers.Integral,
101
106
  )
102
- self._fit(X)
103
- return self
104
-
105
- def _fit(self, X):
106
- if issparse(X):
107
- raise TypeError(
108
- "PCA does not support sparse input. See "
109
- "TruncatedSVD for a possible alternative."
110
- )
111
107
 
112
108
  if sklearn_check_version("0.23"):
113
109
  X = self._validate_data(
114
- X, dtype=[np.float64, np.float32], ensure_2d=True, copy=False
110
+ X,
111
+ dtype=[np.float64, np.float32],
112
+ ensure_2d=True,
113
+ copy=False,
114
+ accept_sparse=True,
115
115
  )
116
116
  else:
117
117
  X = _check_array(
118
- X, dtype=[np.float64, np.float32], ensure_2d=True, copy=False
118
+ X,
119
+ dtype=[np.float64, np.float32],
120
+ ensure_2d=True,
121
+ copy=False,
122
+ accept_sparse=True,
119
123
  )
120
124
 
121
125
  n_samples, n_features = X.shape
@@ -132,7 +136,7 @@ class PCA(sklearn_PCA):
132
136
  self._validate_n_components(n_components, n_samples, n_features, n_sf_min)
133
137
 
134
138
  self._fit_svd_solver = self.svd_solver
135
- shape_good_for_daal = X.shape[1] / X.shape[0] < 2
139
+
136
140
  if self._fit_svd_solver == "auto":
137
141
  if sklearn_check_version("1.1"):
138
142
  if max(X.shape) <= 500 or n_components == "mle":
@@ -164,37 +168,21 @@ class PCA(sklearn_PCA):
164
168
  else:
165
169
  self._fit_svd_solver = "full"
166
170
 
167
- if not shape_good_for_daal or self._fit_svd_solver != "full":
168
- if sklearn_check_version("0.23"):
169
- X = self._validate_data(X, copy=self.copy)
170
- else:
171
- X = check_array(X, copy=self.copy)
172
-
173
- # Call different fits for either full or truncated SVD
174
- if shape_good_for_daal and self._fit_svd_solver == "full":
175
- return dispatch(
176
- self,
177
- "fit",
178
- {
179
- "onedal": self.__class__._onedal_fit,
180
- "sklearn": sklearn_PCA._fit_full,
181
- },
182
- X,
183
- )
184
- elif not shape_good_for_daal and self._fit_svd_solver == "full":
185
- return sklearn_PCA._fit_full(self, X, n_components)
186
- elif self._fit_svd_solver in ["arpack", "randomized"]:
187
- return sklearn_PCA._fit_truncated(
188
- self,
189
- X,
190
- n_components,
191
- self._fit_svd_solver,
192
- )
193
- else:
194
- raise ValueError("Unrecognized svd_solver='{0}'".format(self._fit_svd_solver))
171
+ dispatch(
172
+ self,
173
+ "fit",
174
+ {
175
+ "onedal": self.__class__._onedal_fit,
176
+ "sklearn": sklearn_PCA.fit,
177
+ },
178
+ X,
179
+ )
180
+ return self
195
181
 
196
182
  def _onedal_supported(self, method_name, *data):
197
183
  class_name = self.__class__.__name__
184
+ X = data[0]
185
+
198
186
  if method_name == "fit":
199
187
  patching_status = PatchingConditionsChain(
200
188
  f"sklearn.decomposition.{class_name}.{method_name}"
@@ -206,6 +194,12 @@ class PCA(sklearn_PCA):
206
194
  f"'{self._fit_svd_solver}' SVD solver is not supported. "
207
195
  "Only 'full' solver is supported.",
208
196
  ),
197
+ (not issparse(X), "oneDAL PCA does not support sparse inputs"),
198
+ (
199
+ X.shape[1] / X.shape[0] < 2,
200
+ "The shape of X does not satisfy oneDAL requirements: "
201
+ "number of features / number of samples >= 2",
202
+ ),
209
203
  ]
210
204
  )
211
205
  return patching_status
@@ -290,7 +284,7 @@ class PCA(sklearn_PCA):
290
284
  if self.whiten:
291
285
  X_new /= np.sqrt(self.explained_variance_)
292
286
  else:
293
- return sklearn_PCA.transform(self, X)
287
+ return super().transform(X)
294
288
  return X_new
295
289
 
296
290
  def fit_transform(self, X, y=None):
@@ -308,7 +302,7 @@ class PCA(sklearn_PCA):
308
302
  Transformed values of X.
309
303
  """
310
304
  if self.svd_solver in ["randomized", "arpack"]:
311
- return sklearn_PCA.fit_transform(self, X)
305
+ return super().fit_transform(X)
312
306
  else:
313
307
  self.fit(X)
314
308
  if hasattr(self, "_onedal_estimator"):
@@ -317,7 +311,11 @@ class PCA(sklearn_PCA):
317
311
  X_new /= np.sqrt(self.explained_variance_)
318
312
  return X_new
319
313
  else:
320
- return sklearn_PCA.transform(self, X)
314
+ return super().transform(X)
315
+
316
+ fit.__doc__ = sklearn_PCA.fit.__doc__
317
+ transform.__doc__ = sklearn_PCA.transform.__doc__
318
+ fit_transform.__doc__ = sklearn_PCA.fit_transform.__doc__
321
319
 
322
320
  def _save_attributes(self):
323
321
  self.n_samples_ = self._onedal_estimator.n_samples_
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ===============================================================================
3
2
  # Copyright 2023 Intel Corporation
4
3
  #
@@ -19,6 +18,7 @@ import numpy as np
19
18
  import pytest
20
19
  from numpy.testing import assert_allclose
21
20
 
21
+ from daal4py.sklearn._utils import daal_check_version
22
22
  from onedal.tests.utils._dataframes_support import (
23
23
  _as_numpy,
24
24
  _convert_to_dataframe,
@@ -27,12 +27,16 @@ from onedal.tests.utils._dataframes_support import (
27
27
 
28
28
 
29
29
  @pytest.mark.parametrize("dataframe,queue", get_dataframes_and_queues())
30
- def test_sklearnex_import(dataframe, queue):
30
+ @pytest.mark.parametrize("macro_block", [None, 1024])
31
+ def test_sklearnex_import(dataframe, queue, macro_block):
31
32
  from sklearnex.preview.decomposition import PCA
32
33
 
33
34
  X = [[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]]
34
35
  X = _convert_to_dataframe(X, sycl_queue=queue, target_df=dataframe)
35
- pca = PCA(n_components=2, svd_solver="full").fit(X)
36
+ pca = PCA(n_components=2, svd_solver="full")
37
+ if daal_check_version((2024, "P", 0)) and macro_block is not None:
38
+ pca.get_hyperparameters("fit").cpu_macro_block = macro_block
39
+ pca.fit(X)
36
40
  assert "sklearnex" in pca.__module__
37
41
  assert hasattr(pca, "_onedal_estimator")
38
42
  assert_allclose(_as_numpy(pca.singular_values_), [6.30061232, 0.54980396])
@@ -17,6 +17,7 @@
17
17
  __all__ = [
18
18
  "basic_statistics",
19
19
  "cluster",
20
+ "covariance",
20
21
  "decomposition",
21
22
  "ensemble",
22
23
  "linear_model",
@@ -0,0 +1,19 @@
1
+ # ==============================================================================
2
+ # Copyright 2024 Intel Corporation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ==============================================================================
16
+
17
+ from .covariance import EmpiricalCovariance
18
+
19
+ __all__ = ["EmpiricalCovariance"]
@@ -0,0 +1,21 @@
1
+ # ==============================================================================
2
+ # Copyright 2024 Intel Corporation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ==============================================================================
16
+
17
+ from onedal.spmd.covariance import EmpiricalCovariance
18
+
19
+ # TODO:
20
+ # Currently it uses `onedal` module interface.
21
+ # Add sklearnex dispatching.
@@ -15,5 +15,6 @@
15
15
  # ==============================================================================
16
16
 
17
17
  from .linear_model import LinearRegression
18
+ from .logistic_regression import LogisticRegression
18
19
 
19
- __all__ = ["LinearRegression"]
20
+ __all__ = ["LinearRegression", "LogisticRegression"]
@@ -0,0 +1,21 @@
1
+ # ==============================================================================
2
+ # Copyright 2024 Intel Corporation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ==============================================================================
16
+
17
+ from onedal.spmd.linear_model import LogisticRegression
18
+
19
+ # TODO:
20
+ # Currently it uses `onedal` module interface.
21
+ # Add sklearnex dispatching.
sklearnex/svm/__init__.py CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ==============================================================================
3
2
  # Copyright 2021 Intel Corporation
4
3
  #
sklearnex/svm/nusvc.py CHANGED
@@ -18,6 +18,7 @@ from sklearn.exceptions import NotFittedError
18
18
  from sklearn.svm import NuSVC as sklearn_NuSVC
19
19
  from sklearn.utils.validation import _deprecate_positional_args
20
20
 
21
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
21
22
  from daal4py.sklearn._utils import sklearn_check_version
22
23
 
23
24
  from .._device_offload import dispatch, wrap_output_data
@@ -29,6 +30,9 @@ if sklearn_check_version("1.0"):
29
30
  from onedal.svm import NuSVC as onedal_NuSVC
30
31
 
31
32
 
33
+ @control_n_jobs(
34
+ decorated_methods=["fit", "predict", "_predict_proba", "decision_function"]
35
+ )
32
36
  class NuSVC(sklearn_NuSVC, BaseSVC):
33
37
  __doc__ = sklearn_NuSVC.__doc__
34
38
 
sklearnex/svm/nusvr.py CHANGED
@@ -17,6 +17,7 @@
17
17
  from sklearn.svm import NuSVR as sklearn_NuSVR
18
18
  from sklearn.utils.validation import _deprecate_positional_args
19
19
 
20
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
20
21
  from daal4py.sklearn._utils import sklearn_check_version
21
22
  from onedal.svm import NuSVR as onedal_NuSVR
22
23
 
@@ -24,6 +25,7 @@ from .._device_offload import dispatch, wrap_output_data
24
25
  from ._common import BaseSVR
25
26
 
26
27
 
28
+ @control_n_jobs(decorated_methods=["fit", "predict"])
27
29
  class NuSVR(sklearn_NuSVR, BaseSVR):
28
30
  __doc__ = sklearn_NuSVR.__doc__
29
31
 
sklearnex/svm/svc.py CHANGED
@@ -20,6 +20,7 @@ from sklearn.exceptions import NotFittedError
20
20
  from sklearn.svm import SVC as sklearn_SVC
21
21
  from sklearn.utils.validation import _deprecate_positional_args
22
22
 
23
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
23
24
  from daal4py.sklearn._utils import sklearn_check_version
24
25
 
25
26
  from .._device_offload import dispatch, wrap_output_data
@@ -32,6 +33,9 @@ if sklearn_check_version("1.0"):
32
33
  from onedal.svm import SVC as onedal_SVC
33
34
 
34
35
 
36
+ @control_n_jobs(
37
+ decorated_methods=["fit", "predict", "_predict_proba", "decision_function"]
38
+ )
35
39
  class SVC(sklearn_SVC, BaseSVC):
36
40
  __doc__ = sklearn_SVC.__doc__
37
41
 
@@ -235,7 +239,7 @@ class SVC(sklearn_SVC, BaseSVC):
235
239
  )
236
240
  if len(data) > 1:
237
241
  self._class_count = len(np.unique(data[1]))
238
- self._is_sparse = sp.isspmatrix(data[0])
242
+ self._is_sparse = sp.issparse(data[0])
239
243
  conditions = [
240
244
  (
241
245
  self.kernel in ["linear", "rbf"],
sklearnex/svm/svr.py CHANGED
@@ -17,6 +17,7 @@
17
17
  from sklearn.svm import SVR as sklearn_SVR
18
18
  from sklearn.utils.validation import _deprecate_positional_args
19
19
 
20
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
20
21
  from daal4py.sklearn._utils import sklearn_check_version
21
22
  from onedal.svm import SVR as onedal_SVR
22
23
 
@@ -24,6 +25,7 @@ from .._device_offload import dispatch, wrap_output_data
24
25
  from ._common import BaseSVR
25
26
 
26
27
 
28
+ @control_n_jobs(decorated_methods=["fit", "predict"])
27
29
  class SVR(sklearn_SVR, BaseSVR):
28
30
  __doc__ = sklearn_SVR.__doc__
29
31
 
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ===============================================================================
3
2
  # Copyright 2021 Intel Corporation
4
3
  #
@@ -94,10 +94,7 @@ def remove_duplicated_estimators(estimators_list):
94
94
  return estimators_map.values()
95
95
 
96
96
 
97
- BANNED_ESTIMATORS = (
98
- "LocalOutlierFactor", # fails on ndarray_c for sklearn > 1.0
99
- "TSNE", # too slow for using in testing on common data size
100
- )
97
+ BANNED_ESTIMATORS = ("TSNE",) # too slow for using in testing on common data size
101
98
  estimators = [
102
99
  PreviewPCA,
103
100
  TrainTestSplitEstimator,
@@ -45,8 +45,12 @@ def test_monkey_patching():
45
45
  n = _classes[i][1]
46
46
 
47
47
  sklearnex.unpatch_sklearn(t)
48
- class_module = getattr(p, n).__module__
49
- assert class_module.startswith("sklearn"), "Unpatching has completed with error."
48
+ sklearn_class = getattr(p, n, None)
49
+ if sklearn_class is not None:
50
+ sklearn_class = sklearn_class.__module__
51
+ assert sklearn_class is None or sklearn_class.startswith(
52
+ "sklearn"
53
+ ), "Unpatching has completed with error."
50
54
 
51
55
  sklearnex.unpatch_sklearn()
52
56
 
@@ -55,8 +59,12 @@ def test_monkey_patching():
55
59
  p = _classes[i][0]
56
60
  n = _classes[i][1]
57
61
 
58
- class_module = getattr(p, n).__module__
59
- assert class_module.startswith("sklearn"), "Unpatching has completed with error."
62
+ sklearn_class = getattr(p, n, None)
63
+ if sklearn_class is not None:
64
+ sklearn_class = sklearn_class.__module__
65
+ assert sklearn_class is None or sklearn_class.startswith(
66
+ "sklearn"
67
+ ), "Unpatching has completed with error."
60
68
 
61
69
  sklearnex.unpatch_sklearn()
62
70
 
@@ -85,7 +93,10 @@ def test_patch_by_list_simple():
85
93
 
86
94
  assert RandomForestRegressor.__module__.startswith("sklearn")
87
95
  assert KNeighborsRegressor.__module__.startswith("sklearn")
88
- assert LogisticRegression.__module__.startswith("daal4py")
96
+ if daal_check_version((2024, "P", 1)):
97
+ assert LogisticRegression.__module__.startswith("sklearnex")
98
+ else:
99
+ assert LogisticRegression.__module__.startswith("daal4py")
89
100
  assert SVC.__module__.startswith("sklearn")
90
101
 
91
102
  sklearnex.unpatch_sklearn()
@@ -101,7 +112,10 @@ def test_patch_by_list_many_estimators():
101
112
 
102
113
  assert RandomForestRegressor.__module__.startswith("sklearn")
103
114
  assert KNeighborsRegressor.__module__.startswith("sklearn")
104
- assert LogisticRegression.__module__.startswith("daal4py")
115
+ if daal_check_version((2024, "P", 1)):
116
+ assert LogisticRegression.__module__.startswith("sklearnex")
117
+ else:
118
+ assert LogisticRegression.__module__.startswith("daal4py")
105
119
  assert SVC.__module__.startswith("daal4py") or SVC.__module__.startswith("sklearnex")
106
120
 
107
121
  sklearnex.unpatch_sklearn()
@@ -119,7 +133,10 @@ def test_unpatch_by_list_many_estimators():
119
133
  assert KNeighborsRegressor.__module__.startswith(
120
134
  "daal4py"
121
135
  ) or KNeighborsRegressor.__module__.startswith("sklearnex")
122
- assert LogisticRegression.__module__.startswith("daal4py")
136
+ if daal_check_version((2024, "P", 1)):
137
+ assert LogisticRegression.__module__.startswith("sklearnex")
138
+ else:
139
+ assert LogisticRegression.__module__.startswith("daal4py")
123
140
  assert SVC.__module__.startswith("daal4py") or SVC.__module__.startswith("sklearnex")
124
141
 
125
142
  sklearnex.unpatch_sklearn(["KNeighborsRegressor", "RandomForestRegressor"])
@@ -131,7 +148,11 @@ def test_unpatch_by_list_many_estimators():
131
148
 
132
149
  assert RandomForestRegressor.__module__.startswith("sklearn")
133
150
  assert KNeighborsRegressor.__module__.startswith("sklearn")
134
- assert LogisticRegression.__module__.startswith("daal4py")
151
+ if daal_check_version((2024, "P", 1)):
152
+ assert LogisticRegression.__module__.startswith("sklearnex")
153
+ else:
154
+ assert LogisticRegression.__module__.startswith("daal4py")
155
+
135
156
  assert SVC.__module__.startswith("daal4py") or SVC.__module__.startswith("sklearnex")
136
157
 
137
158
 
@@ -164,14 +185,22 @@ def test_preview_namespace():
164
185
  from sklearn.linear_model import LinearRegression
165
186
  from sklearn.svm import SVC
166
187
 
167
- return LinearRegression(), PCA(), DBSCAN(), SVC(), RandomForestClassifier()
188
+ return (
189
+ LinearRegression(),
190
+ PCA(),
191
+ DBSCAN(),
192
+ SVC(),
193
+ RandomForestClassifier(),
194
+ )
168
195
 
169
196
  # BUG: previous patching tests force PCA to be patched with daal4py.
170
197
  # This unpatching returns behavior to expected
171
198
  sklearnex.unpatch_sklearn()
172
199
  # behavior with enabled preview
173
200
  sklearnex.patch_sklearn(preview=True)
174
- assert sklearnex.dispatcher._is_preview_enabled()
201
+ from sklearnex.dispatcher import _is_preview_enabled
202
+
203
+ assert _is_preview_enabled()
175
204
 
176
205
  lr, pca, dbscan, svc, rfc = get_estimators()
177
206
  assert "sklearnex" in rfc.__module__
@@ -188,21 +217,22 @@ def test_preview_namespace():
188
217
 
189
218
  # no patching behavior
190
219
  lr, pca, dbscan, svc, rfc = get_estimators()
191
- assert "sklearn." in lr.__module__
192
- assert "sklearn." in pca.__module__
193
- assert "sklearn." in dbscan.__module__
194
- assert "sklearn." in svc.__module__
195
- assert "sklearn." in rfc.__module__
220
+ assert "sklearn." in lr.__module__ and "daal4py" not in lr.__module__
221
+ assert "sklearn." in pca.__module__ and "daal4py" not in pca.__module__
222
+ assert "sklearn." in dbscan.__module__ and "daal4py" not in dbscan.__module__
223
+ assert "sklearn." in svc.__module__ and "daal4py" not in svc.__module__
224
+ assert "sklearn." in rfc.__module__ and "daal4py" not in rfc.__module__
196
225
 
197
226
  # default patching behavior
198
227
  sklearnex.patch_sklearn()
199
- assert not sklearnex.dispatcher._is_preview_enabled()
228
+ assert not _is_preview_enabled()
200
229
 
201
230
  lr, pca, dbscan, svc, rfc = get_estimators()
202
231
  if daal_check_version((2023, "P", 100)):
203
232
  assert "sklearnex" in lr.__module__
204
233
  else:
205
234
  assert "daal4py" in lr.__module__
235
+
206
236
  assert "daal4py" in pca.__module__
207
237
  assert "sklearnex" in rfc.__module__
208
238
  assert "sklearnex" in dbscan.__module__
@@ -0,0 +1,93 @@
1
+ # ==============================================================================
2
+ # Copyright 2023 Intel Corporation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ==============================================================================
16
+
17
+ import inspect
18
+ import logging
19
+ from multiprocessing import cpu_count
20
+
21
+ import pytest
22
+ from sklearn.base import BaseEstimator
23
+ from sklearn.datasets import make_classification
24
+
25
+ from sklearnex.dispatcher import get_patch_map
26
+ from sklearnex.svm import SVC, NuSVC
27
+
28
+ ESTIMATORS = set(
29
+ filter(
30
+ lambda x: inspect.isclass(x) and issubclass(x, BaseEstimator),
31
+ [value[0][0][2] for value in get_patch_map().values()],
32
+ )
33
+ )
34
+
35
+ X, Y = make_classification(n_samples=40, n_features=4, random_state=42)
36
+
37
+
38
+ @pytest.mark.parametrize("estimator_class", ESTIMATORS)
39
+ @pytest.mark.parametrize("n_jobs", [None, -1, 1, 2])
40
+ def test_n_jobs_support(caplog, estimator_class, n_jobs):
41
+ def check_estimator_doc(estimator):
42
+ if estimator.__doc__ is not None:
43
+ assert "n_jobs" in estimator.__doc__
44
+
45
+ def check_n_jobs_entry_in_logs(caplog, function_name, n_jobs):
46
+ for rec in caplog.records:
47
+ if function_name in rec.message and "threads" in rec.message:
48
+ expected_n_jobs = n_jobs if n_jobs > 0 else cpu_count() + 1 + n_jobs
49
+ logging.info(f"{function_name}: setting {expected_n_jobs} threads")
50
+ if f"{function_name}: setting {expected_n_jobs} threads" in rec.message:
51
+ return True
52
+ # False if n_jobs is set and not found in logs
53
+ return n_jobs is None
54
+
55
+ def check_method(*args, method, caplog):
56
+ method(*args)
57
+ assert check_n_jobs_entry_in_logs(caplog, method.__name__, n_jobs)
58
+
59
+ def check_methods_decoration(estimator):
60
+ funcs = {
61
+ i: getattr(estimator, i)
62
+ for i in dir(estimator)
63
+ if hasattr(estimator, i) and callable(getattr(estimator, i))
64
+ }
65
+
66
+ for func_name, func in funcs.items():
67
+ assert hasattr(func, "__onedal_n_jobs_decorated__") == (
68
+ func_name in estimator._n_jobs_supported_onedal_methods
69
+ ), f"{estimator}.{func_name} n_jobs decoration does not match {estimator} n_jobs supported methods"
70
+
71
+ caplog.set_level(logging.DEBUG, logger="sklearnex")
72
+ estimator_kwargs = {"n_jobs": n_jobs}
73
+ # by default, [Nu]SVC.predict_proba is restricted by @available_if decorator
74
+ if estimator_class in [SVC, NuSVC]:
75
+ estimator_kwargs["probability"] = True
76
+ estimator_instance = estimator_class(**estimator_kwargs)
77
+ # check `n_jobs` parameter doc entry
78
+ check_estimator_doc(estimator_class)
79
+ check_estimator_doc(estimator_instance)
80
+ # check `n_jobs` log entry for supported methods
81
+ # `fit` call is required before other methods
82
+ check_method(X, Y, method=estimator_instance.fit, caplog=caplog)
83
+ for method_name in estimator_instance._n_jobs_supported_onedal_methods:
84
+ if method_name == "fit":
85
+ continue
86
+ method = getattr(estimator_instance, method_name)
87
+ if len(inspect.signature(method).parameters) == 0:
88
+ check_method(method=method, caplog=caplog)
89
+ else:
90
+ check_method(X, method=method, caplog=caplog)
91
+ # check if correct methods were decorated
92
+ check_methods_decoration(estimator_class)
93
+ check_methods_decoration(estimator_instance)
@@ -14,6 +14,7 @@
14
14
  # limitations under the License.
15
15
  # ==============================================================================
16
16
 
17
+ import inspect
17
18
  import os
18
19
  import pathlib
19
20
  import re
@@ -96,15 +97,15 @@ def _load_all_models(patched):
96
97
  if patched:
97
98
  patch_sklearn()
98
99
 
99
- models = []
100
+ models = {}
100
101
  for patch_infos in get_patch_map().values():
101
- maybe_class = getattr(patch_infos[0][0][0], patch_infos[0][0][1])
102
+ maybe_class = getattr(patch_infos[0][0][0], patch_infos[0][0][1], None)
102
103
  if (
103
104
  maybe_class is not None
104
105
  and isclass(maybe_class)
105
106
  and issubclass(maybe_class, BaseEstimator)
106
107
  ):
107
- models.append(maybe_class())
108
+ models[patch_infos[0][0][1]] = maybe_class
108
109
 
109
110
  if patched:
110
111
  unpatch_sklearn()
@@ -116,7 +117,20 @@ PATCHED_MODELS = _load_all_models(patched=True)
116
117
  UNPATCHED_MODELS = _load_all_models(patched=False)
117
118
 
118
119
 
119
- @pytest.mark.parametrize(("patched", "unpatched"), zip(PATCHED_MODELS, UNPATCHED_MODELS))
120
- def test_is_patched_instance(patched, unpatched):
120
+ @pytest.mark.parametrize("estimator", UNPATCHED_MODELS.keys())
121
+ def test_is_patched_instance(estimator):
122
+ patched = PATCHED_MODELS[estimator]
123
+ unpatched = UNPATCHED_MODELS[estimator]
121
124
  assert is_patched_instance(patched), f"{patched} is a patched instance"
122
125
  assert not is_patched_instance(unpatched), f"{unpatched} is an unpatched instance"
126
+
127
+
128
+ @pytest.mark.parametrize("member", ["_onedal_cpu_supported", "_onedal_gpu_supported"])
129
+ @pytest.mark.parametrize(
130
+ "name",
131
+ [i for i in PATCHED_MODELS.keys() if "sklearnex" in PATCHED_MODELS[i].__module__],
132
+ )
133
+ def test_onedal_supported_member(name, member):
134
+ patched = PATCHED_MODELS[name]
135
+ sig = str(inspect.signature(getattr(patched, member)))
136
+ assert "(self, method_name, *data)" == sig
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ===============================================================================
3
2
  # Copyright 2022 Intel Corporation
4
3
  #