Skip to content

Reference

param_scope(*args, **kwargs)

Bases: _HyperParameter

A thread-safe hyperparameter context scope

Examples:

create new param_scope

>>> ps = param_scope(a="a", b="b")           # create from call arguments
>>> ps = param_scope(**{"a": "a", "b": "b"}) # create from a dict

read parameters from param_scope

>>> ps.a() # read parameter
'a'
>>> ps.c("c")  # read parameter with default value if missing
'c'
>>> ps.c | "c" # another way for reading missing parameters
'c'

param_scope as a context scope

>>> with param_scope(**{"a": "a"}) as ps:
...     print(ps.a())
a

read parameter from param_scope in a function

>>> def foo():
...    with param_scope() as ps:
...        return ps.a()
>>> with param_scope(**{"a": "a", "b": "b"}) as ps:
...     foo() # foo should get param_scope using a with statement
'a'

modify parameters in nested scopes

>>> with param_scope.empty(**{'a': 1, 'b': 2}) as ps:
...     _repr_dict(ps.storage().storage())
...     with param_scope(**{'b': 3}) as ps:
...         _repr_dict(ps.storage().storage())
...     with param_scope() as ps:
...         _repr_dict(ps.storage().storage())
[('a', 1), ('b', 2)]
[('a', 1), ('b', 3)]
[('a', 1), ('b', 2)]

use object-style parameter key in param_scope

>>> with param_scope(**{"a.b.c": [1,2]}) as ps:
...     ps.a.b.c()
[1, 2]

access parameter with param_scope

>>> with param_scope(x=1):
...     param_scope.x(2) # read parameter
...     param_scope.y(2) # read a missing parameter with default value
...     param_scope.y | 2
...     param_scope.z = 3
...     param_scope.z | 0
1
2
2
3

convert param_scope to dict:

>>> ps = param_scope.empty(a=1, b=2)
>>> _repr_dict(dict(ps))
[('a', 1), ('b', 2)]
Source code in hyperparameter/api.py
def __init__(self, *args, **kwargs):
    super().__init__()
    self.update(kwargs)
    for line in args:
        if "=" in line:
            k, v = line.split("=", 1)
            self.put(k, v)

__enter__()

enter a param_scope context

Examples:

>>> with param_scope():
...     param_scope.p = "origin"
...     with param_scope(**{"p": "origin"}) as ps:
...         ps.storage().storage()      # outer scope
...         with param_scope() as ps:   # unmodified scope
...             ps.storage().storage()  # inner scope
...         with param_scope(**{"p": "modified"}) as ps: # modified scope
...             ps.storage().storage()  # inner scope with modified params
...         _ = param_scope(**{"p": "modified"}) # not used in with ctx
...         with param_scope() as ps:   # unmodified scope
...             ps.storage().storage()  # inner scope
{'p': 'origin'}
{'p': 'origin'}
{'p': 'modified'}
{'p': 'origin'}
Source code in hyperparameter/api.py
def __enter__(self):
    """enter a `param_scope` context

    Examples
    --------
    >>> with param_scope():
    ...     param_scope.p = "origin"
    ...     with param_scope(**{"p": "origin"}) as ps:
    ...         ps.storage().storage()      # outer scope
    ...         with param_scope() as ps:   # unmodified scope
    ...             ps.storage().storage()  # inner scope
    ...         with param_scope(**{"p": "modified"}) as ps: # modified scope
    ...             ps.storage().storage()  # inner scope with modified params
    ...         _ = param_scope(**{"p": "modified"}) # not used in with ctx
    ...         with param_scope() as ps:   # unmodified scope
    ...             ps.storage().storage()  # inner scope
    {'p': 'origin'}
    {'p': 'origin'}
    {'p': 'modified'}
    {'p': 'origin'}
    """

    self._storage.enter()
    return self

current() staticmethod

get current param_scope

Examples:

>>> with param_scope(a=1) as ps:
...     param_scope.current().a("empty") # read `a` from current `param_scope`
'1'
>>> with param_scope() as ps1:
...     with param_scope(a=1) as ps2:
...         param_scope.current().a = 2  # set parameter `a` = 2
...         param_scope.a("empty")       # read `a` in `ps2`
...     param_scope.a("empty")           # read `a` in `ps1`, where `a` is not set
'2'
'empty'
Source code in hyperparameter/api.py
@staticmethod
def current():
    """get current `param_scope`

    Examples
    --------
    >>> with param_scope(a=1) as ps:
    ...     param_scope.current().a("empty") # read `a` from current `param_scope`
    '1'

    >>> with param_scope() as ps1:
    ...     with param_scope(a=1) as ps2:
    ...         param_scope.current().a = 2  # set parameter `a` = 2
    ...         param_scope.a("empty")       # read `a` in `ps2`
    ...     param_scope.a("empty")           # read `a` in `ps1`, where `a` is not set
    '2'
    'empty'
    """
    retval = param_scope()
    retval._storage = TLSKVStorage.current()
    return retval

empty(*args, **kwargs) staticmethod

create an empty param_scope.

Examples:

