diff --git a/configs/BENCH-CONFIG-SPEC.md b/configs/BENCH-CONFIG-SPEC.md index c34f4743..26bff24f 100644 --- a/configs/BENCH-CONFIG-SPEC.md +++ b/configs/BENCH-CONFIG-SPEC.md @@ -98,7 +98,7 @@ Configs have the three highest parameter keys: | `data`:`distributed_split` | None | None, `rank_based` | Split type used to distribute data between machines in distributed algorithm. `None` type means usage of all data without split on all machines. `rank_based` type splits the data equally between machines with split sequence based on rank id from MPI. | |

Algorithm parameters

|||| | `algorithm`:`library` | None | | Python module containing measured entity (class or function). | -| `algorithm`:`device` | `default` | `default`, `cpu`, `gpu` | Device selected for computation. | +| `algorithm`:`device` | `default` | `default`, `cpu`, `gpu` | Device selected for computation. `sklearnex`+`gpu` cases enable sklearn's `array_api_dispatch` and use `dpnp` data by default (see `sklearn_context` below). | ## Benchmark-Specific Parameters @@ -109,7 +109,7 @@ Configs have the three highest parameter keys: | `algorithm`:`estimator` | None | | Name of measured estimator. | | `algorithm`:`estimator_params` | Empty `dict` | | Parameters for estimator constructor. | | `algorithm`:`batch_size`:`{stage}` | None | Any positive integer | Enables online mode for `{stage}` methods of estimator (sequential calls for each batch). | -| `algorithm`:`sklearn_context` | None | | Parameters for sklearn `config_context` used over estimator. | +| `algorithm`:`sklearn_context` | None | | Parameters for sklearn `config_context` used over estimator. `array_api_dispatch` requires `SCIPY_ARRAY_API=1`, which scikit-learn_bench sets by default if it is unset in the environment. | | `algorithm`:`sklearnex_context` | None | | Parameters for sklearnex `config_context` used over estimator. Updated by `sklearn_context` if set. | | `bench`:`ensure_sklearnex_patching` | True | | If True, warns about sklearnex patching failures. | diff --git a/configs/common/sklearn.json b/configs/common/sklearn.json index 6b988ba7..bae07393 100644 --- a/configs/common/sklearn.json +++ b/configs/common/sklearn.json @@ -6,12 +6,18 @@ { "library": "sklearnex", "device": "cpu" } ] }, - "sklearn-ex[cpu,gpu] implementations": { - "algorithm": [ - { "library": "sklearn", "device": "cpu" }, - { "library": "sklearnex", "device": ["cpu", "gpu"] } - ] - }, + "sklearn-ex[cpu,gpu] implementations": [ + { "algorithm": { "library": "sklearn", "device": "cpu" } }, + { "algorithm": { "library": "sklearnex", "device": "cpu" } }, + { + "algorithm": { + "library": "sklearnex", + "device": "gpu", + "sklearn_context": { "array_api_dispatch": true } + }, + "data": { "format": "dpnp", "order": "C" } + } + ], "sklearnex spmd implementation": { "algorithm": { "library": "sklearnex.spmd", diff --git a/sklbench/benchmarks/sklearn_estimator.py b/sklbench/benchmarks/sklearn_estimator.py index 5b3032ea..8c511ce3 100644 --- a/sklbench/benchmarks/sklearn_estimator.py +++ b/sklbench/benchmarks/sklearn_estimator.py @@ -22,6 +22,9 @@ from importlib.metadata import PackageNotFoundError, version from typing import Dict, List, Union +# sklbench uses array API by default; must precede scipy import to take effect +os.environ.setdefault("SCIPY_ARRAY_API", "1") + import numpy as np import pandas as pd from sklearn.base import BaseEstimator diff --git a/sklbench/datasets/transformer.py b/sklbench/datasets/transformer.py index 1efc31e6..52473317 100644 --- a/sklbench/datasets/transformer.py +++ b/sklbench/datasets/transformer.py @@ -26,7 +26,9 @@ from ..utils.logger import logger -def convert_data(data, dformat: str, order: str, dtype: str, device: str = None): +def convert_data( + data, dformat: str, order: str, dtype: str, device: str = None, sycl_queue=None +): if isinstance(data, csr_matrix) and dformat != "csr_matrix": data = data.toarray() if dtype == "preserve": @@ -46,6 +48,11 @@ def convert_data(data, dformat: str, order: str, dtype: str, device: str = None) elif dformat == "dpnp": import dpnp + # Pin every subset to one shared queue: sklearnex builds its internal + # arrays (e.g. the take() indices in KNN predict) on the device's default + # queue, and array_api_dispatch requires all arrays share one queue object. + if sycl_queue is not None: + return dpnp.asarray(data, dtype=dtype, order=order, sycl_queue=sycl_queue) return dpnp.array(data, dtype=dtype, order=order, device=device) elif dformat == "dpctl": warnings.warn( @@ -143,6 +150,14 @@ def split_and_transform_data(bench_case, data, data_description): device = get_bench_case_value(bench_case, "algorithm:device", None) common_data_format = get_bench_case_value(bench_case, "data:format", "pandas") + + # Resolve one queue for the device up front so all dpnp subsets share it; + # dpnp.array(device=...) per subset can otherwise land on distinct queues. + sycl_queue = None + if common_data_format == "dpnp" and device is not None: + import dpnp + + sycl_queue = dpnp.array([], device=device).sycl_queue common_data_order = get_bench_case_value(bench_case, "data:order", "F") common_data_dtype = get_bench_case_value(bench_case, "data:dtype", "float32") @@ -177,7 +192,7 @@ def split_and_transform_data(bench_case, data, data_description): data_dtype = required_label_dtype converted_data = convert_data( - subset_content, data_format, data_order, data_dtype, device + subset_content, data_format, data_order, data_dtype, device, sycl_queue ) data_dict[subset_name] = converted_data if not is_label: