scikit-learn-intelex 2024.5.0__py311-none-manylinux1_x86_64.whl → 2024.6.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 (35) hide show
  1. {scikit_learn_intelex-2024.5.0.dist-info → scikit_learn_intelex-2024.6.0.dist-info}/METADATA +2 -2
  2. {scikit_learn_intelex-2024.5.0.dist-info → scikit_learn_intelex-2024.6.0.dist-info}/RECORD +34 -30
  3. sklearnex/cluster/dbscan.py +3 -0
  4. sklearnex/cluster/tests/test_dbscan.py +8 -6
  5. sklearnex/conftest.py +11 -1
  6. sklearnex/decomposition/tests/test_pca.py +4 -2
  7. sklearnex/dispatcher.py +15 -1
  8. sklearnex/ensemble/_forest.py +114 -23
  9. sklearnex/ensemble/tests/test_forest.py +13 -3
  10. sklearnex/glob/dispatcher.py +16 -2
  11. sklearnex/linear_model/incremental_linear.py +102 -25
  12. sklearnex/linear_model/linear.py +25 -7
  13. sklearnex/linear_model/logistic_regression.py +13 -15
  14. sklearnex/linear_model/tests/test_incremental_linear.py +10 -10
  15. sklearnex/linear_model/tests/test_linear.py +2 -2
  16. sklearnex/neighbors/knn_regression.py +24 -0
  17. sklearnex/preview/__init__.py +1 -1
  18. sklearnex/preview/decomposition/__init__.py +19 -0
  19. sklearnex/preview/decomposition/incremental_pca.py +228 -0
  20. sklearnex/preview/decomposition/tests/test_incremental_pca.py +266 -0
  21. sklearnex/svm/_common.py +165 -20
  22. sklearnex/svm/nusvc.py +40 -4
  23. sklearnex/svm/nusvr.py +31 -2
  24. sklearnex/svm/svc.py +40 -4
  25. sklearnex/svm/svr.py +31 -2
  26. sklearnex/tests/_utils.py +49 -17
  27. sklearnex/tests/test_common.py +54 -0
  28. sklearnex/tests/test_memory_usage.py +185 -126
  29. sklearnex/tests/test_patching.py +5 -12
  30. sklearnex/tests/test_run_to_run_stability.py +283 -0
  31. sklearnex/utils/_namespace.py +1 -1
  32. sklearnex/tests/test_run_to_run_stability_tests.py +0 -428
  33. {scikit_learn_intelex-2024.5.0.dist-info → scikit_learn_intelex-2024.6.0.dist-info}/LICENSE.txt +0 -0
  34. {scikit_learn_intelex-2024.5.0.dist-info → scikit_learn_intelex-2024.6.0.dist-info}/WHEEL +0 -0
  35. {scikit_learn_intelex-2024.5.0.dist-info → scikit_learn_intelex-2024.6.0.dist-info}/top_level.txt +0 -0
sklearnex/svm/_common.py CHANGED
@@ -15,15 +15,20 @@
15
15
  # ==============================================================================
16
16
 
17
17
  from abc import ABC
18
+ from numbers import Number, Real
18
19
 
19
20
  import numpy as np
21
+ from scipy import sparse as sp
22
+ from sklearn.base import BaseEstimator, ClassifierMixin
20
23
  from sklearn.calibration import CalibratedClassifierCV
24
+ from sklearn.metrics import r2_score
21
25
  from sklearn.model_selection import StratifiedKFold
22
26
  from sklearn.preprocessing import LabelEncoder
23
27
 
24
28
  from daal4py.sklearn._utils import sklearn_check_version
25
- from onedal.utils import _column_or_1d
29
+ from onedal.utils import _check_array, _check_X_y, _column_or_1d
26
30
 
31
+ from .._config import config_context, get_config
27
32
  from .._utils import PatchingConditionsChain
28
33
 
29
34
 
