-
-
Notifications
You must be signed in to change notification settings - Fork 25.8k
TST Add minimal setup to be able to run test suite on float32 #22690
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
Co-authored-by: Thomas J. Fan <thomasjpfan@gmail.com>
To avoid merging dead code could you please use it in at least one test and set the environment variable on one of the CI builds (a fast one preferably)? |
Yes, this is still in draft and I am figuring which tests I am going to include here based on the discussions in other pull requests. |
I am just adding a test for this global fixture. |
Co-authored-by: Thomas J. Fan <thomasjpfan@gmail.com>
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 start to use this fixture extensively, this will generate a lot of skipped tests by default which will render the output very verbose. At some point we might want to avoid the skip mark and instead do:
GLOBAL_DTYPES_TO_TEST = [np.float64]
if environ.get("SKLEARN_TESTS_RUN_FLOAT32", "0") != "1":
print("Enabling float32 tests globally.")
GLOBAL_DTYPES_TO_TEST.append(np.float32)
else:
print("Skipping float32 tests globally. Set SKLEARN_TESTS_RUN_FLOAT32=1 to enable.")
@pytest.fixture(params=GLOBAL_DTYPES_TO_TEST)
def global_dtype(request):
yield request.param
but I think we can keep it this way for now. +1 for merging as is.
I have an idea to reuse a similar pattern to define a |
Co-authored-by: Olivier Grisel <olivier.grisel@ensta.org>
@thomasjpfan let's merge? |
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.
Codewise this looks good. Can we document the variable along with the other ones here?
scikit-learn/doc/computing/parallelism.rst
Lines 203 to 207 in 05ef752
:SKLEARN_ENABLE_DEBUG_CYTHON_DIRECTIVES: | |
When this environment variable is set to a non zero value, the `Cython` | |
derivative, `boundscheck` is set to `True`. This is useful for finding | |
segfaults. |
(A future PR can be to move some of these environment variables out of doc/computing/parallelism.rst
and into doc/developers/contributing.rst
.)
So as to have a similar name to `SKLEARN_SKIP_NETWORK_TESTS`. Co-authored-by: Thomas J. Fan <thomasjpfan@gmail.com>
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 fixture is not enough on its own
In the tests, we usually end up checking that 2 values are close to each other. "close" depends on the dtype. The default rtol of There's the same concern about atol. in assert_allclose, atol essentially means a value below atol is considered to be equal to zero. In some tests where we want to test some values against 0, rtol is irrelevant and we need to set atol. Although let's 1e-10 could be considered a 0 in float64, it's way too small for float32. We need the dtype to come with an associated rtol and atol. The fixture should be something like
The rtol should then be used in all calls to assert_allclose, unless exception for which a comment should then explain why use a different rtol. |
In PyTorch, they set their own tolerances based on dtype: https://github.com/pytorch/pytorch/blob/1f29b3130af218847a043e58fdc64511bbe072fe/torch/testing/_comparison.py#L43-L51 (They use For our use case, we can have a custom "assert_allclose" that sets the |
I'd be happy with a custom |
+1 as well for a custom |
I also think having custom assertions (e.g Currently, assertions in tests are imported from In this regards, I think that it would be better to import assertions from What do you think? |
Co-authored-by: Olivier Grisel <olivier.grisel@ensta.org>
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.
Looking at what we have to do to implement our custom assert_allclose and the fact that we won't have a dtype dependent atol, I wonder if it wouldn't be simpler to make the fixture being "global_dtype, rtol, atol"
?
I suppose the deletion of |
I do not understand. We need a fixture to enable or disable the float32 tests to avoid doubling the test duration by default no? We would only run the float32 variant on a few fast CI entries to sparse the slow runners that already take more than 25 min to complete. Then if those dtype-parametrized tests use our |
Co-authored-by: Jérémie du Boisberranger <jeremiedbb@users.noreply.github.com>
nevermind, I thought more about that and I think the custom assert all_close is better. |
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.
Could you please add a test in sklearn.utils.tests.test_testing.py
that checks the behavior of the scikit-learn specific assert_allclose
variation?
def test_float32_aware_assert_allclose():
# The relative tolerance for float32 inputs is 1e-4
assert_allclose(np.array([1. + 2e-5], dtype=np.float32), 1.)
with pytest.raises(AssertionError):
assert_allclose(np.array([1. + 2e-4], dtype=np.float32), 1.)
# The relative tolerance for other inputs is left to 1e-7 as in
# the original numpy version.
assert_allclose(np.array([1. + 2e-8], dtype=np.float64), 1.)
with pytest.raises(AssertionError):
assert_allclose(np.array([1. + 2e-7], dtype=np.float64), 1.)
# atol is left to 0.0 by default, even for float32
with pytest.raises(AssertionError):
assert_allclose(np.array([1. + 1e-5], dtype=np.float32), 0.)
assert_allclose(np.array([1. + 1e-5], dtype=np.float32), 0., atol=2e-5)
if I am not mistaken (I have not tested).
No need to test the rest of the behavior of assert_allclose
that is already tested in the numpy test suite.
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 also need a bit of doc to explain what is the difference between rtol and atol, what are their meaning and when to set atol. Not sure where to put that. Maybe in contributing.rst
?
Co-authored-by: Jérémie du Boisberranger <jeremiedbb@users.noreply.github.com> Co-authored-by: Olivier Grisel <olivier.grisel@ensta.org>
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. Just a last remark from my side.
Co-authored-by: Jérémie du Boisberranger <jeremiedbb@users.noreply.github.com>
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.
Final round of nitpicks but other than that LGTM!
Thanks @jjerphan ! |
I made myself suffer for nothing on this one. 😄 |
…-learn#22690) Co-authored-by: Thomas J. Fan <thomasjpfan@gmail.com> Co-authored-by: Olivier Grisel <olivier.grisel@ensta.org> Co-authored-by: Jérémie du Boisberranger <jeremiedbb@users.noreply.github.com>
Reference Issues/PRs
Solves #22680.
What does this implement/fix? Explain your changes.
Based on @thomasjpfan's #22663 (comment), this implements a minimal setup to run the test suite on a
dtype
parameter using a minimal parametrisation.Any other comments?