>>> with param_scope(a="not empty") as ps: # start a new param_scope `a` = 'not empty'
...     param_scope.a("empty")             # read parameter `a`
...     with param_scope.empty() as ps2:   # parameter `a` is cleared in ps2
...         param_scope.a("empty")         # read parameter `a` = 'empty'
'not empty'
'empty'
Source code in hyperparameter/api.py
@staticmethod
def empty(*args, **kwargs):
    """create an empty `param_scope`.

    Examples
    --------
    >>> with param_scope(a="not empty") as ps: # start a new param_scope `a` = 'not empty'
    ...     param_scope.a("empty")             # read parameter `a`
    ...     with param_scope.empty() as ps2:   # parameter `a` is cleared in ps2
    ...         param_scope.a("empty")         # read parameter `a` = 'empty'
    'not empty'
    'empty'
    """
    retval = param_scope().clear().update(kwargs)
    for line in args:
        if "=" in line:
            k, v = line.split("=", 1)
            retval.put(k, v)
    return retval

init(params=None) staticmethod

init param_scope for a new thread.

Source code in hyperparameter/api.py
@staticmethod
def init(params=None):
    """init param_scope for a new thread."""
    param_scope(**params).__enter__()

auto_param(name_or_func)

Convert keyword arguments into hyperparameters

Examples:

>>> @auto_param
... def foo(a, b=2, c='c', d=None):
...     print(a, b, c, d)
>>> foo(1)
1 2 c None
>>> with param_scope('foo.b=3'):
...     foo(2)
2 3 c None

classes are also supported:

>>> @auto_param
... class foo:
...     def __init__(self, a, b=2, c='c', d=None):
...         print(a, b, c, d)
>>> obj = foo(1)
1 2 c None
>>> with param_scope('foo.b=3'):
...     obj = foo(2)
2 3 c None
>>> @auto_param('myns.foo.params')
... def foo(a, b=2, c='c', d=None):
...     print(a, b, c, d)
>>> foo(1)
1 2 c None
>>> with param_scope('myns.foo.params.b=3'):
...     foo(2)
2 3 c None
>>> with param_scope('myns.foo.params.b=3'):
...     param_scope.myns.foo.params.b = 4
...     foo(2)
2 4 c None
Source code in hyperparameter/api.py
def auto_param(name_or_func):
    """Convert keyword arguments into hyperparameters

    Examples
    --------

    >>> @auto_param
    ... def foo(a, b=2, c='c', d=None):
    ...     print(a, b, c, d)

    >>> foo(1)
    1 2 c None

    >>> with param_scope('foo.b=3'):
    ...     foo(2)
    2 3 c None

    classes are also supported:
    >>> @auto_param
    ... class foo:
    ...     def __init__(self, a, b=2, c='c', d=None):
    ...         print(a, b, c, d)

    >>> obj = foo(1)
    1 2 c None

    >>> with param_scope('foo.b=3'):
    ...     obj = foo(2)
    2 3 c None

    >>> @auto_param('myns.foo.params')
    ... def foo(a, b=2, c='c', d=None):
    ...     print(a, b, c, d)
    >>> foo(1)
    1 2 c None

    >>> with param_scope('myns.foo.params.b=3'):
    ...     foo(2)
    2 3 c None

    >>> with param_scope('myns.foo.params.b=3'):
    ...     param_scope.myns.foo.params.b = 4
    ...     foo(2)
    2 4 c None
    """

    if callable(name_or_func):
        return auto_param(None)(name_or_func)

    if has_rust_backend:

        def hashed_wrapper(func):
            predef_kws = {}

            if name_or_func is None:
                namespace = func.__name__
            else:
                namespace = name_or_func

            signature = inspect.signature(func)
            for k, v in signature.parameters.items():
                if v.default != v.empty:
                    name = "{}.{}".format(namespace, k)
                    predef_kws[k] = xxh64(name)

            @functools.wraps(func)
            def inner(*arg, **kws):
                with param_scope() as hp:
                    for k, v in predef_kws.items():
                        if k not in kws:
                            try:
                                val = hp._storage.get_entry(v)
                                kws[k] = val
                            except ValueError:
                                pass
                    return func(*arg, **kws)

            return inner

        return hashed_wrapper

    def wrapper(func):
        predef_kws = {}
        predef_val = {}

        if name_or_func is None:
            namespace = func.__name__
        else:
            namespace = name_or_func

        signature = inspect.signature(func)
        for k, v in signature.parameters.items():
            if v.default != v.empty:
                name = "{}.{}".format(namespace, k)
                predef_kws[k] = name
                predef_val[name] = v.default

        @functools.wraps(func)
        def inner(*arg, **kws):
            with param_scope() as hp:
                local_params = {}
                for k, v in predef_kws.items():
                    if getattr(hp(), v).get_or_else(None) is not None and k not in kws:
                        kws[k] = getattr(hp(), v).get_or_else(None)
                        local_params[v] = hp.get(v)
                    else:
                        local_params[v] = predef_val[v]
                return func(*arg, **kws)

        return inner

    return wrapper