@@ -51,7 +56,8 @@ def set_intercept(self, value):
51
56
  del self._onedal_estimator._onedal_model
52
57
 
53
58
 
54
- class BaseSVM(ABC):
59
+ class BaseSVM(BaseEstimator, ABC):
60
+
55
61
  def _onedal_gpu_supported(self, method_name, *data):
56
62
  patching_status = PatchingConditionsChain(f"sklearn.{method_name}")
57
63
  patching_status.and_conditions([(False, "GPU offloading is not supported.")])
@@ -74,7 +80,7 @@ class BaseSVM(ABC):
74
80
  )
75
81
  return patching_status
76
82
  inference_methods = (
77
- ["predict"]
83
+ ["predict", "score"]
78
84
  if class_name.endswith("R")
79
85
  else ["predict", "predict_proba", "decision_function", "score"]
80
86
  )
@@ -85,6 +91,130 @@ class BaseSVM(ABC):
85
91
  return patching_status
86
92
  raise RuntimeError(f"Unknown method {method_name} in {class_name}")
87
93
 
94
+ def _compute_gamma_sigma(self, X):
95
+ # only run extended conversion if kernel is not linear
96
+ # set to a value = 1.0, so gamma will always be passed to
97
+ # the onedal estimator as a float type
98
+ if self.kernel == "linear":
99
+ return 1.0
100
+
101
+ if isinstance(self.gamma, str):
102
+ if self.gamma == "scale":
103
+ if sp.issparse(X):
104
+ # var = E[X^2] - E[X]^2
105
+ X_sc = (X.multiply(X)).mean() - (X.mean()) ** 2
106
+ else:
107
+ X_sc = X.var()
108
+ _gamma = 1.0 / (X.shape[1] * X_sc) if X_sc != 0 else 1.0
109
+ elif self.gamma == "auto":
110
+ _gamma = 1.0 / X.shape[1]
111
+ else:
112
+ raise ValueError(
113
+ "When 'gamma' is a string, it should be either 'scale' or "
114
+ "'auto'. Got '{}' instead.".format(self.gamma)
115
+ )
116
+ else:
117
+ if sklearn_check_version("1.1") and not sklearn_check_version("1.2"):
118
+ if isinstance(self.gamma, Real):
119
+ if self.gamma <= 0:
120
+ msg = (
121
+ f"gamma value must be > 0; {self.gamma!r} is invalid. Use"
122
+ " a positive number or use 'auto' to set gamma to a"
123
+ " value of 1 / n_features."
124
+ )
125
+ raise ValueError(msg)
126
+ _gamma = self.gamma
127
+ else:
128
+ msg = (
129
+ "The gamma value should be set to 'scale', 'auto' or a"
130
+ f" positive float value. {self.gamma!r} is not a valid option"
131
+ )
132
+ raise ValueError(msg)
133
+ else:
134
+ _gamma = self.gamma
135
+ return _gamma
136
+
137
+ def _onedal_fit_checks(self, X, y, sample_weight=None):
138
+ if hasattr(self, "decision_function_shape"):
139
+ if self.decision_function_shape not in ("ovr", "ovo", None):
140
+ raise ValueError(
141
+ f"decision_function_shape must be either 'ovr' or 'ovo', "
142
+ f"got {self.decision_function_shape}."
143
+ )
144
+
145
+ if y is None:
146
+ if self._get_tags()["requires_y"]:
147
+ raise ValueError(
148
+ f"This {self.__class__.__name__} estimator "
149
+ f"requires y to be passed, but the target y is None."
150
+ )
151
+ # using onedal _check_X_y to insure X and y are contiguous
152
+ # finite check occurs in onedal estimator
153
+ X, y = _check_X_y(
154
+ X,
155
+ y,
156
+ dtype=[np.float64, np.float32],
157
+ force_all_finite=False,
158
+ accept_sparse="csr",
159
+ )
160
+ y = self._validate_targets(y)
161
+ sample_weight = self._get_sample_weight(X, y, sample_weight)
162
+ return X, y, sample_weight
163
+
164
+ def _get_sample_weight(self, X, y, sample_weight):
165
+ n_samples = X.shape[0]
166
+ dtype = X.dtype
167
+ if n_samples == 1:
168
+ raise ValueError("n_samples=1")
169
+
170
+ sample_weight = np.ascontiguousarray(
171
+ [] if sample_weight is None else sample_weight, dtype=np.float64
172
+ )
173
+
174
+ sample_weight_count = sample_weight.shape[0]
175
+ if sample_weight_count != 0 and sample_weight_count != n_samples:
176
+ raise ValueError(
177
+ "sample_weight and X have incompatible shapes: "
178
+ "%r vs %r\n"
179
+ "Note: Sparse matrices cannot be indexed w/"
180
+ "boolean masks (use `indices=True` in CV)."
181
+ % (len(sample_weight), X.shape)
182
+ )
183
+
184
+ if sample_weight_count == 0:
185
+ if not isinstance(self, ClassifierMixin) or self.class_weight_ is None:
186
+ return None
187
+ sample_weight = np.ones(n_samples, dtype=dtype)
188
+ elif isinstance(sample_weight, Number):
189
+ sample_weight = np.full(n_samples, sample_weight, dtype=dtype)
190
+ else:
191
+ sample_weight = _check_array(
192
+ sample_weight,
193
+ accept_sparse=False,
194
+ ensure_2d=False,
195
+ dtype=dtype,
196
+ order="C",
197
+ )
198
+ if sample_weight.ndim != 1:
199
+ raise ValueError("Sample weights must be 1D array or scalar")
200
+
201
+ if sample_weight.shape != (n_samples,):
202
+ raise ValueError(
203
+ "sample_weight.shape == {}, expected {}!".format(
204
+ sample_weight.shape, (n_samples,)
205
+ )
206
+ )
207
+
208
+ if np.all(sample_weight <= 0):
209
+ if "nusvc" in self.__module__:
210
+ raise ValueError("negative dimensions are not allowed")
211
+ else:
212
+ raise ValueError(
213
+ "Invalid input - all samples have zero or negative weights."
214
+ )
215
+
216
+ return sample_weight
217
+
88
218
 
89
219
  class BaseSVC(BaseSVM):
90
220
  def _compute_balanced_class_weight(self, y):
@@ -105,22 +235,31 @@ class BaseSVC(BaseSVM):
105
235
  params["decision_function_shape"] = "ovr"
106
236
  clf_base = self.__class__(**params)
107
237
 
108
- try:
109
- n_splits = 5
110
- n_jobs = n_splits if queue is None or queue.sycl_device.is_cpu else 1
111
- cv = StratifiedKFold(
112
- n_splits=n_splits, shuffle=True, random_state=self.random_state
113
- )
114
- self.clf_prob = CalibratedClassifierCV(
115
- clf_base, ensemble=False, cv=cv, method="sigmoid", n_jobs=n_jobs
116
- )
117
- self.clf_prob.fit(X, y, sample_weight)
118
- except ValueError:
119
- clf_base = clf_base.fit(X, y, sample_weight)
120
- self.clf_prob = CalibratedClassifierCV(
121
- clf_base, cv="prefit", method="sigmoid"
122
- )
123
- self.clf_prob.fit(X, y, sample_weight)
238
+ # We use stock metaestimators below, so the only way
239
+ # to pass a queue is using config_context.
240
+ cfg = get_config()
241
+ cfg["target_offload"] = queue
242
+ with config_context(**cfg):
243
+ try:
244
+ n_splits = 5
245
+ n_jobs = n_splits if queue is None or queue.sycl_device.is_cpu else 1
246
+ cv = StratifiedKFold(
247
+ n_splits=n_splits, shuffle=True, random_state=self.random_state
248
+ )
249
+ self.clf_prob = CalibratedClassifierCV(
250
+ clf_base,
251
+ ensemble=False,
252
+ cv=cv,
253
+ method="sigmoid",
254
+ )
255
+ self.clf_prob.fit(X, y, sample_weight)
256
+
257
+ except ValueError:
258
+ clf_base = clf_base.fit(X, y, sample_weight)
259
+ self.clf_prob = CalibratedClassifierCV(
260
+ clf_base, cv="prefit", method="sigmoid"
261
+ )
262
+ self.clf_prob.fit(X, y, sample_weight)
124
263
 
125
264
  def _save_attributes(self):
126
265
  self.support_vectors_ = self._onedal_estimator.support_vectors_
@@ -129,7 +268,8 @@ class BaseSVC(BaseSVM):
129
268
  self.dual_coef_ = self._onedal_estimator.dual_coef_
130
269
  self.shape_fit_ = self._onedal_estimator.class_weight_
131
270
  self.classes_ = self._onedal_estimator.classes_
132
- self.class_weight_ = self._onedal_estimator.class_weight_
271
+ if isinstance(self, ClassifierMixin) or not sklearn_check_version("1.2"):
272
+ self.class_weight_ = self._onedal_estimator.class_weight_
133
273
  self.support_ = self._onedal_estimator.support_
134
274
 
135
275
  self._intercept_ = self._onedal_estimator.intercept_
@@ -183,3 +323,8 @@ class BaseSVR(BaseSVM):
183
323
 
184
324
  if sklearn_check_version("1.1"):
185
325
  self.n_iter_ = self._onedal_estimator.n_iter_
326
+
327
+ def _onedal_score(self, X, y, sample_weight=None, queue=None):
328
+ return r2_score(
329
+ y, self._onedal_predict(X, queue=queue), sample_weight=sample_weight
330
+ )
sklearnex/svm/nusvc.py CHANGED
@@ -83,6 +83,17 @@ class NuSVC(sklearn_NuSVC, BaseSVC):
83
83
  def fit(self, X, y, sample_weight=None):
84
84
  if sklearn_check_version("1.2"):
85
85
  self._validate_params()
86
+ elif self.nu <= 0 or self.nu > 1:
87
+ # else if added to correct issues with
88
+ # sklearn tests:
89
+ # svm/tests/test_sparse.py::test_error
90
+ # svm/tests/test_svm.py::test_bad_input
91
+ # for sklearn versions < 1.2 (i.e. without
92
+ # validate_params parameter checking)
93
+ # Without this, a segmentation fault with
94
+ # Windows fatal exception: access violation
95
+ # occurs
96
+ raise ValueError("nu <= 0 or nu > 1")
86
97
  if sklearn_check_version("1.0"):
87
98
  self._check_feature_names(X, reset=True)
88
99
  dispatch(
@@ -94,7 +105,7 @@ class NuSVC(sklearn_NuSVC, BaseSVC):
94
105
  },
95
106
  X,
96
107
  y,
97
- sample_weight,
108
+ sample_weight=sample_weight,
98
109
  )
99
110
 
100
111
  return self
@@ -242,12 +253,31 @@ class NuSVC(sklearn_NuSVC, BaseSVC):
242
253
 
243
254
  decision_function.__doc__ = sklearn_NuSVC.decision_function.__doc__
244
255
 
256
+ def _get_sample_weight(self, X, y, sample_weight=None):
257
+ sample_weight = super()._get_sample_weight(X, y, sample_weight)
258
+ if sample_weight is None:
259
+ return sample_weight
260
+
261
+ weight_per_class = [
262
+ np.sum(sample_weight[y == class_label]) for class_label in np.unique(y)
263
+ ]
264
+
265
+ for i in range(len(weight_per_class)):
266
+ for j in range(i + 1, len(weight_per_class)):
267
+ if self.nu * (weight_per_class[i] + weight_per_class[j]) / 2 > min(
268
+ weight_per_class[i], weight_per_class[j]
269
+ ):
270
+ raise ValueError("specified nu is infeasible")
271
+
272
+ return sample_weight
273
+
245
274
  def _onedal_fit(self, X, y, sample_weight=None, queue=None):
