Skip to content
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

ENH: uarray support for scipy.signal #101

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

Smit-create
Copy link

@Smit-create Smit-create commented Dec 16, 2021

Reference issue: scipy#14353

Reference PR from which I followed the implementation: scipy#14356

cc @rgommers

@rgommers
Copy link
Owner

@Smit-create there are a lot of commits in this PR that don't belong here. My master branch is up-to-date with upstream master right now. Can you rebase to get rid of the commits that are unrelated to uarray for scipy.signal?

@AnirudhDagar maybe you'd be able to do a first review on this PR? It's still small - Uarray support for a single function right now.

@Smit-create I'll be travelling for the next couple of days, so I don't think I'll be able to look at this before Thursday.

@Smit-create
Copy link
Author

Can you rebase to get rid of the commits that are unrelated to uarray for scipy.signal?

Done!

I'll be travelling for the next couple of days, so I don't think I'll be able to look at this before Thursday.

Okay, till then I will have a look at some sample code in colab for verifying this PR.

@Smit-create
Copy link
Author

@AnirudhDagar Once you review it in your free time let me know if I can proceed over this or I need to add something more.

@Smit-create
Copy link
Author

I have created a sample cusignal_backend for testing in colab.

Copy link

@AnirudhDagar AnirudhDagar left a comment

Choose a reason for hiding this comment

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

Thanks @Smit-create for your PR. This is already looking like a great start!

I have a few thoughts that might help once you add more functions. Given the number of scipy.signal submodules and the different signatures they have, you will probably need to adapt the argument replacers accordingly and define a few more than just the _h_x_replacer (similar to ndimage). That said, this can get a bit out of hand and testing becomes slightly tedious if we don't use __ua_convert__. It's great that you have created a cusignal backend for testing (that's how I started testing ndimage in cupy as well) but we should also focus on SciPy CI (we can't add cusignal backends there), so, until we actually use __ua_convert__ within the SciPy backend, the mock backend tests on their own don't really mean much in terms of testing the scipy.signal api. With __ua_convert__ we can leverage the scipy.signal test suite already in place. This is discussed in scipy#14356, as the overhead is not too much for __ua_convert__. Maybe we should incorporate it here as well once you start adding more functions.

