FIX: accuracy and zero_loss support for multilabel with Array API#29336
FIX: accuracy and zero_loss support for multilabel with Array API#29336betatim merged 15 commits intoscikit-learn:mainfrom
accuracy and zero_loss support for multilabel with Array API#29336Conversation
| if _is_numpy_namespace(xp): | ||
| # XXX: do we really want to sparse-encode multilabel indicators when | ||
| # they are passed as a dense arrays? This is not possible for array | ||
| # API inputs in general hence we only do it for NumPy inputs. But even | ||
| # for NumPy the usefulness is questionable. |
accuracy and zero_loss with Array APIaccuracy and zero_loss with Array API
accuracy and zero_loss with Array APIaccuracy and zero_loss support for multilabel with Array API
sklearn/metrics/_classification.py
Outdated
| differing_labels = count_nonzero(y_true - y_pred, axis=1) | ||
| else: | ||
| differing_labels = xp.sum( | ||
| xp.astype(xp.astype(y_true - y_pred, xp.bool), xp.int8), |
There was a problem hiding this comment.
Can this be casted to xp.int8 directly?
| xp.astype(xp.astype(y_true - y_pred, xp.bool), xp.int8), | |
| xp.astype(y_true - y_pred, xp.int8), |
There was a problem hiding this comment.
I tried that too, but then it turns into an actual sum of everything that is not 0 (after the subtraction).
I initially just used bool actually, but array_api_scrict was not happy.
I guess an alternative could be xp.where, but I feel if could me even more verbose. What do you think?
There was a problem hiding this comment.
Maybe xp.sum(xp.abs(xp.astype(y_true - y_pred)) would be more explicit instead of relying on casting semantics to turn negative differences into positive counts?
Also I am not sure about the use of xp.int8. If you have more than 127 classes in your target and y_pred never makes a good label prediction for a give data point, then the xp.sum would overflow, no?
There was a problem hiding this comment.
I think we might require sample_weight in the count_nonzero method as well. In the PR I created for f1_score we ignored the multilabel case for the array api integration. f1 score array api PR
If we are now including this I think it might make sense to extract _count_nonzero into a utility function.
There was a problem hiding this comment.
I decide to make a _count_zero function : 6123e64
It doesn't have sample_weight yet (it is not required here, but I can add it)
What do you think about this approach?
There was a problem hiding this comment.
I like it. Thanks for the addition.
|
|
|
@OmarManzoor sounds good! I have some time later today to update this. Feel free to comment with the suggestion if you have something already :) |
OmarManzoor
left a comment
There was a problem hiding this comment.
@EdAbati I have added the suggestions.
Co-authored-by: Omar Salman <omar.salman2007@gmail.com>
Co-authored-by: Omar Salman <omar.salman2007@gmail.com>
Co-authored-by: Omar Salman <omar.salman2007@gmail.com>
Co-authored-by: Omar Salman <omar.salman2007@gmail.com>
Co-authored-by: Omar Salman <omar.salman2007@gmail.com>
Co-authored-by: Omar Salman <omar.salman2007@gmail.com>
OmarManzoor
left a comment
There was a problem hiding this comment.
I think this looks good now. I checked that the cuda tests pass.
|
@ogrisel Could you kindly have another look at this PR with the latest changes? |
ogrisel
left a comment
There was a problem hiding this comment.
Small nits, but otherwise, LGTM.
I launched the CUDA tests here:
sklearn/utils/_array_api.py
Outdated
| if axis == -1: | ||
| axis = 1 | ||
| elif axis == -2: | ||
| axis = 0 |
There was a problem hiding this comment.
I think xp.sum should always support negative axis values, no? If not, then we can simplify / generalize this logic to nd inputs as:
| if axis == -1: | |
| axis = 1 | |
| elif axis == -2: | |
| axis = 0 | |
| if axis < 0: | |
| axis += X.ndim |
Also: if _count_nonzero is only valid on 2d inputs, I think it should be made explicit in the docstring and maybe add an assertions such as:
assert X.ndim == 2at the beginning to avoid accidental mis-use in the code base.
There was a problem hiding this comment.
I think the negative logic was taken directly from the original method that has been defined for sparse arrays.
There was a problem hiding this comment.
Since the original function seems to be defined for 2d inputs,
scikit-learn/sklearn/utils/sparsefuncs.py
Lines 599 to 626 in 2107404
how about updating the docstring and adding the assertion as you suggested?
There was a problem hiding this comment.
yes, I just took this bit from the count_nonzero implementation . I updated now
Oops, I had not seen that before retriggering the CUDA CI... |
|
@ogrisel Does this look good to merge? |
|
Tests pass in https://github.com/scikit-learn/scikit-learn/actions/runs/9756974834/job/26928380940. Merging |
|
Thank you everyone for the review (as always). |
…scikit-learn#29336) Co-authored-by: Omar Salman <omar.salman2007@gmail.com> Co-authored-by: Omar Salman <omar.salman@arbisoft.com>
…scikit-learn#29336) Co-authored-by: Omar Salman <omar.salman2007@gmail.com> Co-authored-by: Omar Salman <omar.salman@arbisoft.com>
Reference Issues/PRs
Related to #29269
Previosly implemented in #29321, but moved to a separate PR
What does this implement/fix? Explain your changes.
Currently the below Array API tests fail in
main. This fixes the support for multilabel inaccuracyandzero_loss.Any other comments?
cc @Tialo @ogrisel