-
-
Notifications
You must be signed in to change notification settings - Fork 25.8k
TST Improve assert_argkmin_results_quasi_equality
error message
#27281
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
TST Improve assert_argkmin_results_quasi_equality
error message
#27281
Conversation
Signed-off-by: Julien Jerphanion <git@jjerphan.xyz> Co-authored-by: Olivier Grisel <olivier.grisel@ensta.org>
test_pairwise_distances_argkmin
Feel free to adapt this PR at will. |
I ran one of the failing tests of #27126 locally using:
the error message was:
but I also wanted to see the distances and the matching indices arrays, so I used the debugger:
The distances for the last neighbor are indeed very close and the difference happens at the 8th digits which might be expected for float32 rounding errors. Using pdb I went up in the stack to compare the distances in the reference distance matrix computed by cdist:
so those are indeed close. Let's have a look at the next neighbors in the reference cdist matrix:
so 88 and 16 are indeed the closest candidate for rank k=10 according to cdist. So we should probably find a way to tolerate those cases where the Cython code returns neighbors swaps within the range of rounding errors of the chosen dtype. |
The CI has failed because of the way I formatted the commit message. Let me push another empty commit with the right message structure. |
@jjerphan the last commit message makes it possible to reproduce all the failures with the extra info of this PR. I suppose we should simplify the code of
This should be probably more robust while being both strict enough and easier to debug in case of failure. WDYT? |
We could do that yes. I think the current yet complex assertion checks that the ordering between both algorithms is identical (up to a bucketing for acceptable numerical imprecision of float32). Is there a way we could check that with what you propose? If I understand your first item correctly, it does not propose to assert that but only the correct ordering of the index w.r.t their distances, is this right? |
Yes but since the computed distances for each neighbor should match the reference computed distance within round-off errors and furthermore that there should not exist any significantly closer neighbor based on the reference distances, the approximate ordering should also be satisfied as a result. |
Let me try to give it a shot. |
@jjerphan I pushed two commits to implement what I had in mind with even stronger tests for the assertion function. This also fixes some xfail edge cases (at least on my machine). I decided to focus this PR to the argkmin tests for now but we could do a follow-up PR to do a similar treatment for the radius neighbors tests and further simplify this test file. Once the last commit CI is green, I will push a new empty commit with message |
The code coverage report reveals that the tests for the checker could be improved. I will do that tomorrow. In the mean time let me push the all random seed commit. |
d4161f7
to
04f7bdd
Compare
…ults_quasi_equality
…ive message with even stronger tests and a fix
… missing neighbor detection
@jjerphan finally this PR is ready for reviewing. It should reduce the average CI time quite significantly (see the CI reports of the second to last commit). |
Thanks! I do not really have time to review it now, but I trust you. (I find that having me approve this PR is a bit weird since I opened it but I, in fact, have not contributed to it much but you.) |
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 have not reviewed it entirely, but I am trusting you for coming up with better assertions than mine.
LGTM for the sake of a faster CI and better error messages.
(I can't approve this PR, but I could if you reopen a PR with this branch.)
Let's wait for you to get a but of time to have a quick look, at least on the updated tests and their messages. If the test cases and the messages make sense to you, then this should be good.
You can just say so in a comment :) |
def test_assert_argkmin_results_quasi_equality(): | ||
rtol = 1e-7 | ||
eps = 1e-7 | ||
def test_assert_compatible_argkmin_results(): |
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.
In my opinion, this is the main entry point for the review.
rtol = 1e-7 | ||
eps = 1e-7 | ||
@pytest.mark.parametrize("check_sorted", [True, False]) | ||
def test_assert_compatible_radius_results(check_sorted): |
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.
And this is a second entry point point to 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.
✔️ LGTM. Thank you, @ogrisel.
Here are some comments which need not be treated and a question.
Edit: I would not block this PR if this fixes errors on the CI which have been there for too long.
Co-authored-by: Julien Jerphanion <git@jjerphan.xyz>
…ults_quasi_equality
…ults_quasi_equality
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.
Only nitpicks. I am fine with the new tests.
indices_row_a, | ||
indices_row_b, | ||
threshold, | ||
): |
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.
It would also be nice to have a docstring if the code below is already explicit.
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.
Done in 7fb4261.
|
||
for neighbor_rank in range(n_neighbors): | ||
rounded_dist = relative_rounding( | ||
ref_dist_row[neighbor_rank], | ||
n_significant_digits=n_significant_digits, | ||
) | ||
reference_neighbors_groups[rounded_dist].add(ref_indices_row[neighbor_rank]) | ||
effective_neighbors_groups[rounded_dist].add(indices_row[neighbor_rank]) | ||
|
||
# Asserting equality of groups (sets) for each distance | ||
msg = ( | ||
f"Neighbors indices for query {query_idx} are not matching " | ||
f"when rounding distances at {n_significant_digits} significant digits " | ||
f"derived from rtol={rtol:.1e}" | ||
# Check that any neighbor with distances below the rounding error threshold have | ||
# matching indices. | ||
threshold = (1 - rtol) * np.maximum( | ||
np.max(dist_row_a), np.max(dist_row_b) |
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 needed to scratch my head here. rtol
is a bit different from the other usage. I don't know if this is siginificant enough to be mentioned (having the docstring in the assert_no_missing_neighbors
will help already.)
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 hope that 7fb4261 helps.
# checking the results is expensive for large result sets), yielding 0 most | ||
# of the time would make the test useless. | ||
if precomputed_dists is None and metric is None: | ||
raise ValueError("Either metric or dists must be provided") |
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.
Apparently this is not covered.
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.
_non_trivial_radius
is a test helper function. It's not meant to be used in the library so I think it's fine (in particular it is not accounted in the test coverage report). This exception is just there to help maintainers use it correctly if they refactor the tests again in the future.
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.
In that case, can it be:
assert (
precomputed_dists is not None or metric is not None
), "Either metric or dists must be provided"
Co-authored-by: Guillaume Lemaitre <g.lemaitre58@gmail.com>
…ults_quasi_equality
Thanks for the review @glemaitre. |
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.
Green tick for #27281 (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.
It looks good on my side.
…ikit-learn#27281) Co-authored-by: Olivier Grisel <olivier.grisel@ensta.org> Co-authored-by: Guillaume Lemaitre <g.lemaitre58@gmail.com>
…ikit-learn#27281) Co-authored-by: Olivier Grisel <olivier.grisel@ensta.org> Co-authored-by: Guillaume Lemaitre <g.lemaitre58@gmail.com>
Reference Issues/PRs
Fixes #27126.
Towards #25888.
Updated scope of this PR
This changes the way we check neighbor results, notably for
test_pairwise_distances_argkmin
with float32 so that:Furthermore, the tests parameterization has been updated to make it faster to run all the tests with all the seeds while still exploring various problem sizes.