On a different note, about documentation of functions (I'm assuming you have left that out intentionally given the PR is still WIP).
scipy/signal/__init__.py will need some documentation on those uarray backend control functions (See this example). Although on a second thought I'm not sure if it is a good idea to duplicate the documentation for these functions and in fact defining these functions again for each and every module that supports uarray since the functions still remain the same. It is still important to add some documentation explaining to the users that the signal module is uarray supported and then maybe we document all these 4 common functions under the uarray.rst doc page? What do you think @Smit-create? I remember @czgdp1807 brought this up some time ago.

I'm yet to test the cusignal backend that you shared but I made a cursory look, seems good to me and you can probably go ahead adding more methods. :)

scipy/signal/_multimethods.py Outdated Show resolved Hide resolved
Comment on lines 28 to 61
def _backend_from_arg(backend):
if isinstance(backend, str):
try:
backend = _named_backends[backend]
except KeyError as e:
raise ValueError('Unknown backend {}'.format(backend)) from e

if backend.__ua_domain__ != 'numpy.scipy.signal':
raise ValueError('Backend does not implement "numpy.scipy.singal"')

return backend


def set_global_backend(backend, coerce=False, only=False, try_last=False):
backend = _backend_from_arg(backend)
ua.set_global_backend(backend, coerce=coerce, only=only, try_last=try_last)


def register_backend(backend):
backend = _backend_from_arg(backend)
ua.register_backend(backend)


def set_backend(backend, coerce=False, only=False):
backend = _backend_from_arg(backend)
return ua.set_backend(backend, coerce=coerce, only=only)


def skip_backend(backend):
backend = _backend_from_arg(backend)
return ua.skip_backend(backend)


set_global_backend('scipy', try_last=True)

Choose a reason for hiding this comment

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

Not sure fully, but these functions might get repeated across modules. We can factor out the common parts later though (dealing with concrete things is better than doing abstract thinking way before things get less hazy).

Choose a reason for hiding this comment

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

Yes, I feel the same way. I remember you mentioned that in scipy#14407 and I guess this comment explains my thoughts on the approach since we still need different documentation.

Choose a reason for hiding this comment

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

Maybe once all the uarray PRs land (possibly starting with scipy#14356), we can work on refactoring the common parts into a signal place which can then be used in all the modules.

Choose a reason for hiding this comment

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

in those functions which can also be addressed through some utility doc functions or we can completely drop module-specific examples and make these functions generalized.

I see. Well may be we can keep the module specific parts (like Examples section) in a common place. I don't see any harm in doing that. Like give examples from 2-3 modules in doc-string of common function (say set_backend).

Choose a reason for hiding this comment

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

we can work on refactoring the common parts into a signal place which can then be used in all the modules.

Yes, that would be way more easier than thinking of possible cases now. We don't know how things might end up in distant future.

Copy link
Author

Choose a reason for hiding this comment

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

Maybe once all the uarray PRs land (possibly starting with scipy#14356), we can work on refactoring the common parts into a signal place which can then be used in all the modules.

+1, refactoring seems an easy option later as we will be more clear which all share common behaviour.

@czgdp1807
Copy link

I remember @czgdp1807 brought this up some time ago.

Are you talking about this function for duplicating docs? Is there any major drawback of duplicating the docs from regular SciPy functions to multimethods? Well, I think it's redundant and introduces a slight overhead (copy pasting doc strings from one variable to another, though no objective data to support this). Other than that I can't think of anything else.

@AnirudhDagar
Copy link

AnirudhDagar commented Dec 23, 2021

Are you talking about this function for duplicating docs?

No not this, although I'm aware this can sit better in some common scipy utils place as well like doccer.py. I was actually talking about the backend control functions (set_global_backend , register_backend,.. ) and their documentation like you mentioned in your comment above.

@Smit-create
Copy link
Author

Thanks for the review @AnirudhDagar and @czgdp1807

probably need to adapt the argument replacers accordingly and define a few more than just the _h_x_replacer

Yes, will do that in further commits.

until we actually use __ua_convert__ within the SciPy backend, the mock backend tests on their own don't really mean much in terms of testing the scipy.signal api. With __ua_convert__ we can leverage the scipy.signal test suite already in place.

Makes sense to me.

It is still important to add some documentation explaining to the users that the signal module is uarray supported and then maybe we document all these 4 common functions under the uarray.rst doc page?

I think once we complete one complete module, we could add some docs that can show how to use the backends (but again should we wait until we add backends/*_backend.py in the modules that support uarray?)

scipy/signal/_backend.py Outdated Show resolved Hide resolved
@Smit-create
Copy link
Author

@rgommers @AnirudhDagar
I created cupy_backend on the other branch and installed it on the colab notebook. It seems to be working fine. Please have a look at the notebook and feel free to provide comments over there too.

@Smit-create
Copy link
Author

There seems to be some issue with all_of_type:

>>> from scipy._lib.uarray import all_of_type
>>> import numpy as np
>>> @all_of_type(np.ndarray)
... def f(p):
...     return p
... 
>>> sos_f32  = np.array([[4., 5., 6., 1., 2., 3.]], dtype=np.float32)
>>> sos_f32
array([[4., 5., 6., 1., 2., 3.]], dtype=float32)
>>> sos_f32.shape
(1, 6)
>>> f(sos_f32)
(<Dispatchable: type=<class 'numpy.ndarray'>, value=array([4., 5., 6., 1., 2., 3.], dtype=float32)>,)
>>> f(sos_f32)[0].value.shape
(6,)

While I was trying to add __ua_convert__, there were many test failures due to changes in the dimensions of numpy arrays. I was expecting sos_f32 and f(sos_f32)[0].value of same dimensions

@rgommers
Copy link
Owner

I think all_of_type doesn't work for multimethod definitions that just return their input - which seems wrong, a 1-element tuple needs to be returned. The for arg in extracted_args in this all_of_type body:

            extracted_args = tuple(func(*args, **kwargs))
            return tuple(
                Dispatchable(arg, arg_type)
                if not isinstance(arg, Dispatchable)
                else arg
                for arg in extracted_args
            )

is assuming extracted_args is a tuple; if it's a single 2-D array then it's going to unpack it into 1-D arrays.

I'm not sure if it's a bug that needs fixing (an assert may be useful), or if the docs need to be updated. Either way, all_of_type isn't tested in uarray, so let's add a few tests and improve the docs. Can you open an issue on the Uarray repo with a reproducer @Smit-create?

This fixes things

@all_of_type(np.ndarray)
def f(p):
    return (p,)

# OR:
def f(p):
    return (Dispatchable(p, np.ndarray),)

@Smit-create
Copy link
Author

With the present commits, __ua_convert__ works fine for the added functions. So, next, I'll look into each function's parameters (optional arguments) which might also need to be dispatched.

Comment on lines +69 to +73
@_create_signal(_input_hrow_hcol_replacer)
@all_of_type(np.ndarray)
@_get_docs
def sepfir2d(input, hrow, hcol):
return input, hrow, hcol

Choose a reason for hiding this comment

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

Can we use a code generator to produce _multimethods.py file? Like a yml file which can contain all the information. We just need to define the replacer methods and these kind of 3-4 liner blocks can be generated dynamically? cc: @grlee77 @rgommers @AnirudhDagar

P.S. It might not be worth it because anyways its the same amount of code in both cases (auto generation and manually writing). But still thought to put this up.

Choose a reason for hiding this comment

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

I know that sounds appealing and probably better engineered (will help with consistency) but I believe there are not many uarray modules and multimethods left to be added now (with the PRs already open) and autogeneration might just make things more complicated (one more thing to be handled).

@Smit-create
Copy link
Author

@rgommers @czgdp1807 @AnirudhDagar This PR now looks good for a first thorough review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants