question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`ScatteringBase1D` kwargs should be passed via `dict`'s

See original GitHub issue

from the ScatteringBase1D frontend to compute_meta_scattering, precompute_size_scattering, and scattering_filter_factory

This dict could be named filterbank_kwargs and eventually also contain the spinned boolean (#807)

This will lead to a reduction in the number of positional arguments in these prototypes. More importantly, it will better decouple hyperparameters from the choice of wavelet shape.

For me to be able to start working on this, i need #833 #842 #848 #850 to be reviewed, rebased, and merged.

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:1
  • Comments:9

github_iconTop GitHub Comments

1reaction
lostanlencommented, Jun 15, 2022

perhaps wavelet function could follow some interface and be callable rather than passing around kwargs.

@cyrusvahidi i’m trying my best (so far with success) not to introduce new object-oriented classes. So a compromise i had in mind would be a two-element tuple with the callable as first element and its kwargs as second elements.

Something like (gauss_1d, {"sigma0": sigma}) or (morlet_1d, {"r_psi": r_psi}).

For a Gammatone, it would become (gammatone_1d, {"r_psi": r_psi, "gammatone_order": 4}) or something like that. The prototype of gammatone_1d would much resemble morlet_1d:

def gammatone_1d(N, xi, sigma, *, r_psi, gammatone_order):

I don’t think it’s necessary to have a new class where that class would basically implement __init__, __call__, and maybe (maybe!) some method T_from_sigma which computes the temporal support as a function of the sigma bandwidth parameter. But we have no such method right now, as we work empirically (compute_temporal_support) on the phi so estimate our min_to_pad. Therefore i don’t believe an OO interface is necessary … yet.

So i see my solution as one step in the journey but not the final destination. In any case this will need to be discussed with @eickenberg, who i know has thought about this for a while now.

1reaction
lostanlencommented, Jun 9, 2022

Update: a more concise version that should work out of the box in v0.3:

def scatnet_generator(J, Q, r_psi, sigma0):
    xi = compute_xi_max(Q)
    sigma = compute_sigma_psi(xi, Q, r=r_psi)
    sigma_min = sigma0 / 2**J

    if sigma <= sigma_min:
        xi = sigma
    else:
        yield xi, sigma
        # High-frequency (constant-Q) region: geometric progression of xi
        while sigma > (sigma_min * math.pow(2, 1 / Q)):
            xi /= math.pow(2, 1 / Q)
            sigma /= math.pow(2, 1 / Q)
            yield xi, sigma

    # Low-frequency (constant-bandwidth) region: arithmetic progression of xi
    for q in range(Q):
        xi -= 1/Q
        yield xi, sigma_min


def scattering_filter_factory(N, Js, Qs, T, generators, filters):
    lowpass, wavelets = filters[0], filters[1:]
    filterbanks = []
    n_resolutions = 1
    for J, Q, generator, wavelet in zip(Js, Qs, generators, wavelets):
        generator_fn, generator_kwargs = generator
        wavelet_fn, wavelet_kwargs = wavelet
        filterbank = []
        max_j = 0
        xi_sigmas = generator_fn(J, Q, **generator_kwargs)
        for n, (xi, sigma) in enumerate(xi_sigmas):
            j = get_max_dyadic_subsampling(xi, sigma, **wavelet_kwargs)
            psi_f = {0: wavelet_fn(N, xi, sigma, **wavelet_kwargs),
                "xi": xi, "sigma": sigma, "j": j, "n": n}
            for k in range(1+n_resolutions):
                psi_f[k] = periodize_filter_fourier(psi_f, n_periods=2**k)
            filterbank.append(psi_f)
            max_j = max(max_j, j)
        n_resolutions = max(n_resolutions, max_j)
        filterbanks.append(filterbank)

    lowpass_fn, lowpass_kwargs = lowpass
    log2_T = math.floor(math.log2(T))
    phi_f = {0: lowpass_fn(N, T, **lowpass_kwargs), "j": log2_T}
    for k in range(1+n_resolutions):
        phi_f[k] = periodize_filter_fourier(phi_f, n_periods=2**k)

    return phi_f, *filterbanks


def create_filters(self):
    sigma0 = 0.1
    r_psi = sqrt(0.5)
    generators = (
        (scatnet_generator, {"r_psi"}),
        (scatnet_generator, {"r_psi"})
    )
    filters = (
        (gauss_1d, {"sigma0": sigma}),
        (morlet_1d, {"r_psi": r_psi}),
        (morlet_1d, {"r_psi": r_psi})
    )
    self.phi_f, self.psi1_f, self.psi2_f = scattering_filter_factory(
        N, J, Q, T, generators, filters)

Note that the last function prepares for a number of features that could happen in v0.4 if we deem it useful:

  • varying Q per order (#854 )
  • varying J per order
  • switching wavelet types
  • varying r_psi per order
  • varying wavelet type per order
  • having more than two orders
  • replacing the scatnet_generator by something else

It also allows to skip filterbank construction in a very concise way:

skip_filters = repeat(lambda *args, **kwargs: None, {})
phi_f, psi1_f, psi2_f = scattering_filter_factory(N, Js, Qs, T, generators, skip_filters)

This idiom is useful for maintaining utils.compute_meta_scattering and utils.precompute_size_scattering. I also believe it will improve our approach to padding

Read more comments on GitHub >

github_iconTop Results From Across the Web

Converting Python dict to kwargs? - Stack Overflow
Here is a complete example showing how to use the ** operator to pass values from a dictionary as keyword ...
Read more >
How to pass a dict when a Python function expects **kwargs
Many Python functions have a ** kwargs parameter — a dict whose keys and values are populated via keyword arguments. But what if...
Read more >
Python args and kwargs: Demystified
When you execute the script above, concatenate() will iterate through the Python kwargs dictionary and concatenate all the values it finds:.
Read more >
A Guide to Args, Kwargs, Packing and Unpacking in Python
Args have been packed into a tuple and kwargs a dictionary. ... They must be passed in the correct order and position.
Read more >
How To Use *args and **kwargs in Python 3 - DigitalOcean
In this tutorial, we will cover the syntax of working with *args and **kwargs as parameters within functions to pass a variable number...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found