-
-
Notifications
You must be signed in to change notification settings - Fork 787
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
add cupyx.scipy.stats.entropy #4369
Conversation
Let me know if the basic tests in |
pfnCI, test this please. |
Thanks for this PR! Yes, we'd like to have |
Would you change the submodule name |
Also nice to have |
self.base, self.axis, self.normalize) | ||
|
||
@testing.numpy_cupy_allclose(atol=1e-3, rtol=5e-3, scipy_name='scp') | ||
def test_entropy_float16(self, xp, scp): |
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.
Now testing.numpy_cupy_allclose
accepts per-dtype tolerance #4269. Would you try that?
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.
That looks like a nice feature, but I have problems with it in this case. I removing the float16
test case and using a rtol dictionary on the other one like:
@testing.numpy_cupy_allclose(rtol={cupy.float16: 1e-3,
cupy.float32: 1e-6,
'default': 1e-12},
scipy_name='scp')
However the cupyx.scipy.special
functions used are in float32 and float64 only, so float16 input -> float32 output and tol=1e-6 will get used. This indicates that I should probably upcast to float32 earlier in the function so that the normalization computations using cupy.sum()
are of equivalent accuracy.
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.
Also, the input with a larger size axis of (128,) does not pass at 1e-12 for double precision. This might be due to lower accuracy in sum
in CuPy vs. NumPy (in some cases, numpy uses some fancier pairwise summation to reduce accumulated errors in sums)
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.
Okay. I also checked that scipy.stats.entropy
returns float32 value for float16 input.
I also noticed that I have |
cast input to at least float32
Jenkins CI test (for commit f7836e7, target branch master) succeeded! |
pfnCI, test this please. |
Jenkins CI test (for commit cec146d, target branch master) succeeded! |
tests/cupyx_tests/scipy_tests/stats_tests/test_distributions.py
Outdated
Show resolved
Hide resolved
remove unused numpy import
e902b02
to
322906d
Compare
pfnCI, test this please. |
LGTM! Waiting for CI pass. |
Jenkins CI test (for commit 6608b60, target branch master) succeeded! |
Thanks! |
This PR adds the
scipy.stats
function,entropy
. This implementation relies on the already existingcupyx.scipy.special.entr
andcupyx.scipy.special.rel_entr
functions and so should be simple to review.There is not currently a
cupyx.scipy.stats
module, so this PR has added it. However, I do not currently have plans to implement other functions within thestats
module. This function is used within a scikit-image function we created a CUDA equivalent for incupyimg
. If there is not an interest in having stats functions within CuPy itself, we can just keep this implementation there.Benchmark with pk input only
Benchmark with pk and qk inputs
benchmark script
import numpy
import scipy.stats
import cupy
import cupyx.scipy.stats
from cupyx.time import repeat
print("## Benchmark with pk input only")
print("shape | GPU time (ms) | CPU time (ms) | acceleration")
print("------|---------------|---------------|-------------")
for shape in [(256,), (512, 512), (2048, 4096), (192, 192, 192)]:
pg = cupy.testing.shaped_random(shape, dtype=numpy.float32)
perf_gpu = repeat(cupyx.scipy.stats.entropy, (pg,), n_warmup=20, n_repeat=100)
gpu_times = perf_gpu.gpu_times * 1000
print("## Benchmark with pk and qk inputs")
print("shape | GPU time (ms) | CPU time (ms) | acceleration")
print("------|---------------|---------------|-------------")
for shape in [(256,), (512, 512), (2048, 4096), (192, 192, 192)]:
pg = cupy.testing.shaped_random(shape, dtype=numpy.float32)
qg = cupy.testing.shaped_random(shape, dtype=numpy.float32)
perf_gpu = repeat(cupyx.scipy.stats.entropy, (pg, qg), n_warmup=20, n_repeat=100)
gpu_times = perf_gpu.gpu_times * 1000