275
+ X, _, weights = self._onedal_fit_checks(X, y, sample_weight)
246
276
  onedal_params = {
247
277
  "nu": self.nu,
248
278
  "kernel": self.kernel,
249
279
  "degree": self.degree,
250
- "gamma": self.gamma,
280
+ "gamma": self._compute_gamma_sigma(X),
251
281
  "coef0": self.coef0,
252
282
  "tol": self.tol,
253
283
  "shrinking": self.shrinking,
@@ -259,10 +289,16 @@ class NuSVC(sklearn_NuSVC, BaseSVC):
259
289
  }
260
290
 
261
291
  self._onedal_estimator = onedal_NuSVC(**onedal_params)
262
- self._onedal_estimator.fit(X, y, sample_weight, queue=queue)
292
+ self._onedal_estimator.fit(X, y, weights, queue=queue)
263
293
 
264
294
  if self.probability:
265
- self._fit_proba(X, y, sample_weight, queue=queue)
295
+ self._fit_proba(
296
+ X,
297
+ y,
298
+ sample_weight=sample_weight,
299
+ queue=queue,
300
+ )
301
+
266
302
  self._save_attributes()
267
303
 
268
304
  def _onedal_predict(self, X, queue=None):
sklearnex/svm/nusvr.py CHANGED
@@ -65,6 +65,17 @@ class NuSVR(sklearn_NuSVR, BaseSVR):
65
65
  def fit(self, X, y, sample_weight=None):
66
66
  if sklearn_check_version("1.2"):
67
67
  self._validate_params()
68
+ elif self.nu <= 0 or self.nu > 1:
69
+ # else if added to correct issues with
70
+ # sklearn tests:
71
+ # svm/tests/test_sparse.py::test_error
72
+ # svm/tests/test_svm.py::test_bad_input
73
+ # for sklearn versions < 1.2 (i.e. without
74
+ # validate_params parameter checking)
75
+ # Without this, a segmentation fault with
76
+ # Windows fatal exception: access violation
77
+ # occurs
78
+ raise ValueError("nu <= 0 or nu > 1")
68
79
  if sklearn_check_version("1.0"):
69
80
  self._check_feature_names(X, reset=True)
70
81
  dispatch(
@@ -76,7 +87,7 @@ class NuSVR(sklearn_NuSVR, BaseSVR):
76
87
  },
77
88
  X,
78
89
  y,
79
- sample_weight,
90
+ sample_weight=sample_weight,
80
91
  )
81
92
  return self
82
93
 
@@ -94,13 +105,30 @@ class NuSVR(sklearn_NuSVR, BaseSVR):
94
105
  X,
95
106
  )
96
107
 
108
+ @wrap_output_data
109
+ def score(self, X, y, sample_weight=None):
110
+ if sklearn_check_version("1.0"):
111
+ self._check_feature_names(X, reset=False)
112
+ return dispatch(
113
+ self,
114
+ "score",
115
+ {
116
+ "onedal": self.__class__._onedal_score,
117
+ "sklearn": sklearn_NuSVR.score,
118
+ },
119
+ X,
120
+ y,
121
+ sample_weight=sample_weight,
122
+ )
123
+
97
124
  def _onedal_fit(self, X, y, sample_weight=None, queue=None):
