Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Raise if fit and predict use different array API namespaces or devices (continued) - #33076

Merged
betatim merged 55 commits into
scikit-learn:mainfrom
betatim:check-fitted-same-namespace-device
Mar 25, 2026
Merged

Raise if fit and predict use different array API namespaces or devices (continued)#33076
betatim merged 55 commits into
scikit-learn:mainfrom
betatim:check-fitted-same-namespace-device

Conversation

@betatim

@betatim betatim commented Jan 14, 2026

Copy link
Copy Markdown
Member

Reference Issues/PRs

Continuation of #29313

What does this implement/fix? Explain your changes.

This PR adds _array_api.check_same_namespace to raise an error if the array namespace used during fit and predict/transform do not match, and _array_api.convert_estimator to move the array attributes of an estimator to the namespace and device of a reference array. Eventually we should put convert_estimator in a public part of the API, because users should use it. For now I think it is Ok to have it in sklearn.utils._array_api as things are still experimental.

A change I've made compared to #29313 is that none of our library code turns on sklearn.set_config(array_api_dispatch=True) for its run (original version in #29313). I think this makes sense because users should opt-in themselves. But it does open up the question of what exactly should happen if you use convert_estimator on an estimator without turning on array API support in scikit-learn. My thinking is there should be an exception to let people know they are doing something weird.

>>> from sklearn.linear_model import Ridge
>>> import sklearn
>>> import torch
>>> from sklearn import datasets

>>> sklearn.set_config(array_api_dispatch=True)

>>> X, y = datasets.make_regression()
>>> X_torch = torch.asarray(X, device='cpu')
>>> y_torch = torch.asarray(y, device='cpu')
>>> ridge = Ridge().fit(X_torch, y_torch)
>>> type(ridge.predict(X_torch))
<class 'torch.Tensor'>
>>> ridge.predict(X)
Traceback (most recent call last):
    ...
ValueError: Inputs passed to Ridge.predict() must use the same array library and the same device as those passed to fit(). Array namespaces used during fit (sklearn.externals.array_api_compat.torch) and predict (sklearn.externals.array_api_compat.numpy) differ. You can convert the estimator to the same library and device as X with: 'from sklearn.utils._array_api import convert_estimator; estimator = convert_estimator(estimator, X)'
>>> from sklearn.utils._array_api import convert_estimator
>>> ridge = convert_estimator(ridge, X)
>>> type(ridge.predict(X))
<class 'numpy.ndarray'>
>>> ridge = convert_estimator(ridge, X_torch)
>>> type(ridge.predict(X_torch))
<class 'torch.Tensor'>

AI usage disclosure

There were quite a few merge conflicts which Cursor managed to resolve and it managed to figure out how to change from the old "what's new" system to the new one once I explained that there is a README to read.

I used AI assistance for:

  • Code generation (e.g., when writing an implementation or fixing a bug)
  • Test/benchmark generation
  • Documentation (including examples)
  • Research and understanding

@ogrisel

ogrisel commented Mar 20, 2026

Copy link
Copy Markdown
Member

I pushed my merge conflict resolution commit without running the tests locally. Sorry for that. I am on it.

@ogrisel ogrisel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (if CI is green after my pass few commits).

yield partial(
check_array_api_same_namespace,
array_namespace="array_api_strict",
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good to only test with array_api_strict for this to keep time cost bounded. There is no reason for this to depend on the kind of namespace.

Comment thread sklearn/utils/tests/test_estimator_checks.py
run: |
source "${HOME}/conda/etc/profile.d/conda.sh"
conda activate sklearn
cd doc

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason, this is necessary, because otherwise it would try to import from the unbuilt sklearn source folder.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't fully understand it either, in build_tools/github/test_docs.sh we also use this "one weird trick they don't want you to know"

Comment thread sklearn/utils/estimator_checks.py
@ogrisel

ogrisel commented Mar 20, 2026

Copy link
Copy Markdown
Member

@OmarManzoor @virchan merge?

@OmarManzoor OmarManzoor left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thank you @betatim

Comment thread sklearn/utils/tests/test_array_api.py Outdated
Co-authored-by: Omar Salman <[email protected]>
@betatim

betatim commented Mar 25, 2026

Copy link
Copy Markdown
Member Author

Thanks for the reviews, I turned on automerge

@betatim
betatim enabled auto-merge (squash) March 25, 2026 14:12
@betatim
betatim merged commit c50ac77 into scikit-learn:main Mar 25, 2026
36 checks passed
@github-project-automation github-project-automation Bot moved this from In progress to Done in Labs Mar 25, 2026
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Array API Mar 25, 2026
@betatim
betatim deleted the check-fitted-same-namespace-device branch March 25, 2026 15:54
Comment on lines +523 to +524
# XXX Do we need this? What else could the custom logic do that wouldn't work
# with the default logic?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@betatim just checking, is this comment meant to remain? Is this questioning the need for the line self.converted_ = True ?

Not sure how realistic but would a e.g., NamedTuple attribute work? Since we do: estimator_type in (list, tuple, set, frozenset)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't planning on leaving it in, but only if we resolved the question.

What it is asking is "what is a somewhat realistic thing the custom array API conversion logic could do?" For now it just sets some arbitrary estimator fitted attribute, but that seems totally "weird"/we wouldn't see this in the real world.

So the comment is more about my lack of imagination than anything else.

Given it has now been merged I'd leave it until we can come up with a better example.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thanks for explaining.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

7 participants