Skip to content

Commit 3c05eeb

Browse files
author
KulikovNikita
authored
Fix for devices that does not support fp64 (#1198)
1 parent c43c1ab commit 3c05eeb

File tree

12 files changed

+125
-92
lines changed

12 files changed

+125
-92
lines changed

onedal/datatypes/_data_conversion.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,19 @@
1414
# limitations under the License.
1515
# ===============================================================================
1616

17+
import warnings
1718
from onedal import _backend
1819
from daal4py.sklearn._utils import make2d
1920

2021

21-
def from_table(*args):
22+
def _apply_and_pass(func, *args):
2223
if len(args) == 1:
23-
return _backend.from_table(args[0])
24-
return (_backend.from_table(item) for item in args)
24+
return func(args[0])
25+
return tuple(map(func, args))
26+
27+
28+
def from_table(*args):
29+
return _apply_and_pass(_backend.from_table, *args)
2530

2631

2732
def convert_one_to_table(arg):
@@ -30,9 +35,7 @@ def convert_one_to_table(arg):
3035

3136

3237
def to_table(*args):
33-
if len(args) == 1:
34-
return convert_one_to_table(args[0])
35-
return (convert_one_to_table(item) for item in args)
38+
return _apply_and_pass(convert_one_to_table, *args)
3639

3740

3841
from onedal import _is_dpc_backend
@@ -42,33 +45,34 @@ def to_table(*args):
4245

4346
from ..common._policy import _HostInteropPolicy
4447

45-
def _convert_to_supported_impl(policy, *data):
48+
def _convert_to_supported(policy, *data):
49+
def func(x):
50+
return x
51+
4652
# CPUs support FP64 by default
4753
if isinstance(policy, _HostInteropPolicy):
48-
return data
54+
return _apply_and_pass(func, *data)
4955

5056
# It can be either SPMD or DPCPP policy
5157
device = policy._queue.sycl_device
5258

5359
def convert_or_pass(x):
54-
if x.dtype is np.float64:
60+
if x.dtype == np.float64:
61+
warnings.warn("Data will be converted into float32 from "
62+
"float64 because device does not support it",
63+
RuntimeWarning, )
5564
return x.astype(np.float32)
5665
else:
5766
return x
5867

5968
if not device.has_aspect_fp64:
60-
return (convert_or_pass(x) for x in data)
61-
else:
62-
return data
63-
else:
64-
def _convert_to_supported_impl(policy, *data):
65-
return data
69+
func = convert_or_pass
6670

71+
return _apply_and_pass(func, *data)
6772

68-
def _convert_to_supported(policy, *data):
69-
res = _convert_to_supported_impl(policy, *data)
73+
else:
74+
def _convert_to_supported(policy, *data):
75+
def func(x):
76+
return x
7077

71-
if len(data) == 1:
72-
return res[0]
73-
else:
74-
return res
78+
return _apply_and_pass(func, *data)

onedal/datatypes/data_conversion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ inline dal::homogen_table convert_to_homogen_impl(PyArrayObject *np_data) {
6161
if (array_numdims(np_data) > 2) {
6262
throw std::runtime_error("Input array has wrong dimensionality (must be 2d).");
6363
}
64-
T *data_pointer = reinterpret_cast<T *>(array_data(np_data));
64+
T* const data_pointer = reinterpret_cast<T* const>(array_data(np_data));
6565
// TODO: check safe cast from int to std::int64_t
6666
const std::int64_t row_count = static_cast<std::int64_t>(array_size(np_data, 0));
6767
if (array_numdims(np_data) == 2) {

onedal/datatypes/numpy_helpers.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,20 @@
6363

6464
#define SET_NPY_FEATURE(_T, _FUNCT, _EXCEPTION) \
6565
switch (_T) { \
66-
case NPY_DOUBLE: \
67-
case NPY_CDOUBLE: \
68-
case NPY_DOUBLELTR: \
69-
case NPY_CDOUBLELTR: { \
70-
_FUNCT(double); \
71-
break; \
72-
} \
7366
case NPY_FLOAT: \
7467
case NPY_CFLOAT: \
7568
case NPY_FLOATLTR: \
7669
case NPY_CFLOATLTR: { \
7770
_FUNCT(float); \
7871
break; \
7972
} \
73+
case NPY_DOUBLE: \
74+
case NPY_CDOUBLE: \
75+
case NPY_DOUBLELTR: \
76+
case NPY_CDOUBLELTR: { \
77+
_FUNCT(double); \
78+
break; \
79+
} \
8080
case NPY_INT32: { \
8181
_FUNCT(std::int32_t); \
8282
break; \

onedal/decomposition/pca.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
# limitations under the License.
1515
#===============================================================================
1616

17+
import numpy as np
18+
1719
from onedal import _backend
1820
from ..common._policy import _get_policy
19-
from ..datatypes._data_conversion import from_table, to_table
21+
from ..datatypes._data_conversion import from_table, to_table, _convert_to_supported
2022
from daal4py.sklearn._utils import sklearn_check_version
2123

22-
import numpy as np
23-
2424

2525
class PCA():
2626
def __init__(
@@ -37,7 +37,7 @@ def __init__(
3737
def get_onedal_params(self, data):
3838
return {
3939
'fptype':
40-
'float' if data.dtype is np.dtype('float32') else 'double',
40+
'float' if data.dtype == np.float32 else 'double',
4141
'method': self.method,
4242
'n_components': self.n_components,
4343
'is_deterministic': self.is_deterministic
@@ -48,6 +48,8 @@ def fit(self, X, y, queue):
4848
n_sf_min = min(n_samples, n_features)
4949

5050
policy = _get_policy(queue, X, y)
51+
52+
X, y = _convert_to_supported(policy, X, y)
5153
params = self.get_onedal_params(X)
5254
cov_result = _backend.covariance.compute(
5355
policy,
@@ -97,8 +99,10 @@ def _create_model(self):
9799

98100
def predict(self, X, queue):
99101
policy = _get_policy(queue, X)
100-
params = self.get_onedal_params(X)
101102
model = self._create_model()
103+
104+
X = _convert_to_supported(policy, X)
105+
params = self.get_onedal_params(X)
102106
result = _backend.decomposition.dim_reduction.infer(policy,
103107
params,
104108
model,

onedal/ensemble/forest.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
_check_X_y,
4141
_check_array,
4242
_column_or_1d,
43-
_check_n_features
43+
_check_n_features,
44+
_convert_to_supported
4445
)
4546

4647
from ..common._mixin import ClassifierMixin, RegressorMixin
@@ -204,7 +205,7 @@ def _get_onedal_params(self, data):
204205
self.min_samples_split * n_samples)))
205206

206207
onedal_params = {
207-
'fptype': 'float' if data.dtype is np.dtype('float32') else 'double',
208+
'fptype': 'float' if data.dtype == np.float32 else 'double',
208209
'method': self.algorithm,
209210
'infer_mode': self.infer_mode,
210211
'voting_mode': self.voting_mode,
@@ -350,6 +351,8 @@ def _fit(self, X, y, sample_weight, module, queue):
350351
if not sklearn_check_version('1.0'):
351352
self.n_features_ = self.n_features_in_
352353
policy = self._get_policy(queue, X, y, sample_weight)
354+
355+
X, y, sample_weight = _convert_to_supported(policy, X, y, sample_weight)
353356
params = self._get_onedal_params(X)
354357
train_result = module.train(
355358
policy, params, *to_table(X, y, sample_weight))
@@ -380,9 +383,10 @@ def _predict(self, X, module, queue):
380383
force_all_finite=True, accept_sparse=False)
381384
_check_n_features(self, X, False)
382385
policy = self._get_policy(queue, X)
383-
params = self._get_onedal_params(X)
384386

385387
model = self._onedal_model
388+
X = _convert_to_supported(policy, X)
389+
params = self._get_onedal_params(X)
386390
result = module.infer(policy, params, model, to_table(X))
387391
y = from_table(result.responses)
388392
return y
@@ -393,6 +397,7 @@ def _predict_proba(self, X, module, queue):
393397
force_all_finite=True, accept_sparse=False)
394398
_check_n_features(self, X, False)
395399
policy = self._get_policy(queue, X)
400+
X = _convert_to_supported(policy, X)
396401
params = self._get_onedal_params(X)
397402
params['infer_mode'] = 'class_probabilities'
398403

onedal/linear_model/linear_model.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def _get_policy(self, queue, *data):
4949
def _get_onedal_params(self, dtype=np.float32):
5050
intercept = 'intercept|' if self.fit_intercept else ''
5151
return {
52-
'fptype': 'float' if dtype is np.float32 else 'double',
52+
'fptype': 'float' if dtype == np.float32 else 'double',
5353
'method': self.algorithm, 'intercept': self.fit_intercept,
5454
'result_option': (intercept + 'coefficients'),
5555
}
@@ -63,20 +63,19 @@ def _fit(self, X, y, module, queue):
6363

6464
dtype = get_dtype(X_loc)
6565
if dtype not in [np.float32, np.float64]:
66-
X_loc = X_loc.astype(np.float64, copy=self.copy_X)
6766
dtype = np.float64
67+
X_loc = X_loc.astype(dtype, copy=self.copy_X)
6868

6969
y_loc = np.asarray(y_loc).astype(dtype=dtype)
7070

7171
# Finiteness is checked in the sklearnex wrapper
7272
X_loc, y_loc = _check_X_y(
7373
X_loc, y_loc, force_all_finite=False, accept_2d_y=True)
7474

75-
params = self._get_onedal_params(dtype)
76-
7775
self.n_features_in_ = _num_features(X_loc, fallback_1d=True)
7876

7977
X_loc, y_loc = _convert_to_supported(policy, X_loc, y_loc)
78+
params = self._get_onedal_params(get_dtype(X_loc))
8079
X_table, y_table = to_table(X_loc, y_loc)
8180

8281
result = module.train(policy, params, X_table, y_table)
@@ -92,7 +91,7 @@ def _fit(self, X, y, module, queue):
9291

9392
return self
9493

95-
def _create_model(self, module):
94+
def _create_model(self, module, policy):
9695
m = module.model()
9796

9897
coefficients = self.coef_
@@ -137,6 +136,8 @@ def _create_model(self, module):
137136
if self.fit_intercept:
138137
packed_coefficients[:, 0][:, np.newaxis] = intercept
139138

139+
packed_coefficients = _convert_to_supported(policy, packed_coefficients)
140+
140141
m.packed_coefficients = to_table(packed_coefficients)
141142

142143
self._onedal_model = m
@@ -158,15 +159,14 @@ def _predict(self, X, module, queue):
158159
force_all_finite=False, ensure_2d=False)
159160
_check_n_features(self, X_loc, False)
160161

161-
params = self._get_onedal_params(X_loc)
162-
163162
if hasattr(self, '_onedal_model'):
164163
model = self._onedal_model
165164
else:
166-
model = self._create_model(module)
165+
model = self._create_model(module, policy)
167166

168167
X_loc = make2d(X_loc)
169168
X_loc = _convert_to_supported(policy, X_loc)
169+
params = self._get_onedal_params(get_dtype(X_loc))
170170

171171
X_table = to_table(X_loc)
172172
result = module.infer(policy, params, model, X_table)

0 commit comments

Comments
 (0)