125
+ X, _, sample_weight = self._onedal_fit_checks(X, y, sample_weight)
98
126
  onedal_params = {
99
127
  "C": self.C,
100
128
  "nu": self.nu,
101
129
  "kernel": self.kernel,
102
130
  "degree": self.degree,
103
- "gamma": self.gamma,
131
+ "gamma": self._compute_gamma_sigma(X),
104
132
  "coef0": self.coef0,
105
133
  "tol": self.tol,
106
134
  "shrinking": self.shrinking,
@@ -117,3 +145,4 @@ class NuSVR(sklearn_NuSVR, BaseSVR):
117
145
 
118
146
  fit.__doc__ = sklearn_NuSVR.fit.__doc__
119
147
  predict.__doc__ = sklearn_NuSVR.predict.__doc__
148
+ score.__doc__ = sklearn_NuSVR.score.__doc__
sklearnex/svm/svc.py CHANGED
@@ -85,6 +85,17 @@ class SVC(sklearn_SVC, BaseSVC):
85
85
  def fit(self, X, y, sample_weight=None):
86
86
  if sklearn_check_version("1.2"):
87
87
  self._validate_params()
88
+ elif self.C <= 0:
89
+ # else if added to correct issues with
90
+ # sklearn tests:
91
+ # svm/tests/test_sparse.py::test_error
92
+ # svm/tests/test_svm.py::test_bad_input
93
+ # for sklearn versions < 1.2 (i.e. without
94
+ # validate_params parameter checking)
95
+ # Without this, a segmentation fault with
96
+ # Windows fatal exception: access violation
97
+ # occurs
98
+ raise ValueError("C <= 0")
88
99
  if sklearn_check_version("1.0"):
89
100
  self._check_feature_names(X, reset=True)
90
101
  dispatch(
@@ -96,8 +107,9 @@ class SVC(sklearn_SVC, BaseSVC):
96
107
  },
97
108
  X,
98
109
  y,
99
- sample_weight,
110
+ sample_weight=sample_weight,
100
111
  )
112
+
101
113
  return self
102
114
 
103
115
  @wrap_output_data
@@ -270,12 +282,30 @@ class SVC(sklearn_SVC, BaseSVC):
270
282
  return patching_status
271
283
  raise RuntimeError(f"Unknown method {method_name} in {class_name}")
272
284
 
285
+ def _get_sample_weight(self, X, y, sample_weight=None):
286
+ sample_weight = super()._get_sample_weight(X, y, sample_weight)
287
+ if sample_weight is None:
288
+ return sample_weight
289
+
290
+ if np.any(sample_weight <= 0) and len(np.unique(y[sample_weight > 0])) != len(
291
+ self.classes_
292
+ ):
293
+ raise ValueError(
294
+ "Invalid input - all samples with positive weights "
295
+ "belong to the same class"
296
+ if sklearn_check_version("1.2")
297
+ else "Invalid input - all samples with positive weights "
298
+ "have the same label."
299
+ )
300
+ return sample_weight
301
+
273
302
  def _onedal_fit(self, X, y, sample_weight=None, queue=None):
303
+ X, _, weights = self._onedal_fit_checks(X, y, sample_weight)
274
304
  onedal_params = {
275
305
  "C": self.C,
276
306
  "kernel": self.kernel,
277
307
  "degree": self.degree,
278
- "gamma": self.gamma,
308
+ "gamma": self._compute_gamma_sigma(X),
279
309
  "coef0": self.coef0,
280
310
  "tol": self.tol,
281
311
  "shrinking": self.shrinking,
@@ -287,10 +317,16 @@ class SVC(sklearn_SVC, BaseSVC):
287
317
  }
288
318
 
289
319
  self._onedal_estimator = onedal_SVC(**onedal_params)
290
- self._onedal_estimator.fit(X, y, sample_weight, queue=queue)
320
+ self._onedal_estimator.fit(X, y, weights, queue=queue)
291
321
 
292
322
  if self.probability:
293
- self._fit_proba(X, y, sample_weight, queue=queue)
323
+ self._fit_proba(
324
+ X,
325
+ y,
326
+ sample_weight=sample_weight,
327
+ queue=queue,
328
+ )
329
+
294
330
  self._save_attributes()
295
331
 
296
332
  def _onedal_predict(self, X, queue=None):
