-
-
Notifications
You must be signed in to change notification settings - Fork 25.8k
[MRG] MNT Api only mode in check_estimator #18582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At some point, I think we need to have docstrings for at least the API-only checks, so we can include it in the docs. This way there is a human readable description of "what is the API".
'check_n_features_in', | ||
# set of checks that do not check API-compatibility. They are ignored when | ||
# api_only is True. | ||
_NON_API_CHECKS = set([ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should hard code the complement of this set, _API_CHECKS
so it is easier to tell "what is the API".
In the docs, we can point to _API_CHECKS
to be "what the API is".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we can immediately do that, because there are 3 kinds of checks, not 2:
- the ones that don't check the API at all (in this dict)
- the ones that only check the API
- the ones that check the API in some parts, and do some other kinds of checks in other parts.
1 and 2 don't use the api_only
parameter. The checks in 3 are the only ones to use it (we agreed in previous PRs that this was the easiest way to go).
separating 2 and 3 would be a lot of work, probably worth it I agree, but out of scope here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
separating 2 and 3 would be a lot of work, probably worth it I agree, but out of scope here.
I see defining the API mainly about communication. Having 3 makes it harder to communicate what the API is.
I guess as a first step, we can add this api_only=True
, and state "Your estimator is API compliant if you pass check_estimator(..., api_only=True)
". In a future PR, we can separate 2 and 3 and then we can firmly say "These are the checks that test the API".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Merging this PR isn't the end of the road, it's only the beginning.
Which is why I think we should keep things as simple as possible here, and improve incrementally in the future.
Totally agree, the checks need much better docs. Most of them were completely undocumented. In this PR I tried to document them at least a little bit to ease the review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this redefinition of "strict". I wonder whether I would have designed it as mode="compatible"
vs mode="strict"
. This is looking good to me, but I've not had time to review in full that the implementation matches the designation of what is "API only".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @NicolasHug
Haven't gone through all the tests yet. But I guess I'd include quite a few more tests in API tests than what we have now. And there are a bunch of tests which have api_only=False
defaults, but also have if not api_only
sections, not sure if that makes sense.
# When api_only is True, check_fit2d_1sample is skipped along | ||
# with the rest of the xfail_checks | ||
with pytest.warns(SkipTestWarning, match=skip_match): | ||
check_estimator(NuSVC(), api_only=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we're calling this with api_only=True
, then why is there a need to ignore a check_fit2d_1sample is not an API check
warning?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I don't understand the question. We're not ignoring a warning here, we're making sure it's raised.
The SkipTestWarning is raised by check_fit2d_1sample because it is a non-API check and we have set api_only=True. There are other warnings that are raised by check_estimator
, we just assert that at least this one is raised.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I mean here is, as a user, if I call check_estimator(..., api_only=True)
, I'm explicitly saying I only want the api_only
tests. Then why would I get a warning which says check_fit2d_1sample is not an API check
? Should I just not be getting that warning?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're treating these checks as if they were in the _xfail_checks
tag and for this tag we decided to ignore with a warning. It makes things much simpler to re-use that logic rather than implement a new check-ignoring logic (I believe there are discussions in previous PRs like #17361)
I personally don't have a strong opinion on whether the ignored checks should raise a warning or not. Note that for parametrize_with_checks
, which is sort of the sister of check_estimators
, those checks would be marked as XFAIL, so pytest would still output them in stdout saying something like "this was xfailed" or "this was xpassed".
Maybe @rth @thomasjpfan can remind us why we decided to ignore with a warning instead of just ignoring?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is better to raise a skip warning. It allows us to know which tests were not run and for which reason.
# this case, check_fit_non_negative() will not check the exact error | ||
# messsage. (We still assert that the warning from | ||
# check_fit2d_1sample is raised) | ||
with pytest.warns(SkipTestWarning, match=skip_match): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same question here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same answer ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @adrinjalali for the review, I replied in the comments.
I'd include quite a few more tests in API tests than what we have now
I believe most of these already are API checks. Any check that isn't in the NON_API_CHECKS
will (at least partially) check the API. The value of the api_only
param determines which parts of these checks are part of the API. Some checks are actually full API checks, in which case api_only
isn't even used.
And there are a bunch of tests which have api_only=False defaults, but also have if not api_only sections, not sure if that makes sense
We want the default api_only=False to be False because we want the check to be strict by default. All checks need to have this default (whether they use it or not) so that calls to checks (with partials, etc.) don't get too complicated. The value of the default is not an indiation of whether the check is part of the API checks or not. I agree this is not completely ideal but this is the solution we went for, after quite a lot of alternatives (#17361 (review)). We also need to think about backward compatibility here.
In general the whole check suite could use a big re-design. Even the "name" parameters mostly don't make sense and are usually not used. I'd love to see that happen, but that's not in scope here.
# When api_only is True, check_fit2d_1sample is skipped along | ||
# with the rest of the xfail_checks | ||
with pytest.warns(SkipTestWarning, match=skip_match): | ||
check_estimator(NuSVC(), api_only=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I don't understand the question. We're not ignoring a warning here, we're making sure it's raised.
The SkipTestWarning is raised by check_fit2d_1sample because it is a non-API check and we have set api_only=True. There are other warnings that are raised by check_estimator
, we just assert that at least this one is raised.
# this case, check_fit_non_negative() will not check the exact error | ||
# messsage. (We still assert that the warning from | ||
# check_fit2d_1sample is raised) | ||
with pytest.warns(SkipTestWarning, match=skip_match): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same answer ;)
The split between API/non-API seems OK with me. I think that we should split the test into these 2 groups later on. It would allow having nicer documentation that we can expose publicly as well as pointed out by @thomasjpfan |
I am wondering if it would not be a good solution. This might allow grouping in more fine-grained the test maybe. |
@@ -816,7 +816,7 @@ def check_estimator_sparse_data(name, estimator_orig, strict_mode=True): | |||
|
|||
|
|||
@ignore_warnings(category=FutureWarning) | |||
def check_sample_weights_pandas_series(name, estimator_orig, strict_mode=True): | |||
def check_sample_weights_pandas_series(name, estimator_orig, api_only=False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My latest comment regarding several mode
would be nice here. One mode would be the interoperability of array-like.
One might want to be API and array-like compliant while not be strict on the error message raised. In this case maybe mode
is not a good name but I have in mind something like model=["api", "interoperability"]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I am fine with the change. I would maybe prefer to introduce a list of str instead of single keyword thought. WDYT @NicolasHug ?
Co-authored-by: Guillaume Lemaitre <g.lemaitre58@gmail.com>
The No strong opinion, but I'm not sure having lots of check levels is something we want to get into. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am fine with this step forward.
I just tested the approach in LightGBM. Once microsoft/LightGBM#3533 is merged (changes that were required after announcing some deprecation in 0.23), the api_only is working. I will try to do the same in xgboost. |
Did we announced in 0.22 or 0.23? |
Maybe also hdbscan and UMAP? |
we announce in 0.23 for changing in 0.24 |
I tested |
Uhm, this is weird regarding the estimator tag. We have a default tag so
probably the test will be run in this case. If they break, I would say that
this is fine. It forces the use of tags to bypass the test then.
…On Mon, 9 Nov 2020 at 14:43, Jérémie du Boisberranger < ***@***.***> wrote:
I tested check_estimator on cuml estimators and all fail because they
don't have estimator tags (they do not even inherit from BaseEstimator).
I wonder if having estimator tags is mandatory to be a compatible
estimator. Do you think check_estimator could somehow work on estimators
without tags, maybe by assuming default tags in this case (seems brittle
though...) ?
—
You are receiving this because you were assigned.
Reply to this email directly, view it on GitHub
<#18582 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABY32PYQDMMX4KWV67OQMD3SO7WWZANCNFSM4SKHRKWA>
.
--
Guillaume Lemaitre
Scikit-learn @ Inria Foundation
https://glemaitre.github.io/
|
(please edit if I missed anything) We just had a meeting with @glemaitre @ogrisel @jeremiedbb @amueller @adrinjalali @thomasjpfan With the approaching release and the potential for a cleaner/more modular implementation (#18750), we decided on the following (among other things):
|
Closes #13969
Towards #16241
This PR introduces the possibility to only run API-compatibility checks in
check_estimator
andparametrize_with_checks
, as discussed in the previous monthly meeting. This is a follow-up to #17361, though I had to renamestrict_mode=True
intoapi_only=False
.I had to make a bunch of decisions on what we consider to be an API check. In general, my line of thought was:
__init__
,set/get_params()
, attributes etcHowever I don't feel strongly about any of these, so please feel free to directly push to this PR if you disagree ;)
CC @jnothman @rth @thomasjpfan @ogrisel @adrinjalali @glemaitre