scikit-learn-intelex 2024.1.0__py311-none-manylinux1_x86_64.whl → 2024.4.0__py311-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 (62) hide show
  1. {scikit_learn_intelex-2024.1.0.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/METADATA +2 -2
  2. scikit_learn_intelex-2024.4.0.dist-info/RECORD +101 -0
  3. sklearnex/__init__.py +9 -7
  4. sklearnex/_device_offload.py +31 -4
  5. sklearnex/basic_statistics/__init__.py +2 -1
  6. sklearnex/basic_statistics/incremental_basic_statistics.py +288 -0
  7. sklearnex/basic_statistics/tests/test_incremental_basic_statistics.py +386 -0
  8. sklearnex/cluster/dbscan.py +6 -4
  9. sklearnex/conftest.py +63 -0
  10. sklearnex/{preview/decomposition → covariance}/__init__.py +19 -19
  11. sklearnex/covariance/incremental_covariance.py +130 -0
  12. sklearnex/covariance/tests/test_incremental_covariance.py +143 -0
  13. sklearnex/decomposition/pca.py +319 -1
  14. sklearnex/decomposition/tests/test_pca.py +34 -5
  15. sklearnex/dispatcher.py +93 -61
  16. sklearnex/ensemble/_forest.py +81 -97
  17. sklearnex/ensemble/tests/test_forest.py +15 -19
  18. sklearnex/linear_model/__init__.py +1 -2
  19. sklearnex/linear_model/linear.py +275 -347
  20. sklearnex/{preview/linear_model → linear_model}/logistic_regression.py +83 -50
  21. sklearnex/linear_model/tests/test_linear.py +40 -5
  22. sklearnex/linear_model/tests/test_logreg.py +70 -7
  23. sklearnex/neighbors/__init__.py +1 -1
  24. sklearnex/neighbors/_lof.py +221 -0
  25. sklearnex/neighbors/common.py +4 -1
  26. sklearnex/neighbors/knn_classification.py +47 -137
  27. sklearnex/neighbors/knn_regression.py +20 -132
  28. sklearnex/neighbors/knn_unsupervised.py +16 -93
  29. sklearnex/neighbors/tests/test_neighbors.py +12 -16
  30. sklearnex/preview/__init__.py +1 -1
  31. sklearnex/preview/cluster/k_means.py +8 -81
  32. sklearnex/preview/covariance/covariance.py +51 -16
  33. sklearnex/preview/covariance/tests/test_covariance.py +18 -5
  34. sklearnex/spmd/__init__.py +1 -0
  35. sklearnex/{preview/linear_model → spmd/covariance}/__init__.py +5 -5
  36. sklearnex/spmd/covariance/covariance.py +21 -0
  37. sklearnex/spmd/ensemble/forest.py +4 -12
  38. sklearnex/spmd/linear_model/__init__.py +2 -1
  39. sklearnex/spmd/linear_model/logistic_regression.py +21 -0
  40. sklearnex/svm/_common.py +4 -7
  41. sklearnex/svm/nusvc.py +74 -55
  42. sklearnex/svm/nusvr.py +9 -56
  43. sklearnex/svm/svc.py +74 -56
  44. sklearnex/svm/svr.py +6 -53
  45. sklearnex/tests/_utils.py +164 -0
  46. sklearnex/tests/test_memory_usage.py +9 -7
  47. sklearnex/tests/test_monkeypatch.py +179 -138
  48. sklearnex/tests/test_n_jobs_support.py +77 -9
  49. sklearnex/tests/test_parallel.py +6 -8
  50. sklearnex/tests/test_patching.py +338 -89
  51. sklearnex/utils/__init__.py +2 -1
  52. sklearnex/utils/_namespace.py +97 -0
  53. scikit_learn_intelex-2024.1.0.dist-info/RECORD +0 -97
  54. sklearnex/neighbors/lof.py +0 -436
  55. sklearnex/preview/decomposition/pca.py +0 -376
  56. sklearnex/preview/decomposition/tests/test_preview_pca.py +0 -42
  57. sklearnex/preview/linear_model/tests/test_preview_logistic_regression.py +0 -59
  58. sklearnex/tests/_models_info.py +0 -170
  59. sklearnex/tests/utils/_launch_algorithms.py +0 -118
  60. {scikit_learn_intelex-2024.1.0.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/LICENSE.txt +0 -0
  61. {scikit_learn_intelex-2024.1.0.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/WHEEL +0 -0
  62. {scikit_learn_intelex-2024.1.0.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/top_level.txt +0 -0
sklearnex/dispatcher.py CHANGED
@@ -1,5 +1,6 @@
1
1
  # ==============================================================================
2
2
  # Copyright 2021 Intel Corporation
3
+ # Copyright 2024 Fujitsu Limited
3
4
  #
4
5
  # Licensed under the Apache License, Version 2.0 (the "License");
5
6
  # you may not use this file except in compliance with the License.
@@ -22,7 +23,7 @@ from daal4py.sklearn._utils import daal_check_version, sklearn_check_version
22
23
 
23
24
 
24
25
  def _is_new_patching_available():
25
- return os.environ.get("OFF_ONEDAL_IFACE") is None and daal_check_version(
26
+ return os.environ.get("OFF_ONEDAL_IFACE", "0") == "0" and daal_check_version(
26
27
  (2021, "P", 300)
27
28
  )
28
29
 
@@ -32,16 +33,66 @@ def _is_preview_enabled():
32
33
 
33
34
 
34
35
  @lru_cache(maxsize=None)
35
- def get_patch_map():
36
+ def get_patch_map_core(preview=False):
37
+ if preview:
38
+ # use recursion to guarantee that state of preview
39
+ # and non-preview maps are done at the same time.
40
+ # The two lru_cache dicts are actually one underneath.
41
+ # Preview is always secondary. Both sklearnex patch
42
+ # maps are referring to the daal4py dict unless the
43
+ # key has been replaced. Use with caution.
44
+ mapping = get_patch_map_core().copy()
45
+
46
+ if _is_new_patching_available():
47
+ import sklearn.covariance as covariance_module
48
+
49
+ # Preview classes for patching
50
+ from .preview.cluster import KMeans as KMeans_sklearnex
51
+ from .preview.covariance import (
52
+ EmpiricalCovariance as EmpiricalCovariance_sklearnex,
53
+ )
54
+
55
+ # Since the state of the lru_cache without preview cannot be
56
+ # guaranteed to not have already enabled sklearnex algorithms
57
+ # when preview is used, setting the mapping element[1] to None
58
+ # should NOT be done. This may lose track of the unpatched
59
+ # sklearn estimator or function.
60
+ # KMeans
61
+ cluster_module, _, _ = mapping["kmeans"][0][0]
62
+ sklearn_obj = mapping["kmeans"][0][1]
63
+ mapping.pop("kmeans")
64
+ mapping["kmeans"] = [
65
+ [(cluster_module, "kmeans", KMeans_sklearnex), sklearn_obj]
66
+ ]
67
+
68
+ # Covariance
69
+ mapping["empiricalcovariance"] = [
70
+ [
71
+ (
72
+ covariance_module,
73
+ "EmpiricalCovariance",
74
+ EmpiricalCovariance_sklearnex,
75
+ ),
76
+ None,
77
+ ]
78
+ ]
79
+ return mapping
80
+
36
81
  from daal4py.sklearn.monkeypatch.dispatcher import _get_map_of_algorithms
37
82
 
83
+ # NOTE: this is a shallow copy of a dict, modification is dangerous
38
84
  mapping = _get_map_of_algorithms().copy()
39
85
 
86
+ # NOTE: Use of daal4py _get_map_of_algorithms and
87
+ # get_patch_map/get_patch_map_core should not be used concurrently.
88
+ # The setting of elements to None below may cause loss of state
89
+ # when interacting with sklearn. A dictionary key must not be
90
+ # modified but totally replaced, otherwise it will cause chaos.
91
+ # Hence why pop is being used.
40
92
  if _is_new_patching_available():
41
93
  # Scikit-learn* modules
42
94
  import sklearn as base_module
43
95
  import sklearn.cluster as cluster_module
44
- import sklearn.covariance as covariance_module
45
96
  import sklearn.decomposition as decomposition_module
46
97
  import sklearn.ensemble as ensemble_module
47
98
  import sklearn.linear_model as linear_model_module
@@ -64,80 +115,30 @@ def get_patch_map():
64
115
  from .utils.parallel import _FuncWrapperOld as _FuncWrapper_sklearnex
65
116
 
66
117
  from .cluster import DBSCAN as DBSCAN_sklearnex
118
+ from .decomposition import PCA as PCA_sklearnex
67
119
  from .ensemble import ExtraTreesClassifier as ExtraTreesClassifier_sklearnex
68
120
  from .ensemble import ExtraTreesRegressor as ExtraTreesRegressor_sklearnex
69
121
  from .ensemble import RandomForestClassifier as RandomForestClassifier_sklearnex
70
122
  from .ensemble import RandomForestRegressor as RandomForestRegressor_sklearnex
71
123
  from .linear_model import LinearRegression as LinearRegression_sklearnex
124
+ from .linear_model import LogisticRegression as LogisticRegression_sklearnex
72
125
  from .neighbors import KNeighborsClassifier as KNeighborsClassifier_sklearnex
73
126
  from .neighbors import KNeighborsRegressor as KNeighborsRegressor_sklearnex
74
127
  from .neighbors import LocalOutlierFactor as LocalOutlierFactor_sklearnex
75
128
  from .neighbors import NearestNeighbors as NearestNeighbors_sklearnex
76
-
77
- # Preview classes for patching
78
- from .preview.cluster import KMeans as KMeans_sklearnex
79
- from .preview.covariance import (
80
- EmpiricalCovariance as EmpiricalCovariance_sklearnex,
81
- )
82
- from .preview.decomposition import PCA as PCA_sklearnex
83
- from .preview.linear_model import (
84
- LogisticRegression as LogisticRegression_sklearnex,
85
- )
86
129
  from .svm import SVC as SVC_sklearnex
87
130
  from .svm import SVR as SVR_sklearnex
88
131
  from .svm import NuSVC as NuSVC_sklearnex
89
132
  from .svm import NuSVR as NuSVR_sklearnex
90
133
 
91
- # Patch for mapping
92
- if _is_preview_enabled():
93
- # PCA
94
- mapping.pop("pca")
95
- mapping["pca"] = [[(decomposition_module, "PCA", PCA_sklearnex), None]]
96
-
97
- # KMeans
98
- mapping.pop("kmeans")
99
- mapping["kmeans"] = [
100
- [
101
- (
102
- cluster_module,
103
- "KMeans",
104
- KMeans_sklearnex,
105
- ),
106
- None,
107
- ]
108
- ]
109
-
110
- # Covariance
111
- mapping["empiricalcovariance"] = [
112
- [
113
- (
114
- covariance_module,
115
- "EmpiricalCovariance",
116
- EmpiricalCovariance_sklearnex,
117
- ),
118
- None,
119
- ]
120
- ]
121
-
122
- # LogisticRegression
123
- mapping.pop("logisticregression")
124
- mapping.pop("log_reg")
125
- mapping["log_reg"] = [
126
- [
127
- (
128
- linear_model_module,
129
- "LogisticRegression",
130
- LogisticRegression_sklearnex,
131
- ),
132
- None,
133
- ]
134
- ]
135
- mapping["logisticregression"] = mapping["log_reg"]
136
-
137
134
  # DBSCAN
138
135
  mapping.pop("dbscan")
139
136
  mapping["dbscan"] = [[(cluster_module, "DBSCAN", DBSCAN_sklearnex), None]]
140
137
 
138
+ # PCA
139
+ mapping.pop("pca")
140
+ mapping["pca"] = [[(decomposition_module, "PCA", PCA_sklearnex), None]]
141
+
141
142
  # SVM
142
143
  mapping.pop("svm")
143
144
  mapping.pop("svc")
@@ -161,6 +162,24 @@ def get_patch_map():
161
162
  ]
162
163
  mapping["linearregression"] = mapping["linear"]
163
164
 
165
+ # Logistic Regression
166
+
167
+ mapping.pop("logisticregression")
168
+ mapping.pop("log_reg")
169
+ mapping.pop("logistic")
170
+ mapping.pop("_logistic_regression_path")
171
+ mapping["log_reg"] = [
172
+ [
173
+ (
174
+ linear_model_module,
175
+ "LogisticRegression",
176
+ LogisticRegression_sklearnex,
177
+ ),
178
+ None,
179
+ ]
180
+ ]
181
+ mapping["logisticregression"] = mapping["log_reg"]
182
+
164
183
  # kNN
165
184
  mapping.pop("knn_classifier")
166
185
  mapping.pop("kneighborsclassifier")
@@ -275,6 +294,19 @@ def get_patch_map():
275
294
  return mapping
276
295
 
277
296
 
297
+ # This is necessary to properly cache the patch_map when
298
+ # using preview.
299
+ def get_patch_map():
300
+ preview = _is_preview_enabled()
301
+ return get_patch_map_core(preview=preview)
302
+
303
+
304
+ get_patch_map.cache_clear = get_patch_map_core.cache_clear
305
+
306
+
307
+ get_patch_map.cache_info = get_patch_map_core.cache_info
308
+
309
+
278
310
  def get_patch_names():
279
311
  return list(get_patch_map().keys())
280
312
 
@@ -282,10 +314,10 @@ def get_patch_names():
282
314
  def patch_sklearn(name=None, verbose=True, global_patch=False, preview=False):
283
315
  if preview:
284
316
  os.environ["SKLEARNEX_PREVIEW"] = "enabled_via_patch_sklearn"
285
- if not sklearn_check_version("0.22"):
317
+ if not sklearn_check_version("0.24"):
286
318
  raise NotImplementedError(
287
319
  "Intel(R) Extension for Scikit-learn* patches apply "
288
- "for scikit-learn >= 0.22 only ..."
320
+ "for scikit-learn >= 0.24 only ..."
289
321
  )
290
322
 
291
323
  if global_patch:
@@ -25,8 +25,11 @@ from sklearn.ensemble import ExtraTreesClassifier as sklearn_ExtraTreesClassifie
25
25
  from sklearn.ensemble import ExtraTreesRegressor as sklearn_ExtraTreesRegressor
26
26
  from sklearn.ensemble import RandomForestClassifier as sklearn_RandomForestClassifier
27
27
  from sklearn.ensemble import RandomForestRegressor as sklearn_RandomForestRegressor
28
+ from sklearn.ensemble._forest import ForestClassifier as sklearn_ForestClassifier
29
+ from sklearn.ensemble._forest import ForestRegressor as sklearn_ForestRegressor
28
30
  from sklearn.ensemble._forest import _get_n_samples_bootstrap
29
31
  from sklearn.exceptions import DataConversionWarning
32
+ from sklearn.metrics import accuracy_score
30
33
  from sklearn.tree import (
31
34
  DecisionTreeClassifier,
32
35
  DecisionTreeRegressor,
@@ -35,37 +38,22 @@ from sklearn.tree import (
35
38
  )
36
39
  from sklearn.tree._tree import Tree
37
40
  from sklearn.utils import check_random_state, deprecated
38
- from sklearn.utils.validation import (
39
- check_array,
40
- check_consistent_length,
41
- check_is_fitted,
42
- check_X_y,
43
- )
41
+ from sklearn.utils.validation import check_array, check_is_fitted
44
42
 
43
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
45
44
  from daal4py.sklearn._utils import (
46
45
  check_tree_nodes,
47
- control_n_jobs,
48
46
  daal_check_version,
49
- run_with_n_jobs,
50
47
  sklearn_check_version,
51
48
  )
52
49
  from onedal.ensemble import ExtraTreesClassifier as onedal_ExtraTreesClassifier
53
50
  from onedal.ensemble import ExtraTreesRegressor as onedal_ExtraTreesRegressor
54
51
  from onedal.ensemble import RandomForestClassifier as onedal_RandomForestClassifier
55
52
  from onedal.ensemble import RandomForestRegressor as onedal_RandomForestRegressor
56
-
57
- # try catch needed for changes in structures observed in Scikit-learn around v0.22
58
- try:
59
- from sklearn.ensemble._forest import ForestClassifier as sklearn_ForestClassifier
60
- from sklearn.ensemble._forest import ForestRegressor as sklearn_ForestRegressor
61
- except ModuleNotFoundError:
62
- from sklearn.ensemble.forest import ForestClassifier as sklearn_ForestClassifier
63
- from sklearn.ensemble.forest import ForestRegressor as sklearn_ForestRegressor
64
-
65
53
  from onedal.primitives import get_tree_state_cls, get_tree_state_reg
66
54
  from onedal.utils import _num_features, _num_samples
55
+ from sklearnex.utils import get_namespace
67
56
 
68
- from .._config import get_config
69
57
  from .._device_offload import dispatch, wrap_output_data
70
58
  from .._utils import PatchingConditionsChain
71
59
 
@@ -78,26 +66,15 @@ if sklearn_check_version("1.4"):
78
66
  class BaseForest(ABC):
79
67
  _onedal_factory = None
80
68
 
81
- @run_with_n_jobs
82
69
  def _onedal_fit(self, X, y, sample_weight=None, queue=None):
83
- if sklearn_check_version("0.24"):
84
- X, y = self._validate_data(
85
- X,
86
- y,
87
- multi_output=False,
88
- accept_sparse=False,
89
- dtype=[np.float64, np.float32],
90
- force_all_finite=False,
91
- )
92
- else:
93
- X, y = check_X_y(
94
- X,
95
- y,
96
- accept_sparse=False,
97
- dtype=[np.float64, np.float32],
98
- multi_output=False,
99
- force_all_finite=False,
100
- )
70
+ X, y = self._validate_data(
71
+ X,
72
+ y,
73
+ multi_output=False,
74
+ accept_sparse=False,
75
+ dtype=[np.float64, np.float32],
76
+ force_all_finite=False,
77
+ )
101
78
 
102
79
  if sample_weight is not None:
103
80
  sample_weight = self.check_sample_weight(sample_weight, X)
@@ -175,15 +152,6 @@ class BaseForest(ABC):
175
152
 
176
153
  return self
177
154
 
178
- def _fit_proba(self, X, y, sample_weight=None, queue=None):
179
- params = self.get_params()
180
- self.__class__(**params)
181
-
182
- # We use stock metaestimators below, so the only way
183
- # to pass a queue is using config_context.
184
- cfg = get_config()
185
- cfg["target_offload"] = queue
186
-
187
155
  def _save_attributes(self):
188
156
  if self.oob_score:
189
157
  self.oob_score_ = self._onedal_estimator.oob_score_
@@ -206,8 +174,6 @@ class BaseForest(ABC):
206
174
  self._validate_estimator()
207
175
  return self
208
176
 
209
- # TODO:
210
- # move to onedal modul.
211
177
  def _check_parameters(self):
212
178
  if isinstance(self.min_samples_leaf, numbers.Integral):
213
179
  if not 1 <= self.min_samples_leaf:
@@ -455,14 +421,12 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
455
421
 
456
422
  # The estimator is checked against the class attribute for conformance.
457
423
  # This should only trigger if the user uses this class directly.
458
- if (
459
- self.estimator.__class__ == DecisionTreeClassifier
460
- and self._onedal_factory != onedal_RandomForestClassifier
424
+ if self.estimator.__class__ == DecisionTreeClassifier and not issubclass(
425
+ self._onedal_factory, onedal_RandomForestClassifier
461
426
  ):
462
427
  self._onedal_factory = onedal_RandomForestClassifier
463
- elif (
464
- self.estimator.__class__ == ExtraTreeClassifier
465
- and self._onedal_factory != onedal_ExtraTreesClassifier
428
+ elif self.estimator.__class__ == ExtraTreeClassifier and not issubclass(
429
+ self._onedal_factory, onedal_ExtraTreesClassifier
466
430
  ):
467
431
  self._onedal_factory = onedal_ExtraTreesClassifier
468
432
 
@@ -554,18 +518,14 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
554
518
  )
555
519
 
556
520
  if patching_status.get_status():
557
- if sklearn_check_version("0.24"):
558
- X, y = self._validate_data(
559
- X,
560
- y,
561
- multi_output=True,
562
- accept_sparse=True,
563
- dtype=[np.float64, np.float32],
564
- force_all_finite=False,
565
- )
566
- else:
567
- X = check_array(X, dtype=[np.float64, np.float32], force_all_finite=False)
568
- y = check_array(y, ensure_2d=False, dtype=X.dtype, force_all_finite=False)
521
+ X, y = self._validate_data(
522
+ X,
523
+ y,
524
+ multi_output=True,
525
+ accept_sparse=True,
526
+ dtype=[np.float64, np.float32],
527
+ force_all_finite=False,
528
+ )
569
529
 
570
530
  if y.ndim == 2 and y.shape[1] == 1:
571
531
  warnings.warn(
@@ -659,9 +619,38 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
659
619
  X,
660
620
  )
661
621
 
622
+ def predict_log_proba(self, X):
623
+ xp, _ = get_namespace(X)
624
+ proba = self.predict_proba(X)
625
+
626
+ if self.n_outputs_ == 1:
627
+ return xp.log(proba)
628
+
629
+ else:
630
+ for k in range(self.n_outputs_):
631
+ proba[k] = xp.log(proba[k])
632
+
633
+ return proba
634
+
635
+ @wrap_output_data
636
+ def score(self, X, y, sample_weight=None):
637
+ return dispatch(
638
+ self,
639
+ "score",
640
+ {
641
+ "onedal": self.__class__._onedal_score,
642
+ "sklearn": sklearn_ForestClassifier.score,
643
+ },
644
+ X,
645
+ y,
646
+ sample_weight=sample_weight,
647
+ )
648
+
662
649
  fit.__doc__ = sklearn_ForestClassifier.fit.__doc__
663
650
  predict.__doc__ = sklearn_ForestClassifier.predict.__doc__
664
651
  predict_proba.__doc__ = sklearn_ForestClassifier.predict_proba.__doc__
652
+ predict_log_proba.__doc__ = sklearn_ForestClassifier.predict_log_proba.__doc__
653
+ score.__doc__ = sklearn_ForestClassifier.score.__doc__
665
654
 
666
655
  def _onedal_cpu_supported(self, method_name, *data):
667
656
  class_name = self.__class__.__name__
@@ -688,7 +677,7 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
688
677
  ]
689
678
  )
690
679
 
691
- elif method_name in ["predict", "predict_proba"]:
680
+ elif method_name in ["predict", "predict_proba", "score"]:
692
681
  X = data[0]
693
682
 
694
683
  patching_status.and_conditions(
@@ -749,11 +738,11 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
749
738
  or self.estimator.__class__ == DecisionTreeClassifier,
750
739
  "ExtraTrees only supported starting from oneDAL version 2023.1",
751
740
  ),
752
- (sample_weight is not None, "sample_weight is not supported."),
741
+ (sample_weight is None, "sample_weight is not supported."),
753
742
  ]
754
743
  )
755
744
 
756
- elif method_name in ["predict", "predict_proba"]:
745
+ elif method_name in ["predict", "predict_proba", "score"]:
757
746
  X = data[0]
758
747
 
759
748
  patching_status.and_conditions(
@@ -787,7 +776,6 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
787
776
 
788
777
  return patching_status
789
778
 
790
- @run_with_n_jobs
791
779
  def _onedal_predict(self, X, queue=None):
792
780
  X = check_array(
793
781
  X,
@@ -802,17 +790,20 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
802
790
  res = self._onedal_estimator.predict(X, queue=queue)
803
791
  return np.take(self.classes_, res.ravel().astype(np.int64, casting="unsafe"))
804
792
 
805
- @run_with_n_jobs
806
793
  def _onedal_predict_proba(self, X, queue=None):
807
794
  X = check_array(X, dtype=[np.float64, np.float32], force_all_finite=False)
808
795
  check_is_fitted(self, "_onedal_estimator")
809
796
 
810
- if sklearn_check_version("0.23"):
811
- self._check_n_features(X, reset=False)
797
+ self._check_n_features(X, reset=False)
812
798
  if sklearn_check_version("1.0"):
813
799
  self._check_feature_names(X, reset=False)
814
800
  return self._onedal_estimator.predict_proba(X, queue=queue)
815
801
 
802
+ def _onedal_score(self, X, y, sample_weight=None, queue=None):
803
+ return accuracy_score(
804
+ y, self._onedal_predict(X, queue=queue), sample_weight=sample_weight
805
+ )
806
+
816
807
 
817
808
  class ForestRegressor(sklearn_ForestRegressor, BaseForest):
818
809
  _err = "out_of_bag_error_r2|out_of_bag_error_prediction"
@@ -847,14 +838,12 @@ class ForestRegressor(sklearn_ForestRegressor, BaseForest):
847
838
 
848
839
  # The splitter is checked against the class attribute for conformance
849
840
  # This should only trigger if the user uses this class directly.
850
- if (
851
- self.estimator.__class__ == DecisionTreeRegressor
852
- and self._onedal_factory != onedal_RandomForestRegressor
841
+ if self.estimator.__class__ == DecisionTreeRegressor and not issubclass(
842
+ self._onedal_factory, onedal_RandomForestRegressor
853
843
  ):
854
844
  self._onedal_factory = onedal_RandomForestRegressor
855
- elif (
856
- self.estimator.__class__ == ExtraTreeRegressor
857
- and self._onedal_factory != onedal_ExtraTreesRegressor
845
+ elif self.estimator.__class__ == ExtraTreeRegressor and not issubclass(
846
+ self._onedal_factory, onedal_ExtraTreesRegressor
858
847
  ):
859
848
  self._onedal_factory = onedal_ExtraTreesRegressor
860
849
 
@@ -924,18 +913,14 @@ class ForestRegressor(sklearn_ForestRegressor, BaseForest):
924
913
  )
925
914
 
926
915
  if patching_status.get_status():
927
- if sklearn_check_version("0.24"):
928
- X, y = self._validate_data(
929
- X,
930
- y,
931
- multi_output=True,
932
- accept_sparse=True,
933
- dtype=[np.float64, np.float32],
934
- force_all_finite=False,
935
- )
936
- else:
937
- X = check_array(X, dtype=[np.float64, np.float32], force_all_finite=False)
938
- y = check_array(y, ensure_2d=False, dtype=X.dtype, force_all_finite=False)
916
+ X, y = self._validate_data(
917
+ X,
918
+ y,
919
+ multi_output=True,
920
+ accept_sparse=True,
921
+ dtype=[np.float64, np.float32],
922
+ force_all_finite=False,
923
+ )
939
924
 
940
925
  if y.ndim == 2 and y.shape[1] == 1:
941
926
  warnings.warn(
@@ -1060,7 +1045,7 @@ class ForestRegressor(sklearn_ForestRegressor, BaseForest):
1060
1045
  or self.estimator.__class__ == DecisionTreeClassifier,
1061
1046
  "ExtraTrees only supported starting from oneDAL version 2023.1",
1062
1047
  ),
1063
- (sample_weight is not None, "sample_weight is not supported."),
1048
+ (sample_weight is None, "sample_weight is not supported."),
1064
1049
  ]
1065
1050
  )
1066
1051
 
@@ -1096,7 +1081,6 @@ class ForestRegressor(sklearn_ForestRegressor, BaseForest):
1096
1081
 
1097
1082
  return patching_status
1098
1083
 
1099
- @run_with_n_jobs
1100
1084
  def _onedal_predict(self, X, queue=None):
1101
1085
  X = check_array(
1102
1086
  X, dtype=[np.float64, np.float32], force_all_finite=False
@@ -1138,7 +1122,7 @@ class ForestRegressor(sklearn_ForestRegressor, BaseForest):
1138
1122
  predict.__doc__ = sklearn_ForestRegressor.predict.__doc__
1139
1123
 
1140
1124
 
1141
- @control_n_jobs
1125
+ @control_n_jobs(decorated_methods=["fit", "predict", "predict_proba", "score"])
1142
1126
  class RandomForestClassifier(ForestClassifier):
1143
1127
  __doc__ = sklearn_RandomForestClassifier.__doc__
1144
1128
  _onedal_factory = onedal_RandomForestClassifier
@@ -1348,7 +1332,7 @@ class RandomForestClassifier(ForestClassifier):
1348
1332
  self.min_bin_size = min_bin_size
1349
1333
 
1350
1334
 
1351
- @control_n_jobs
1335
+ @control_n_jobs(decorated_methods=["fit", "predict"])
1352
1336
  class RandomForestRegressor(ForestRegressor):
1353
1337
  __doc__ = sklearn_RandomForestRegressor.__doc__
1354
1338
  _onedal_factory = onedal_RandomForestRegressor
@@ -1549,7 +1533,7 @@ class RandomForestRegressor(ForestRegressor):
1549
1533
  self.min_bin_size = min_bin_size
1550
1534
 
1551
1535
 
1552
- @control_n_jobs
1536
+ @control_n_jobs(decorated_methods=["fit", "predict", "predict_proba", "score"])
1553
1537
  class ExtraTreesClassifier(ForestClassifier):
1554
1538
  __doc__ = sklearn_ExtraTreesClassifier.__doc__
1555
1539
  _onedal_factory = onedal_ExtraTreesClassifier
@@ -1759,7 +1743,7 @@ class ExtraTreesClassifier(ForestClassifier):
1759
1743
  self.min_bin_size = min_bin_size
1760
1744
 
1761
1745
 
1762
- @control_n_jobs
1746
+ @control_n_jobs(decorated_methods=["fit", "predict"])
1763
1747
  class ExtraTreesRegressor(ForestRegressor):
1764
1748
  __doc__ = sklearn_ExtraTreesRegressor.__doc__
1765
1749
  _onedal_factory = onedal_ExtraTreesRegressor
@@ -45,11 +45,7 @@ def test_sklearnex_import_rf_classifier(dataframe, queue):
45
45
  assert_allclose([1], _as_numpy(rf.predict([[0, 0, 0, 0]])))
46
46
 
47
47
 
48
- # TODO:
49
- # investigate failure for `dpnp.ndarrays` and `dpctl.tensors` on `GPU`
50
- @pytest.mark.parametrize(
51
- "dataframe,queue", get_dataframes_and_queues(device_filter_="cpu")
52
- )
48
+ @pytest.mark.parametrize("dataframe,queue", get_dataframes_and_queues())
53
49
  def test_sklearnex_import_rf_regression(dataframe, queue):
54
50
  from sklearnex.ensemble import RandomForestRegressor
55
51
 
@@ -59,17 +55,17 @@ def test_sklearnex_import_rf_regression(dataframe, queue):
59
55
  rf = RandomForestRegressor(max_depth=2, random_state=0).fit(X, y)
60
56
  assert "sklearnex" in rf.__module__
61
57
  pred = _as_numpy(rf.predict([[0, 0, 0, 0]]))
62
- if daal_check_version((2024, "P", 0)):
63
- assert_allclose([-6.971], pred, atol=1e-2)
58
+
59
+ if queue is not None and queue.sycl_device.is_gpu:
60
+ assert_allclose([-0.011208], pred, atol=1e-2)
64
61
  else:
65
- assert_allclose([-6.839], pred, atol=1e-2)
62
+ if daal_check_version((2024, "P", 0)):
63
+ assert_allclose([-6.971], pred, atol=1e-2)
64
+ else:
65
+ assert_allclose([-6.839], pred, atol=1e-2)
66
66
 
67
67
 
68
- # TODO:
69
- # investigate failure for `dpnp.ndarrays` and `dpctl.tensors` on `GPU`
70
- @pytest.mark.parametrize(
71
- "dataframe,queue", get_dataframes_and_queues(device_filter_="cpu")
72
- )
68
+ @pytest.mark.parametrize("dataframe,queue", get_dataframes_and_queues())
73
69
  def test_sklearnex_import_et_classifier(dataframe, queue):
74
70
  from sklearnex.ensemble import ExtraTreesClassifier
75
71
 
@@ -90,11 +86,7 @@ def test_sklearnex_import_et_classifier(dataframe, queue):
90
86
  assert_allclose([1], _as_numpy(rf.predict([[0, 0, 0, 0]])))
91
87
 
92
88
 
93
- # TODO:
94
- # investigate failure for `dpnp.ndarrays` and `dpctl.tensors` on `GPU`
95
- @pytest.mark.parametrize(
96
- "dataframe,queue", get_dataframes_and_queues(device_filter_="cpu")
97
- )
89
+ @pytest.mark.parametrize("dataframe,queue", get_dataframes_and_queues())
98
90
  def test_sklearnex_import_et_regression(dataframe, queue):
99
91
  from sklearnex.ensemble import ExtraTreesRegressor
100
92
 
@@ -114,4 +106,8 @@ def test_sklearnex_import_et_regression(dataframe, queue):
114
106
  ]
115
107
  )
116
108
  )
117
- assert_allclose([0.445], pred, atol=1e-2)
109
+
110
+ if queue is not None and queue.sycl_device.is_gpu:
111
+ assert_allclose([1.909769], pred, atol=1e-2)
112
+ else:
113
+ assert_allclose([0.445], pred, atol=1e-2)
@@ -16,14 +16,13 @@
16
16
 
17
17
  from .coordinate_descent import ElasticNet, Lasso
18
18
  from .linear import LinearRegression
19
- from .logistic_path import LogisticRegression, logistic_regression_path
19
+ from .logistic_regression import LogisticRegression
20
20
  from .ridge import Ridge
21
21
 
22
22
  __all__ = [
23
23
  "Ridge",
24
24
  "LinearRegression",
25
25
  "LogisticRegression",
26
- "logistic_regression_path",
27
26
  "ElasticNet",
28
27
  "Lasso",
29
28
  ]