sklearnex/svm/svr.py CHANGED
@@ -65,6 +65,17 @@ class SVR(sklearn_SVR, BaseSVR):
65
65
  def fit(self, X, y, sample_weight=None):
66
66
  if sklearn_check_version("1.2"):
67
67
  self._validate_params()
68
+ elif self.C <= 0:
69
+ # else if added to correct issues with
70
+ # sklearn tests:
71
+ # svm/tests/test_sparse.py::test_error
72
+ # svm/tests/test_svm.py::test_bad_input
73
+ # for sklearn versions < 1.2 (i.e. without
74
+ # validate_params parameter checking)
75
+ # Without this, a segmentation fault with
76
+ # Windows fatal exception: access violation
77
+ # occurs
78
+ raise ValueError("C <= 0")
68
79
  if sklearn_check_version("1.0"):
69
80
  self._check_feature_names(X, reset=True)
70
81
  dispatch(
@@ -76,7 +87,7 @@ class SVR(sklearn_SVR, BaseSVR):
76
87
  },
77
88
  X,
78
89
  y,
79
- sample_weight,
90
+ sample_weight=sample_weight,
80
91
  )
81
92
 
82
93
  return self
@@ -95,13 +106,30 @@ class SVR(sklearn_SVR, BaseSVR):
95
106
  X,
96
107
  )
97
108
 
109
+ @wrap_output_data
110
+ def score(self, X, y, sample_weight=None):
111
+ if sklearn_check_version("1.0"):
112
+ self._check_feature_names(X, reset=False)
113
+ return dispatch(
114
+ self,
115
+ "score",
116
+ {
117
+ "onedal": self.__class__._onedal_score,
118
+ "sklearn": sklearn_SVR.score,
119
+ },
120
+ X,
121
+ y,
122
+ sample_weight=sample_weight,
123
+ )
124
+
98
125
  def _onedal_fit(self, X, y, sample_weight=None, queue=None):
