Skip to content

[WIP] Fix ZeroDivisionWarning in Matern Kernel #7385

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

Closed
wants to merge 5 commits into from

Conversation

MechCoder
Copy link
Member

@MechCoder MechCoder commented Sep 10, 2016

Reference Issue

Fixes what @amueller thought was the issue in #5664,
though that's not really the issue [edited by @amueller so that the issue remains open after this fix is merged]

What does this implement/fix? Explain your changes.

The previous code had got around the case where the distance equals zero by setting the gradient to zero after finding where it becomes infinite that raises a ZeroDivisionWarning. This is another solution using masked arrays in NumPy. I am unable to reproduce any other warning on master with the latest versions of NumPy and SciPy


This change is Reviewable

@MechCoder MechCoder added this to the 0.18 milestone Sep 10, 2016
K_gradient[~np.isfinite(K_gradient)] = 0
dist = np.ma.masked_array(np.sqrt(D.sum(2))[:, :, np.newaxis])
K_gradient = K[..., np.newaxis] * D / dist
K_gradient = K_gradient.filled(0)
Copy link
Member

Choose a reason for hiding this comment

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

K_gradient remains a masked_array afterwards?

Copy link
Member Author

Choose a reason for hiding this comment

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

@ogrisel
Copy link
Member

ogrisel commented Sep 10, 2016

Can you please add a non regression test with assert_no_warnings?

@MechCoder
Copy link
Member Author

done. hope that was sufficient.

@@ -317,4 +317,4 @@ def test_repr_kernels():

def test_no_warnings_matern_eval_gradient():
mat = Matern(length_scale=[0.5, 2.0], nu=0.5)
assert_no_warnings(mat, X, eval_gradient=True)
Copy link
Member

Choose a reason for hiding this comment

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

You don't need to pass __call__. The original line was already correct.

@MechCoder
Copy link
Member Author

Sorry about pushing directly. I was not able to reproduce the failure by doing nosetests-3.4 sklearn/gaussian_process/tests/test_kernels.py or nosetests-3.4 sklearn/gaussian_process/tests, but I can reproduce while doing nosetests-3.4 sklearn/. Just running nosetests-3.4 sklearn/ seesms to raise plenty of other warnings in test_kernels.py though. Trying to investigate.

@MechCoder MechCoder changed the title [MRG] Fix ZeroDivisionWarning in Matern Kernel [WIP] Fix ZeroDivisionWarning in Matern Kernel Sep 11, 2016
@MechCoder
Copy link
Member Author

I was facing some issues in using masked arrays with regards to the warnings. I removed the masked arrays logic and replaced it with a less elegant (but working) solution using initialization of K_gradient with zeros.

These are the following issues that I faced during the usage of masked arrays.

  1. In older versions of NumPy doing this, raised a warning. (reported here False warning for masked arrays: RuntimeWarning: divide by zero encountered in divide numpy/numpy#4269).
1 / np.ma.masked_equal([1, 0], 0)

It is necessary to do this in those cases. np.ma.masked_array([1]) / np.ma.masked_equal([1, 0], 0)

  1. Also, seems to be affected by this issue over here (Masked array mean reports spurious floating point error (underflow) numpy/numpy#4895) while multiplying K_gradient and D.

I also feel it is necessary to use a.__call__ explicitly to raise a more meaning full error message here (https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/utils/testing.py#L285) since instances have no __name__ attribute.

@agramfort
Copy link
Member

LGTM

K_gradient = K[..., np.newaxis] * D \
/ np.sqrt(D.sum(2))[:, :, np.newaxis]
K_gradient[~np.isfinite(K_gradient)] = 0
K_gradient = np.zeros_like(D)
Copy link
Member

@amueller amueller Sep 12, 2016

Choose a reason for hiding this comment

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

Is this faster or slower than the previous solution? Alternatively we could just catch the warning, because we expect it and treat it, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I don't like the solution that I wrote, but I wasn't sure if using the with warnings.catch_warnings(): warnings.simplefilter block was encouraged.

Copy link
Member

@amueller amueller Sep 12, 2016

Choose a reason for hiding this comment

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

You should catch only the ZeroDivisionError. It is expected and then treated, so it's ok to catch it (imho)

Copy link
Member

Choose a reason for hiding this comment

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

Ah. it's RuntimeWarning?

@amueller
Copy link
Member

we use np.seterr in dict_learning. I think this is probably the best pattern?
No idea how that might interfere with parallel processing?

@amueller amueller modified the milestones: 0.18, 0.19 Sep 22, 2016
@jnothman
Copy link
Member

This is marked WIP and has a LGTM. What's the story, @MechCoder? Do we want this in 0.20?

@MechCoder
Copy link
Member Author

MechCoder commented Jun 14, 2017 via email

@jnothman jnothman removed this from the 0.19 milestone Feb 28, 2019
Base automatically changed from master to main January 22, 2021 10:49
@jeremiedbb
Copy link
Member

The fix was done in #24245. This PR can be closed.

@jeremiedbb jeremiedbb closed this Feb 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants