Module project.esn.updater

Expand source code
from pprint import pprint as p

import numpy as np
import project.esn.matrix as m
from project.esn import utils as u


def apply_leak(state, update, leaking_rate=0.3):
    """Simple leaking formula which returns the new state from the next
state and the previous one scaling both by the leaking rate and
1-leaking rate

    """
    return (update * leaking_rate) + (state * (1 - leaking_rate))


@u.mydataclass(repr=True, init=True, check=False)
class Updator():
    """Updator data class This class manage the update process and all
    the weights involved in it It also store the last state in other
    to use it in the next update
    """


    _next: callable = None
    """ The update function used to calculate the next state """

    weights: m.Esn_matrixs = None
    """The class which wraps all the matrixs involved in the ESN"""

    state: np.ndarray = None
    """The current state of the network (it will be updated at each
iteration)"""

    squeeze_f: callable = np.tanh
    """The squeezing function applied to the result of the the _next
function"""

    squeeze_o: callable = lambda x: x
    """The squeezing function applied to the result of the output
function"""

    leaking_rate: float = 0.3
    """The leaking rate used to calculate the _next state"""

    noise: float = 0.0
    """The noise which is added to the result of the _next function"""

    def __post_init__(self):
        """Enrich the specified _next function. It adds the noise and squeeze
the final output after calling the _next function"""
        self._next = u.comp(self.squeeze_f, lambda x: x + self.noise,
                            self._next)

    def __call__(self, other):
        """calculate the next state from a tuple(other) which is composed by
the input and possibly an output

        """
        next_state = self._next(self.weights, self.state, other)
        self.state = apply_leak(self.state, next_state, self.leaking_rate)
        return self.state

    def __lshift__(self, other):
        """reflect the __call__ function

        """
        return self.__call__(other)

    def __rshift__(self, other):
        """calculate the output of the network given an input (other)"""
        return default_output(self.weights.W_out, self.state, other,
                              self.squeeze_o)


def def_updator(fun):
    """Decorator which define a new updater
    """
    def inner(*args, **kwargs):
        return Updator(fun, *args, **kwargs)
    return inner



@def_updator
@u.pre_proc_args({
    "state":
    u.force_2dim,
    "tuple":
    lambda tuple: (u.force_2dim(tuple[0]), u.force_2dim(tuple[1]))
})
def vanilla_updator(weights: m.Esn_matrixs, state, tuple):
    """This calculate the next state using the standard update formula
    \(1+1 \)

    """
    (input, _) = tuple
    return weights.W_in.dot(input) + weights.W_res.dot(state)


@def_updator
@u.pre_proc_args({
    "state":
    u.force_2dim,
    "tuple":
    lambda tuple: (u.force_2dim(tuple[0]), u.force_2dim(tuple[1]))
})
def feedback_updator(weights: m.Esn_matrixs, state, tuple):
    """This function calculate the next state given an input and an output
using the enhanced formula

    """
    (input, output) = tuple
    return ((weights.W_in * input) + (weights.W_res * state) +
            (weights.W_feb * output))


@u.pre_proc_args({"input": u.force_2dim, "state": u.force_2dim})
def default_output(W_out, state, input, output_f=lambda x: x):
    """calculate the output using the standard formula

    """
    z_n = m.build_extended_states(input.T, state.T).T
    return output_f(W_out.dot(z_n)).reshape(-1)

Functions

def apply_leak(state, update, leaking_rate=0.3)

Simple leaking formula which returns the new state from the next state and the previous one scaling both by the leaking rate and 1-leaking rate

Expand source code
def apply_leak(state, update, leaking_rate=0.3):
    """Simple leaking formula which returns the new state from the next
state and the previous one scaling both by the leaking rate and
1-leaking rate

    """
    return (update * leaking_rate) + (state * (1 - leaking_rate))
def def_updator(fun)

Decorator which define a new updater

Expand source code
def def_updator(fun):
    """Decorator which define a new updater
    """
    def inner(*args, **kwargs):
        return Updator(fun, *args, **kwargs)
    return inner
def default_output(W_out, state, input, output_f=<function <lambda>>)

calculate the output using the standard formula

Expand source code
@u.pre_proc_args({"input": u.force_2dim, "state": u.force_2dim})
def default_output(W_out, state, input, output_f=lambda x: x):
    """calculate the output using the standard formula

    """
    z_n = m.build_extended_states(input.T, state.T).T
    return output_f(W_out.dot(z_n)).reshape(-1)
def feedback_updator(*args, **kwargs)
Expand source code
def inner(*args, **kwargs):
    return Updator(fun, *args, **kwargs)
def vanilla_updator(*args, **kwargs)
Expand source code
def inner(*args, **kwargs):
    return Updator(fun, *args, **kwargs)

Classes

class Updator (weights: Esn_matrixs = None, state: numpy.ndarray = None, squeeze_f:  = <ufunc 'tanh'>, squeeze_o:  = <function Updator.<lambda>>, leaking_rate: float = 0.3, noise: float = 0.0)

Updator data class This class manage the update process and all the weights involved in it It also store the last state in other to use it in the next update

Expand source code
class Updator():
    """Updator data class This class manage the update process and all
    the weights involved in it It also store the last state in other
    to use it in the next update
    """


    _next: callable = None
    """ The update function used to calculate the next state """

    weights: m.Esn_matrixs = None
    """The class which wraps all the matrixs involved in the ESN"""

    state: np.ndarray = None
    """The current state of the network (it will be updated at each
iteration)"""

    squeeze_f: callable = np.tanh
    """The squeezing function applied to the result of the the _next
function"""

    squeeze_o: callable = lambda x: x
    """The squeezing function applied to the result of the output
function"""

    leaking_rate: float = 0.3
    """The leaking rate used to calculate the _next state"""

    noise: float = 0.0
    """The noise which is added to the result of the _next function"""

    def __post_init__(self):
        """Enrich the specified _next function. It adds the noise and squeeze
the final output after calling the _next function"""
        self._next = u.comp(self.squeeze_f, lambda x: x + self.noise,
                            self._next)

    def __call__(self, other):
        """calculate the next state from a tuple(other) which is composed by
the input and possibly an output

        """
        next_state = self._next(self.weights, self.state, other)
        self.state = apply_leak(self.state, next_state, self.leaking_rate)
        return self.state

    def __lshift__(self, other):
        """reflect the __call__ function

        """
        return self.__call__(other)

    def __rshift__(self, other):
        """calculate the output of the network given an input (other)"""
        return default_output(self.weights.W_out, self.state, other,
                              self.squeeze_o)

Class variables

var leaking_rate : float

The leaking rate used to calculate the _next state

var noise : float

The noise which is added to the result of the _next function

var squeeze_f : 

The squeezing function applied to the result of the the _next function

var state : numpy.ndarray

The current state of the network (it will be updated at each iteration)

var weights : Esn_matrixs

The class which wraps all the matrixs involved in the ESN

Methods

def squeeze_o(x) ‑> 
Expand source code
squeeze_o: callable = lambda x: x