126
+ X, _, sample_weight = self._onedal_fit_checks(X, y, sample_weight)
99
127
  onedal_params = {
100
128
  "C": self.C,
101
129
  "epsilon": self.epsilon,
102
130
  "kernel": self.kernel,
103
131
  "degree": self.degree,
104
- "gamma": self.gamma,
132
+ "gamma": self._compute_gamma_sigma(X),
105
133
  "coef0": self.coef0,
106
134
  "tol": self.tol,
107
135
  "shrinking": self.shrinking,
@@ -118,3 +146,4 @@ class SVR(sklearn_SVR, BaseSVR):
118
146
 
119
147
  fit.__doc__ = sklearn_SVR.fit.__doc__
120
148
  predict.__doc__ = sklearn_SVR.predict.__doc__
149
+ score.__doc__ = sklearn_SVR.score.__doc__
sklearnex/tests/_utils.py CHANGED
@@ -14,9 +14,11 @@
14
14
  # limitations under the License.
15
15
  # ==============================================================================
16
16
 
17
+ from functools import partial
17
18
  from inspect import isclass
18
19
 
19
20
  import numpy as np
21
+ from scipy import sparse as sp
20
22
  from sklearn import clone
21
23
  from sklearn.base import (
22
24
  BaseEstimator,
@@ -116,8 +118,8 @@ def gen_models_info(algorithms):
116
118
 
117
119
  if i in PATCHED_MODELS:
118
120
  est = PATCHED_MODELS[i]
119
- elif i in SPECIAL_INSTANCES:
120
- est = SPECIAL_INSTANCES[i].__class__
121
+ elif isinstance(algorithms[i], BaseEstimator):
122
+ est = algorithms[i].__class__
121
123
  else:
122
124
  raise KeyError(f"Unrecognized sklearnex estimator: {i}")
123
125
 
@@ -138,24 +140,54 @@ def gen_models_info(algorithms):
138
140
  return output
139
141
 
140
142
 
141
- def gen_dataset(estimator, queue=None, target_df=None, dtype=np.float64):
142
- dataset = None
143
- name = estimator.__class__.__name__
144
- est = PATCHED_MODELS[name]
143
+ def gen_dataset_type(est):
144
+ # est should be an estimator or estimator class
145
+ # dataset initialized to classification, but will be swapped
146
+ # for other types as necessary
147
+ dataset = "classification"
148
+ estimator = est.__class__ if isinstance(est, BaseEstimator) else est
149
+
145
150
  for mixin, _, data in mixin_map:
146
- if issubclass(est, mixin) and data is not None:
151
+ if issubclass(estimator, mixin) and data is not None:
147
152
  dataset = data
153
+ return dataset
154
+
155
+
156
+ _dataset_dict = {
157
+ "classification": [partial(load_iris, return_X_y=True)],
158
+ "regression": [partial(load_diabetes, return_X_y=True)],
159
+ }
160
+
161
+
162
+ def gen_dataset(
163
+ est,
164
+ datasets=_dataset_dict,
165
+ sparse=False,
166
+ queue=None,
167
+ target_df=None,
168
+ dtype=None,
169
+ ):
170
+ dataset_type = gen_dataset_type(est)
171
+ output = []
148
172
  # load data
149
- if dataset == "classification" or dataset is None:
150
- X, y = load_iris(return_X_y=True)
151
- elif dataset == "regression":
152
- X, y = load_diabetes(return_X_y=True)
153
- else:
154
- raise ValueError("Unknown dataset type")
155
-
156
- X = _convert_to_dataframe(X, sycl_queue=queue, target_df=target_df, dtype=dtype)
157
- y = _convert_to_dataframe(y, sycl_queue=queue, target_df=target_df, dtype=dtype)
158
- return X, y
173
+ flag = dtype is None
174
+
175
+ for func in datasets[dataset_type]:
176
+ X, y = func()
177
+ if flag:
178
+ dtype = X.dtype if hasattr(X, "dtype") else np.float64
179
+
180
+ if sparse:
181
+ X = sp.csr_matrix(X)
182
+ else:
183
+ X = _convert_to_dataframe(
184
+ X, sycl_queue=queue, target_df=target_df, dtype=dtype
185
+ )
186
+ y = _convert_to_dataframe(
187
+ y, sycl_queue=queue, target_df=target_df, dtype=dtype
188
+ )
189
+ output += [[X, y]]
190
+ return output
159
191
 
160
192
 
161
193
  DTYPES = [
@@ -0,0 +1,54 @@
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
+ import os
18
+ from glob import glob
19
+
20
+ import pytest
21
+
22
+ ALLOWED_LOCATIONS = [
23
+ "_config.py",
24
+ "_device_offload.py",
25
+ "test",
26
+ "svc.py",
27
+ "svm" + os.sep + "_common.py",
28
+ ]
29
+
30
+
31
+ def test_target_offload_ban():
32
+ """This test blocks the use of target_offload in
33
+ in sklearnex files. Offloading computation to devices
34
+ via target_offload should only occur externally, and not
35
+ within the architecture of the sklearnex classes. This
36
+ is for clarity, traceability and maintainability.
37
+ """
38
+ from sklearnex import __file__ as loc
39
+
40
+ path = loc.replace("__init__.py", "")
41
+ files = [y for x in os.walk(path) for y in glob(os.path.join(x[0], "*.py"))]
42
+
43
+ output = []
44
+
45
+ for f in files:
46
+ if open(f, "r").read().find("target_offload") != -1:
47
+ output += [f.replace(path, "sklearnex" + os.sep)]
48
+
49
+ # remove this file from the list
50
+ for allowed in ALLOWED_LOCATIONS:
51
+ output = [i for i in output if allowed not in i]
52
+
53
+ output = "\n".join(output)
54
+ assert output == "", f"sklearn versioning is occuring in: \n{output}"