diff --git a/brainpy/_src/dnn/interoperation_flax.py b/brainpy/_src/dnn/interoperation_flax.py index 09f03ac13..9804ac3bb 100644 --- a/brainpy/_src/dnn/interoperation_flax.py +++ b/brainpy/_src/dnn/interoperation_flax.py @@ -86,7 +86,7 @@ def initialize_carry(self, rng, batch_dims, size=None, init_fn=None): raise NotImplementedError _state_vars = self.model.vars().unique().not_subset(bm.TrainVar) - self.model.reset_state(batch_size=batch_dims) + self.model.reset(batch_size=batch_dims) return [_state_vars.dict(), 0, 0.] def setup(self): diff --git a/brainpy/_src/dyn/projections/align_post.py b/brainpy/_src/dyn/projections/align_post.py index b5679dc7d..9bd280f81 100644 --- a/brainpy/_src/dyn/projections/align_post.py +++ b/brainpy/_src/dyn/projections/align_post.py @@ -141,6 +141,10 @@ def update(self, x): self.refs['syn'].add_current(current) # synapse post current return current + syn = property(lambda self: self.refs['syn']) + out = property(lambda self: self.refs['out']) + post = property(lambda self: self.refs['post']) + class FullProjAlignPostMg(Projection): """Full-chain synaptic projection with the align-post reduction and the automatic synapse merging. @@ -270,6 +274,12 @@ def update(self): self.refs['syn'].add_current(current) # synapse post current return current + syn = property(lambda self: self.refs['syn']) + out = property(lambda self: self.refs['out']) + delay = property(lambda self: self.refs['delay']) + pre = property(lambda self: self.refs['pre']) + post = property(lambda self: self.refs['post']) + class HalfProjAlignPost(Projection): """Defining the half-part of synaptic projection with the align-post reduction. @@ -363,6 +373,8 @@ def update(self, x): self.refs['out'].bind_cond(g) # synapse post current return current + post = property(lambda self: self.refs['post']) + class FullProjAlignPost(Projection): """Full-chain synaptic projection with the align-post reduction. @@ -488,3 +500,8 @@ def update(self): g = self.syn(self.comm(x)) self.refs['out'].bind_cond(g) # synapse post current return g + + delay = property(lambda self: self.refs['delay']) + pre = property(lambda self: self.refs['pre']) + post = property(lambda self: self.refs['post']) + out = property(lambda self: self.refs['out']) diff --git a/brainpy/_src/dyn/projections/align_pre.py b/brainpy/_src/dyn/projections/align_pre.py index 237bc38a3..6e5cd223a 100644 --- a/brainpy/_src/dyn/projections/align_pre.py +++ b/brainpy/_src/dyn/projections/align_pre.py @@ -195,6 +195,12 @@ def update(self, x=None): self.refs['out'].bind_cond(current) return current + pre = property(lambda self: self.refs['pre']) + post = property(lambda self: self.refs['post']) + syn = property(lambda self: self.refs['syn']) + delay = property(lambda self: self.refs['delay']) + out = property(lambda self: self.refs['out']) + class FullProjAlignPreDSMg(Projection): """Full-chain synaptic projection with the align-pre reduction and delay+synapse updating and merging. @@ -326,6 +332,11 @@ def update(self): self.refs['out'].bind_cond(current) return current + pre = property(lambda self: self.refs['pre']) + post = property(lambda self: self.refs['post']) + syn = property(lambda self: self.refs['syn']) + out = property(lambda self: self.refs['out']) + class FullProjAlignPreSD(Projection): """Full-chain synaptic projection with the align-pre reduction and synapse+delay updating. @@ -454,6 +465,12 @@ def update(self, x=None): self.refs['out'].bind_cond(current) return current + pre = property(lambda self: self.refs['pre']) + post = property(lambda self: self.refs['post']) + syn = property(lambda self: self.refs['syn']) + delay = property(lambda self: self.refs['delay']) + out = property(lambda self: self.refs['out']) + class FullProjAlignPreDS(Projection): """Full-chain synaptic projection with the align-pre reduction and delay+synapse updating. @@ -581,3 +598,9 @@ def update(self): g = self.comm(self.syn(spk)) self.refs['out'].bind_cond(g) return g + + pre = property(lambda self: self.refs['pre']) + post = property(lambda self: self.refs['post']) + delay = property(lambda self: self.refs['delay']) + out = property(lambda self: self.refs['out']) + diff --git a/brainpy/_src/dyn/projections/plasticity.py b/brainpy/_src/dyn/projections/plasticity.py index d36074b9c..439b6eb6c 100644 --- a/brainpy/_src/dyn/projections/plasticity.py +++ b/brainpy/_src/dyn/projections/plasticity.py @@ -189,6 +189,12 @@ def __init__( self.A1 = A1 self.A2 = A2 + pre = property(lambda self: self.refs['pre']) + post = property(lambda self: self.refs['post']) + syn = property(lambda self: self.refs['syn']) + delay = property(lambda self: self.refs['delay']) + out = property(lambda self: self.refs['out']) + def update(self): # pre-synaptic spikes pre_spike = self.refs['delay'].at(self.name) # spike diff --git a/brainpy/_src/math/random.py b/brainpy/_src/math/random.py index 19603f94c..d0f74bf23 100644 --- a/brainpy/_src/math/random.py +++ b/brainpy/_src/math/random.py @@ -4,7 +4,7 @@ from collections import namedtuple from functools import partial from operator import index -from typing import Optional, Union +from typing import Optional, Union, Sequence import jax import numpy as np @@ -40,6 +40,8 @@ 'rand_like', 'randint_like', 'randn_like', ] +JAX_RAND_KEY = jax.Array + def _formalize_key(key): if isinstance(key, int): @@ -565,12 +567,16 @@ def split_keys(self, n): # random functions # # ---------------- # - def rand(self, *dn, key=None): + def rand(self, *dn, key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) r = jr.uniform(key, shape=dn, minval=0., maxval=1.) return _return(r) - def randint(self, low, high=None, size=None, dtype=int, key=None): + def randint(self, + low, + high=None, + size: Optional[Union[int, Sequence[int]]] = None, + dtype=int, key: Optional[Union[int, JAX_RAND_KEY]] = None): dtype = get_int() if dtype is None else dtype low = _as_jax_array(low) high = _as_jax_array(high) @@ -588,7 +594,11 @@ def randint(self, low, high=None, size=None, dtype=int, key=None): minval=low, maxval=high, dtype=dtype) return _return(r) - def random_integers(self, low, high=None, size=None, key=None): + def random_integers(self, + low, + high=None, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): low = _as_jax_array(low) high = _as_jax_array(high) low = _check_py_seq(low) @@ -606,29 +616,34 @@ def random_integers(self, low, high=None, size=None, key=None): maxval=high) return _return(r) - def randn(self, *dn, key=None): + def randn(self, *dn, key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) r = jr.normal(key, shape=dn) return _return(r) - def random(self, size=None, key=None): + def random(self, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) r = jr.uniform(key, shape=_size2shape(size), minval=0., maxval=1.) return _return(r) - def random_sample(self, size=None, key=None): + def random_sample(self, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r = self.random(size=size, key=key) return _return(r) - def ranf(self, size=None, key=None): + def ranf(self, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r = self.random(size=size, key=key) return _return(r) - def sample(self, size=None, key=None): + def sample(self, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r = self.random(size=size, key=key) return _return(r) - def choice(self, a, size=None, replace=True, p=None, key=None): + def choice(self, a, size: Optional[Union[int, Sequence[int]]] = None, replace=True, p=None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): a = _as_jax_array(a) p = _as_jax_array(p) a = _check_py_seq(a) @@ -637,21 +652,23 @@ def choice(self, a, size=None, replace=True, p=None, key=None): r = jr.choice(key, a=a, shape=_size2shape(size), replace=replace, p=p) return _return(r) - def permutation(self, x, axis: int = 0, independent: bool = False, key=None): + def permutation(self, x, axis: int = 0, independent: bool = False, key: Optional[Union[int, JAX_RAND_KEY]] = None): x = x.value if isinstance(x, Array) else x x = _check_py_seq(x) key = self.split_key() if key is None else _formalize_key(key) r = jr.permutation(key, x, axis=axis, independent=independent) return _return(r) - def shuffle(self, x, axis=0, key=None): + def shuffle(self, x, axis=0, key: Optional[Union[int, JAX_RAND_KEY]] = None): if not isinstance(x, Array): raise TypeError('This numpy operator needs in-place updating, therefore ' 'inputs should be brainpy Array.') key = self.split_key() if key is None else _formalize_key(key) x.value = jr.permutation(key, x.value, axis=axis) - def beta(self, a, b, size=None, key=None): + def beta(self, a, b, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): a = a.value if isinstance(a, Array) else a b = b.value if isinstance(b, Array) else b a = _check_py_seq(a) @@ -662,7 +679,9 @@ def beta(self, a, b, size=None, key=None): r = jr.beta(key, a=a, b=b, shape=_size2shape(size)) return _return(r) - def exponential(self, scale=None, size=None, key=None): + def exponential(self, scale=None, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): scale = _as_jax_array(scale) scale = _check_py_seq(scale) if size is None: @@ -673,7 +692,9 @@ def exponential(self, scale=None, size=None, key=None): r = r / scale return _return(r) - def gamma(self, shape, scale=None, size=None, key=None): + def gamma(self, shape, scale=None, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): shape = _as_jax_array(shape) scale = _as_jax_array(scale) shape = _check_py_seq(shape) @@ -686,7 +707,9 @@ def gamma(self, shape, scale=None, size=None, key=None): r = r * scale return _return(r) - def gumbel(self, loc=None, scale=None, size=None, key=None): + def gumbel(self, loc=None, scale=None, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): loc = _as_jax_array(loc) scale = _as_jax_array(scale) loc = _check_py_seq(loc) @@ -697,7 +720,9 @@ def gumbel(self, loc=None, scale=None, size=None, key=None): r = _loc_scale(loc, scale, jr.gumbel(key, shape=_size2shape(size))) return _return(r) - def laplace(self, loc=None, scale=None, size=None, key=None): + def laplace(self, loc=None, scale=None, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): loc = _as_jax_array(loc) scale = _as_jax_array(scale) loc = _check_py_seq(loc) @@ -708,7 +733,9 @@ def laplace(self, loc=None, scale=None, size=None, key=None): r = _loc_scale(loc, scale, jr.laplace(key, shape=_size2shape(size))) return _return(r) - def logistic(self, loc=None, scale=None, size=None, key=None): + def logistic(self, loc=None, scale=None, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): loc = _as_jax_array(loc) scale = _as_jax_array(scale) loc = _check_py_seq(loc) @@ -719,7 +746,9 @@ def logistic(self, loc=None, scale=None, size=None, key=None): r = _loc_scale(loc, scale, jr.logistic(key, shape=_size2shape(size))) return _return(r) - def normal(self, loc=None, scale=None, size=None, key=None): + def normal(self, loc=None, scale=None, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): loc = _as_jax_array(loc) scale = _as_jax_array(scale) loc = _check_py_seq(loc) @@ -730,7 +759,9 @@ def normal(self, loc=None, scale=None, size=None, key=None): r = _loc_scale(loc, scale, jr.normal(key, shape=_size2shape(size))) return _return(r) - def pareto(self, a, size=None, key=None): + def pareto(self, a, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): a = _as_jax_array(a) a = _check_py_seq(a) if size is None: @@ -739,7 +770,9 @@ def pareto(self, a, size=None, key=None): r = jr.pareto(key, b=a, shape=_size2shape(size)) return _return(r) - def poisson(self, lam=1.0, size=None, key=None): + def poisson(self, lam=1.0, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): lam = _check_py_seq(_as_jax_array(lam)) if size is None: size = jnp.shape(lam) @@ -747,17 +780,24 @@ def poisson(self, lam=1.0, size=None, key=None): r = jr.poisson(key, lam=lam, shape=_size2shape(size)) return _return(r) - def standard_cauchy(self, size=None, key=None): + def standard_cauchy(self, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) r = jr.cauchy(key, shape=_size2shape(size)) return _return(r) - def standard_exponential(self, size=None, key=None): + def standard_exponential(self, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) r = jr.exponential(key, shape=_size2shape(size)) return _return(r) - def standard_gamma(self, shape, size=None, key=None): + def standard_gamma(self, + shape, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): shape = _as_jax_array(shape) shape = _check_py_seq(shape) if size is None: @@ -766,12 +806,16 @@ def standard_gamma(self, shape, size=None, key=None): r = jr.gamma(key, a=shape, shape=_size2shape(size)) return _return(r) - def standard_normal(self, size=None, key=None): + def standard_normal(self, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) r = jr.normal(key, shape=_size2shape(size)) return _return(r) - def standard_t(self, df, size=None, key=None): + def standard_t(self, df, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): df = _as_jax_array(df) df = _check_py_seq(df) if size is None: @@ -780,7 +824,9 @@ def standard_t(self, df, size=None, key=None): r = jr.t(key, df=df, shape=_size2shape(size)) return _return(r) - def uniform(self, low=0.0, high=1.0, size=None, key=None): + def uniform(self, low=0.0, high=1.0, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): low = _as_jax_array(low) high = _as_jax_array(high) low = _check_py_seq(low) @@ -795,7 +841,14 @@ def __norm_cdf(self, x, sqrt2, dtype): # Computes standard normal cumulative distribution function return (np.asarray(1., dtype) + lax.erf(x / sqrt2)) / np.asarray(2., dtype) - def truncated_normal(self, lower, upper, size=None, loc=0., scale=1., dtype=float, key=None): + def truncated_normal(self, + lower, + upper, + size: Optional[Union[int, Sequence[int]]] = None, + loc=0., + scale=1., + dtype=float, + key: Optional[Union[int, JAX_RAND_KEY]] = None): lower = _check_py_seq(_as_jax_array(lower)) upper = _check_py_seq(_as_jax_array(upper)) loc = _check_py_seq(_as_jax_array(loc)) @@ -828,8 +881,8 @@ def truncated_normal(self, lower, upper, size=None, loc=0., scale=1., dtype=floa # Uniformly fill tensor with values from [l, u], then translate to # [2l-1, 2u-1]. key = self.split_key() if key is None else _formalize_key(key) - out = jr.uniform(key, size, dtype, - minval=lax.nextafter(2 * l - 1, np.array(np.inf, dtype=dtype)), + out = jr.uniform(key, size, dtype, + minval=lax.nextafter(2 * l - 1, np.array(np.inf, dtype=dtype)), maxval=lax.nextafter(2 * u - 1, np.array(-np.inf, dtype=dtype))) # Use inverse cdf transform for normal distribution to get truncated @@ -848,7 +901,8 @@ def truncated_normal(self, lower, upper, size=None, loc=0., scale=1., dtype=floa def _check_p(self, p): raise ValueError(f'Parameter p should be within [0, 1], but we got {p}') - def bernoulli(self, p, size=None, key=None): + def bernoulli(self, p, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): p = _check_py_seq(_as_jax_array(p)) jit_error_checking(jnp.any(jnp.logical_and(p < 0, p > 1)), self._check_p, p) if size is None: @@ -857,7 +911,8 @@ def bernoulli(self, p, size=None, key=None): r = jr.bernoulli(key, p=p, shape=_size2shape(size)) return _return(r) - def lognormal(self, mean=None, sigma=None, size=None, key=None): + def lognormal(self, mean=None, sigma=None, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): mean = _check_py_seq(_as_jax_array(mean)) sigma = _check_py_seq(_as_jax_array(sigma)) if size is None: @@ -869,7 +924,8 @@ def lognormal(self, mean=None, sigma=None, size=None, key=None): samples = jnp.exp(samples) return _return(samples) - def binomial(self, n, p, size=None, key=None): + def binomial(self, n, p, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): n = _check_py_seq(n.value if isinstance(n, Array) else n) p = _check_py_seq(p.value if isinstance(p, Array) else p) jit_error_checking(jnp.any(jnp.logical_and(p < 0, p > 1)), self._check_p, p) @@ -879,7 +935,8 @@ def binomial(self, n, p, size=None, key=None): r = _binomial(key, p, n, shape=_size2shape(size)) return _return(r) - def chisquare(self, df, size=None, key=None): + def chisquare(self, df, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): df = _check_py_seq(_as_jax_array(df)) key = self.split_key() if key is None else _formalize_key(key) if size is None: @@ -893,13 +950,15 @@ def chisquare(self, df, size=None, key=None): dist = dist.sum(axis=0) return _return(dist) - def dirichlet(self, alpha, size=None, key=None): + def dirichlet(self, alpha, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) alpha = _check_py_seq(_as_jax_array(alpha)) r = jr.dirichlet(key, alpha=alpha, shape=_size2shape(size)) return _return(r) - def geometric(self, p, size=None, key=None): + def geometric(self, p, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): p = _as_jax_array(p) p = _check_py_seq(p) if size is None: @@ -912,7 +971,8 @@ def geometric(self, p, size=None, key=None): def _check_p2(self, p): raise ValueError(f'We require `sum(pvals[:-1]) <= 1`. But we got {p}') - def multinomial(self, n, pvals, size=None, key=None): + def multinomial(self, n, pvals, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) n = _check_py_seq(_as_jax_array(n)) pvals = _check_py_seq(_as_jax_array(pvals)) @@ -925,7 +985,8 @@ def multinomial(self, n, pvals, size=None, key=None): r = _multinomial(key, pvals, n, n_max, batch_shape + size) return _return(r) - def multivariate_normal(self, mean, cov, size=None, method: str = 'cholesky', key=None): + def multivariate_normal(self, mean, cov, size: Optional[Union[int, Sequence[int]]] = None, method: str = 'cholesky', + key: Optional[Union[int, JAX_RAND_KEY]] = None): if method not in {'svd', 'eigh', 'cholesky'}: raise ValueError("method must be one of {'svd', 'eigh', 'cholesky'}") mean = _check_py_seq(_as_jax_array(mean)) @@ -958,7 +1019,8 @@ def multivariate_normal(self, mean, cov, size=None, method: str = 'cholesky', ke r = mean + jnp.einsum('...ij,...j->...i', factor, normal_samples) return _return(r) - def rayleigh(self, scale=1.0, size=None, key=None): + def rayleigh(self, scale=1.0, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): scale = _check_py_seq(_as_jax_array(scale)) if size is None: size = jnp.shape(scale) @@ -967,13 +1029,15 @@ def rayleigh(self, scale=1.0, size=None, key=None): r = x * scale return _return(r) - def triangular(self, size=None, key=None): + def triangular(self, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) bernoulli_samples = jr.bernoulli(key, p=0.5, shape=_size2shape(size)) r = 2 * bernoulli_samples - 1 return _return(r) - def vonmises(self, mu, kappa, size=None, key=None): + def vonmises(self, mu, kappa, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) mu = _check_py_seq(_as_jax_array(mu)) kappa = _check_py_seq(_as_jax_array(kappa)) @@ -985,7 +1049,8 @@ def vonmises(self, mu, kappa, size=None, key=None): samples = (samples + jnp.pi) % (2.0 * jnp.pi) - jnp.pi return _return(samples) - def weibull(self, a, size=None, key=None): + def weibull(self, a, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) a = _check_py_seq(_as_jax_array(a)) if size is None: @@ -998,7 +1063,8 @@ def weibull(self, a, size=None, key=None): r = jnp.power(-jnp.log1p(-random_uniform), 1.0 / a) return _return(r) - def weibull_min(self, a, scale=None, size=None, key=None): + def weibull_min(self, a, scale=None, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): """Sample from a Weibull minimum distribution. Parameters @@ -1030,14 +1096,15 @@ def weibull_min(self, a, scale=None, size=None, key=None): r /= scale return _return(r) - def maxwell(self, size=None, key=None): + def maxwell(self, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) shape = core.canonicalize_shape(_size2shape(size)) + (3,) norm_rvs = jr.normal(key=key, shape=shape) r = jnp.linalg.norm(norm_rvs, axis=-1) return _return(r) - def negative_binomial(self, n, p, size=None, key=None): + def negative_binomial(self, n, p, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): n = _check_py_seq(_as_jax_array(n)) p = _check_py_seq(_as_jax_array(p)) if size is None: @@ -1052,7 +1119,8 @@ def negative_binomial(self, n, p, size=None, key=None): r = self.poisson(lam=rate, key=keys[1]) return _return(r) - def wald(self, mean, scale, size=None, key=None): + def wald(self, mean, scale, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) mean = _check_py_seq(_as_jax_array(mean)) scale = _check_py_seq(_as_jax_array(scale)) @@ -1092,7 +1160,7 @@ def wald(self, mean, scale, size=None, key=None): jnp.square(mean) / sampled) return _return(res) - def t(self, df, size=None, key=None): + def t(self, df, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): df = _check_py_seq(_as_jax_array(df)) if size is None: size = np.shape(df) @@ -1110,7 +1178,8 @@ def t(self, df, size=None, key=None): r = n * jnp.sqrt(half_df / g) return _return(r) - def orthogonal(self, n: int, size=None, key=None): + def orthogonal(self, n: int, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) size = _size2shape(size) _check_shape("orthogonal", size) @@ -1121,7 +1190,8 @@ def orthogonal(self, n: int, size=None, key=None): r = q * jnp.expand_dims(d / abs(d), -2) return _return(r) - def noncentral_chisquare(self, df, nonc, size=None, key=None): + def noncentral_chisquare(self, df, nonc, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): df = _check_py_seq(_as_jax_array(df)) nonc = _check_py_seq(_as_jax_array(nonc)) if size is None: @@ -1139,7 +1209,8 @@ def noncentral_chisquare(self, df, nonc, size=None, key=None): r = jnp.where(cond, chi2 + n * n, chi2) return _return(r) - def loggamma(self, a, size=None, key=None): + def loggamma(self, a, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) a = _check_py_seq(_as_jax_array(a)) if size is None: @@ -1147,7 +1218,8 @@ def loggamma(self, a, size=None, key=None): r = jr.loggamma(key, a, shape=_size2shape(size)) return _return(r) - def categorical(self, logits, axis: int = -1, size=None, key=None): + def categorical(self, logits, axis: int = -1, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): key = self.split_key() if key is None else _formalize_key(key) logits = _check_py_seq(_as_jax_array(logits)) if size is None: @@ -1156,7 +1228,7 @@ def categorical(self, logits, axis: int = -1, size=None, key=None): r = jr.categorical(key, logits, axis=axis, shape=_size2shape(size)) return _return(r) - def zipf(self, a, size=None, key=None): + def zipf(self, a, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): a = _check_py_seq(_as_jax_array(a)) if size is None: size = jnp.shape(a) @@ -1165,7 +1237,7 @@ def zipf(self, a, size=None, key=None): result_shape=jax.ShapeDtypeStruct(size, jnp.int_)) return _return(r) - def power(self, a, size=None, key=None): + def power(self, a, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): a = _check_py_seq(_as_jax_array(a)) if size is None: size = jnp.shape(a) @@ -1174,7 +1246,8 @@ def power(self, a, size=None, key=None): a, result_shape=jax.ShapeDtypeStruct(size, jnp.float_)) return _return(r) - def f(self, dfnum, dfden, size=None, key=None): + def f(self, dfnum, dfden, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): dfnum = _as_jax_array(dfnum) dfden = _as_jax_array(dfden) dfnum = _check_py_seq(dfnum) @@ -1190,7 +1263,8 @@ def f(self, dfnum, dfden, size=None, key=None): result_shape=jax.ShapeDtypeStruct(size, jnp.float_)) return _return(r) - def hypergeometric(self, ngood, nbad, nsample, size=None, key=None): + def hypergeometric(self, ngood, nbad, nsample, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): ngood = _check_py_seq(_as_jax_array(ngood)) nbad = _check_py_seq(_as_jax_array(nbad)) nsample = _check_py_seq(_as_jax_array(nsample)) @@ -1208,7 +1282,8 @@ def hypergeometric(self, ngood, nbad, nsample, size=None, key=None): d, result_shape=jax.ShapeDtypeStruct(size, jnp.int_)) return _return(r) - def logseries(self, p, size=None, key=None): + def logseries(self, p, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): p = _check_py_seq(_as_jax_array(p)) if size is None: size = jnp.shape(p) @@ -1217,7 +1292,8 @@ def logseries(self, p, size=None, key=None): p, result_shape=jax.ShapeDtypeStruct(size, jnp.int_)) return _return(r) - def noncentral_f(self, dfnum, dfden, nonc, size=None, key=None): + def noncentral_f(self, dfnum, dfden, nonc, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): dfnum = _check_py_seq(_as_jax_array(dfnum)) dfden = _check_py_seq(_as_jax_array(dfden)) nonc = _check_py_seq(_as_jax_array(nonc)) @@ -1237,7 +1313,7 @@ def noncentral_f(self, dfnum, dfden, nonc, size=None, key=None): # PyTorch compatibility # # --------------------- # - def rand_like(self, input, *, dtype=None, key=None): + def rand_like(self, input, *, dtype=None, key: Optional[Union[int, JAX_RAND_KEY]] = None): """Returns a tensor with the same size as input that is filled with random numbers from a uniform distribution on the interval ``[0, 1)``. @@ -1251,7 +1327,7 @@ def rand_like(self, input, *, dtype=None, key=None): """ return self.random(shape(input), key=key).astype(dtype) - def randn_like(self, input, *, dtype=None, key=None): + def randn_like(self, input, *, dtype=None, key: Optional[Union[int, JAX_RAND_KEY]] = None): """Returns a tensor with the same size as ``input`` that is filled with random numbers from a normal distribution with mean 0 and variance 1. @@ -1265,7 +1341,7 @@ def randn_like(self, input, *, dtype=None, key=None): """ return self.randn(*shape(input), key=key).astype(dtype) - def randint_like(self, input, low=0, high=None, *, dtype=None, key=None): + def randint_like(self, input, low=0, high=None, *, dtype=None, key: Optional[Union[int, JAX_RAND_KEY]] = None): if high is None: high = max(input) return self.randint(low, high=high, size=shape(input), dtype=dtype, key=key) @@ -1319,7 +1395,7 @@ def clone_rng(seed_or_key=None, clone: bool = True) -> RandomState: return RandomState(seed_or_key) -def default_rng(seed_or_key=None, clone=True) -> RandomState: +def default_rng(seed_or_key=None, clone: bool = True) -> RandomState: if seed_or_key is None: return DEFAULT.clone() if clone else DEFAULT else: @@ -1341,7 +1417,7 @@ def seed(seed: int = None): DEFAULT.seed(seed) -def rand(*dn, key=None): +def rand(*dn, key: Optional[Union[int, JAX_RAND_KEY]] = None): r"""Random values in a given shape. .. note:: @@ -1379,7 +1455,8 @@ def rand(*dn, key=None): return DEFAULT.rand(*dn, key=key) -def randint(low, high=None, size=None, dtype=int, key=None): +def randint(low, high=None, size: Optional[Union[int, Sequence[int]]] = None, dtype=int, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r"""Return random integers from `low` (inclusive) to `high` (exclusive). Return random integers from the "discrete uniform" distribution of @@ -1451,7 +1528,10 @@ def randint(low, high=None, size=None, dtype=int, key=None): return DEFAULT.randint(low, high=high, size=size, dtype=dtype, key=key) -def random_integers(low, high=None, size=None, key=None): +def random_integers(low, + high=None, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Random integers of type `np.int_` between `low` and `high`, inclusive. @@ -1529,7 +1609,7 @@ def random_integers(low, high=None, size=None, key=None): return DEFAULT.random_integers(low, high=high, size=size, key=key) -def randn(*dn, key=None): +def randn(*dn, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Return a sample (or samples) from the "standard normal" distribution. @@ -1589,7 +1669,7 @@ def randn(*dn, key=None): return DEFAULT.randn(*dn, key=key) -def random(size=None, key=None): +def random(size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Return random floats in the half-open interval [0.0, 1.0). Alias for `random_sample` to ease forward-porting to the new random API. @@ -1597,7 +1677,7 @@ def random(size=None, key=None): return DEFAULT.random(size, key=key) -def random_sample(size=None, key=None): +def random_sample(size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Return random floats in the half-open interval [0.0, 1.0). @@ -1648,7 +1728,7 @@ def random_sample(size=None, key=None): return DEFAULT.random_sample(size, key=key) -def ranf(size=None, key=None): +def ranf(size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" This is an alias of `random_sample`. See `random_sample` for the complete documentation. @@ -1656,7 +1736,7 @@ def ranf(size=None, key=None): return DEFAULT.ranf(size, key=key) -def sample(size=None, key=None): +def sample(size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): """ This is an alias of `random_sample`. See `random_sample` for the complete documentation. @@ -1664,7 +1744,8 @@ def sample(size=None, key=None): return DEFAULT.sample(size, key=key) -def choice(a, size=None, replace=True, p=None, key=None): +def choice(a, size: Optional[Union[int, Sequence[int]]] = None, replace=True, p=None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Generates a random sample from a given 1-D array @@ -1752,7 +1833,10 @@ def choice(a, size=None, replace=True, p=None, key=None): return DEFAULT.choice(a=a, size=size, replace=replace, p=p, key=key) -def permutation(x, axis: int = 0, independent: bool = False, key=None): +def permutation(x, + axis: int = 0, + independent: bool = False, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Randomly permute a sequence, or return a permuted range. @@ -1789,7 +1873,7 @@ def permutation(x, axis: int = 0, independent: bool = False, key=None): return DEFAULT.permutation(x, axis=axis, independent=independent, key=key) -def shuffle(x, axis=0, key=None): +def shuffle(x, axis=0, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Modify a sequence in-place by shuffling its contents. @@ -1826,7 +1910,7 @@ def shuffle(x, axis=0, key=None): DEFAULT.shuffle(x, axis, key=key) -def beta(a, b, size=None, key=None): +def beta(a, b, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a Beta distribution. @@ -1864,7 +1948,8 @@ def beta(a, b, size=None, key=None): return DEFAULT.beta(a, b, size=size, key=key) -def exponential(scale=None, size=None, key=None): +def exponential(scale=None, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from an exponential distribution. @@ -1910,7 +1995,8 @@ def exponential(scale=None, size=None, key=None): return DEFAULT.exponential(scale, size, key=key) -def gamma(shape, scale=None, size=None, key=None): +def gamma(shape, scale=None, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a Gamma distribution. @@ -1962,7 +2048,8 @@ def gamma(shape, scale=None, size=None, key=None): return DEFAULT.gamma(shape, scale, size=size, key=key) -def gumbel(loc=None, scale=None, size=None, key=None): +def gumbel(loc=None, scale=None, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a Gumbel distribution. @@ -2031,7 +2118,8 @@ def gumbel(loc=None, scale=None, size=None, key=None): return DEFAULT.gumbel(loc, scale, size=size, key=key) -def laplace(loc=None, scale=None, size=None, key=None): +def laplace(loc=None, scale=None, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from the Laplace or double exponential distribution with specified location (or mean) and scale (decay). @@ -2111,7 +2199,8 @@ def laplace(loc=None, scale=None, size=None, key=None): return DEFAULT.laplace(loc, scale, size, key=key) -def logistic(loc=None, scale=None, size=None, key=None): +def logistic(loc=None, scale=None, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a logistic distribution. @@ -2181,7 +2270,8 @@ def logistic(loc=None, scale=None, size=None, key=None): return DEFAULT.logistic(loc, scale, size, key=key) -def normal(loc=None, scale=None, size=None, key=None): +def normal(loc=None, scale=None, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw random samples from a normal (Gaussian) distribution. @@ -2273,7 +2363,7 @@ def normal(loc=None, scale=None, size=None, key=None): return DEFAULT.normal(loc, scale, size, key=key) -def pareto(a, size=None, key=None): +def pareto(a, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a Pareto II or Lomax distribution with specified shape. @@ -2365,7 +2455,7 @@ def pareto(a, size=None, key=None): return DEFAULT.pareto(a, size, key=key) -def poisson(lam=1.0, size=None, key=None): +def poisson(lam=1.0, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a Poisson distribution. @@ -2432,7 +2522,7 @@ def poisson(lam=1.0, size=None, key=None): return DEFAULT.poisson(lam, size, key=key) -def standard_cauchy(size=None, key=None): +def standard_cauchy(size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a standard Cauchy distribution with mode = 0. @@ -2494,7 +2584,8 @@ def standard_cauchy(size=None, key=None): return DEFAULT.standard_cauchy(size, key=key) -def standard_exponential(size=None, key=None): +def standard_exponential(size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from the standard exponential distribution. @@ -2522,7 +2613,8 @@ def standard_exponential(size=None, key=None): return DEFAULT.standard_exponential(size, key=key) -def standard_gamma(shape, size=None, key=None): +def standard_gamma(shape, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a standard Gamma distribution. @@ -2591,7 +2683,7 @@ def standard_gamma(shape, size=None, key=None): return DEFAULT.standard_gamma(shape, size, key=key) -def standard_normal(size=None, key=None): +def standard_normal(size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a standard Normal distribution (mean=0, stdev=1). @@ -2647,7 +2739,7 @@ def standard_normal(size=None, key=None): return DEFAULT.standard_normal(size, key=key) -def standard_t(df, size=None, key=None): +def standard_t(df, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a standard Student's t distribution with `df` degrees of freedom. @@ -2747,7 +2839,8 @@ def standard_t(df, size=None, key=None): return DEFAULT.standard_t(df, size, key=key) -def uniform(low=0.0, high=1.0, size=None, key=None): +def uniform(low=0.0, high=1.0, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a uniform distribution. @@ -2834,7 +2927,8 @@ def uniform(low=0.0, high=1.0, size=None, key=None): return DEFAULT.uniform(low, high, size, key=key) -def truncated_normal(lower, upper, size=None, loc=0., scale=1., dtype=float, key=None): +def truncated_normal(lower, upper, size: Optional[Union[int, Sequence[int]]] = None, loc=0., scale=1., dtype=float, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r"""Sample truncated standard normal random values with given shape and dtype. Method based on https://people.sc.fsu.edu/~jburkardt/presentations/truncated_normal.pdf @@ -2895,7 +2989,7 @@ def truncated_normal(lower, upper, size=None, loc=0., scale=1., dtype=float, key RandomState.truncated_normal.__doc__ = truncated_normal.__doc__ -def bernoulli(p=0.5, size=None, key=None): +def bernoulli(p=0.5, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r"""Sample Bernoulli random values with given shape and mean. Parameters @@ -2918,7 +3012,8 @@ def bernoulli(p=0.5, size=None, key=None): return DEFAULT.bernoulli(p, size, key=key) -def lognormal(mean=None, sigma=None, size=None, key=None): +def lognormal(mean=None, sigma=None, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a log-normal distribution. @@ -3023,7 +3118,7 @@ def lognormal(mean=None, sigma=None, size=None, key=None): return DEFAULT.lognormal(mean, sigma, size, key=key) -def binomial(n, p, size=None, key=None): +def binomial(n, p, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a binomial distribution. @@ -3108,7 +3203,7 @@ def binomial(n, p, size=None, key=None): return DEFAULT.binomial(n, p, size, key=key) -def chisquare(df, size=None, key=None): +def chisquare(df, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a chi-square distribution. @@ -3171,7 +3266,7 @@ def chisquare(df, size=None, key=None): return DEFAULT.chisquare(df, size, key=key) -def dirichlet(alpha, size=None, key=None): +def dirichlet(alpha, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from the Dirichlet distribution. @@ -3248,7 +3343,7 @@ def dirichlet(alpha, size=None, key=None): return DEFAULT.dirichlet(alpha, size, key=key) -def geometric(p, size=None, key=None): +def geometric(p, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from the geometric distribution. @@ -3294,7 +3389,7 @@ def geometric(p, size=None, key=None): return DEFAULT.geometric(p, size, key=key) -def f(dfnum, dfden, size=None, key=None): +def f(dfnum, dfden, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from an F distribution. @@ -3377,7 +3472,8 @@ def f(dfnum, dfden, size=None, key=None): return DEFAULT.f(dfnum, dfden, size, key=key) -def hypergeometric(ngood, nbad, nsample, size=None, key=None): +def hypergeometric(ngood, nbad, nsample, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a Hypergeometric distribution. @@ -3468,7 +3564,7 @@ def hypergeometric(ngood, nbad, nsample, size=None, key=None): return DEFAULT.hypergeometric(ngood, nbad, nsample, size, key=key) -def logseries(p, size=None, key=None): +def logseries(p, size: Optional[Union[int, Sequence[int]]] = None, key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a logarithmic series distribution. @@ -3543,7 +3639,8 @@ def logseries(p, size=None, key=None): return DEFAULT.logseries(p, size, key=key) -def multinomial(n, pvals, size=None, key=None): +def multinomial(n, pvals, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a multinomial distribution. @@ -3619,7 +3716,8 @@ def multinomial(n, pvals, size=None, key=None): return DEFAULT.multinomial(n, pvals, size, key=key) -def multivariate_normal(mean, cov, size=None, method: str = 'cholesky', key=None): +def multivariate_normal(mean, cov, size: Optional[Union[int, Sequence[int]]] = None, method: str = 'cholesky', + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw random samples from a multivariate normal distribution. @@ -3744,7 +3842,8 @@ def multivariate_normal(mean, cov, size=None, method: str = 'cholesky', key=None return DEFAULT.multivariate_normal(mean, cov, size, method, key=key) -def negative_binomial(n, p, size=None, key=None): +def negative_binomial(n, p, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a negative binomial distribution. @@ -3815,7 +3914,8 @@ def negative_binomial(n, p, size=None, key=None): return DEFAULT.negative_binomial(n, p, size, key=key) -def noncentral_chisquare(df, nonc, size=None, key=None): +def noncentral_chisquare(df, nonc, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a noncentral chi-square distribution. @@ -3886,7 +3986,8 @@ def noncentral_chisquare(df, nonc, size=None, key=None): return DEFAULT.noncentral_chisquare(df, nonc, size, key=key) -def noncentral_f(dfnum, dfden, nonc, size=None, key=None): +def noncentral_f(dfnum, dfden, nonc, size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from the noncentral F distribution. @@ -3955,7 +4056,9 @@ def noncentral_f(dfnum, dfden, nonc, size=None, key=None): return DEFAULT.noncentral_f(dfnum, dfden, nonc, size, key=key) -def power(a, size=None, key=None): +def power(a, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draws samples in [0, 1] from a power distribution with positive exponent a - 1. @@ -4050,7 +4153,9 @@ def power(a, size=None, key=None): return DEFAULT.power(a, size, key=key) -def rayleigh(scale=1.0, size=None, key=None): +def rayleigh(scale=1.0, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a Rayleigh distribution. @@ -4113,7 +4218,8 @@ def rayleigh(scale=1.0, size=None, key=None): return DEFAULT.rayleigh(scale, size, key=key) -def triangular(size=None, key=None): +def triangular(size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from the triangular distribution over the interval ``[left, right]``. @@ -4169,7 +4275,10 @@ def triangular(size=None, key=None): return DEFAULT.triangular(size, key=key) -def vonmises(mu, kappa, size=None, key=None): +def vonmises(mu, + kappa, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a von Mises distribution. @@ -4247,7 +4356,10 @@ def vonmises(mu, kappa, size=None, key=None): return DEFAULT.vonmises(mu, kappa, size, key=key) -def wald(mean, scale, size=None, key=None): +def wald(mean, + scale, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a Wald, or inverse Gaussian, distribution. @@ -4310,7 +4422,9 @@ def wald(mean, scale, size=None, key=None): return DEFAULT.wald(mean, scale, size, key=key) -def weibull(a, size=None, key=None): +def weibull(a, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a Weibull distribution. @@ -4401,7 +4515,10 @@ def weibull(a, size=None, key=None): return DEFAULT.weibull(a, size, key=key) -def weibull_min(a, scale=None, size=None, key=None): +def weibull_min(a, + scale=None, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): """Sample from a Weibull distribution. The scipy counterpart is `scipy.stats.weibull_min`. @@ -4420,7 +4537,9 @@ def weibull_min(a, scale=None, size=None, key=None): return DEFAULT.weibull_min(a, scale, size, key=key) -def zipf(a, size=None, key=None): +def zipf(a, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): r""" Draw samples from a Zipf distribution. @@ -4507,7 +4626,8 @@ def zipf(a, size=None, key=None): return DEFAULT.zipf(a, size, key=key) -def maxwell(size=None, key=None): +def maxwell(size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): """Sample from a one sided Maxwell distribution. The scipy counterpart is `scipy.stats.maxwell`. @@ -4524,7 +4644,9 @@ def maxwell(size=None, key=None): return DEFAULT.maxwell(size, key=key) -def t(df, size=None, key=None): +def t(df, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): """Sample Student’s t random values. Parameters @@ -4543,7 +4665,9 @@ def t(df, size=None, key=None): return DEFAULT.t(df, size, key=key) -def orthogonal(n: int, size=None, key=None): +def orthogonal(n: int, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): """Sample uniformly from the orthogonal group `O(n)`. Parameters @@ -4561,7 +4685,9 @@ def orthogonal(n: int, size=None, key=None): return DEFAULT.orthogonal(n, size, key=key) -def loggamma(a, size=None, key=None): +def loggamma(a, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): """Sample log-gamma random values. Parameters @@ -4577,10 +4703,13 @@ def loggamma(a, size=None, key=None): out: array_like The sampled results. """ - return DEFAULT.loggamma(a, size) + return DEFAULT.loggamma(a, size, key=key) -def categorical(logits, axis: int = -1, size=None, key=None): +def categorical(logits, + axis: int = -1, + size: Optional[Union[int, Sequence[int]]] = None, + key: Optional[Union[int, JAX_RAND_KEY]] = None): """Sample random values from categorical distributions. Args: @@ -4599,7 +4728,7 @@ def categorical(logits, axis: int = -1, size=None, key=None): return DEFAULT.categorical(logits, axis, size, key=key) -def rand_like(input, *, dtype=None, key=None): +def rand_like(input, *, dtype=None, key: Optional[Union[int, JAX_RAND_KEY]] = None): """Similar to ``rand_like`` in torch. Returns a tensor with the same size as input that is filled with random @@ -4616,7 +4745,7 @@ def rand_like(input, *, dtype=None, key=None): return DEFAULT.rand_like(input, dtype=dtype, key=key) -def randn_like(input, *, dtype=None, key=None): +def randn_like(input, *, dtype=None, key: Optional[Union[int, JAX_RAND_KEY]] = None): """Similar to ``randn_like`` in torch. Returns a tensor with the same size as ``input`` that is filled with @@ -4633,7 +4762,7 @@ def randn_like(input, *, dtype=None, key=None): return DEFAULT.randn_like(input, dtype=dtype, key=key) -def randint_like(input, low=0, high=None, *, dtype=None, key=None): +def randint_like(input, low=0, high=None, *, dtype=None, key: Optional[Union[int, JAX_RAND_KEY]] = None): """Similar to ``randint_like`` in torch. Returns a tensor with the same shape as Tensor ``input`` filled with diff --git a/brainpy/_src/train/back_propagation.py b/brainpy/_src/train/back_propagation.py index f395158c0..6809d7125 100644 --- a/brainpy/_src/train/back_propagation.py +++ b/brainpy/_src/train/back_propagation.py @@ -278,7 +278,7 @@ def fit( for x, y in _training_data: # reset state if reset_state: - self.target.reset_state(self._get_input_batch_size(x)) + self.target.reset(self._get_input_batch_size(x)) self.reset_state() # training @@ -356,7 +356,7 @@ def fit( for x, y in _testing_data: # reset state if reset_state: - self.target.reset_state(self._get_input_batch_size(x)) + self.target.reset(self._get_input_batch_size(x)) self.reset_state() # testing @@ -604,7 +604,7 @@ def predict( # reset the model states if reset_state: - self.target.reset_state(self._get_input_batch_size(xs=inputs)) + self.target.reset(self._get_input_batch_size(xs=inputs)) self.reset_state() # init monitor for key in self._monitors.keys(): diff --git a/brainpy/_src/train/online.py b/brainpy/_src/train/online.py index 212a22617..d80764f26 100644 --- a/brainpy/_src/train/online.py +++ b/brainpy/_src/train/online.py @@ -161,7 +161,7 @@ def fit( # reset the model states if reset_state: num_batch = self._get_input_batch_size(xs) - self.target.reset_state(num_batch) + self.target.reset(num_batch) self.reset_state() # format input/target data diff --git a/brainpy/_src/transform.py b/brainpy/_src/transform.py index c9a8e4b13..cc20c6686 100644 --- a/brainpy/_src/transform.py +++ b/brainpy/_src/transform.py @@ -275,7 +275,6 @@ def __call__( return results def reset_state(self, batch_size=None): - self.target.reset_state(batch_size) if self.i0 is not None: self.i0.value = bm.as_jax(self._i0) if self.t0 is not None: diff --git a/docs/core_concept/brainpy_dynamical_system.ipynb b/docs/core_concept/brainpy_dynamical_system.ipynb index b8151486d..4f86de402 100644 --- a/docs/core_concept/brainpy_dynamical_system.ipynb +++ b/docs/core_concept/brainpy_dynamical_system.ipynb @@ -425,7 +425,7 @@ " currents = bm.random.rand(200, 10, 100)\n", "\n", " # run the model\n", - " net2.reset_state(batch_size=10)\n", + " net2.reset(10)\n", " out = bm.for_loop(run_net2, (times, currents))\n", "\n", "out.shape" @@ -459,7 +459,7 @@ } ], "source": [ - "net2.reset_state(batch_size=10)\n", + "net2.reset(10)\n", "looper = bp.LoopOverTime(net2)\n", "out = looper(currents)\n", "out.shape" diff --git a/docs/quickstart/training.ipynb b/docs/quickstart/training.ipynb index 511cd38b7..84874787f 100644 --- a/docs/quickstart/training.ipynb +++ b/docs/quickstart/training.ipynb @@ -888,7 +888,7 @@ } ], "source": [ - "model.reset_state(num_batch)\n", + "model.reset(num_batch)\n", "x, y = build_inputs_and_targets()\n", "predicts = trainer.predict(x)" ] @@ -961,7 +961,8 @@ "end_time": "2023-07-21T11:11:21.986941100Z", "start_time": "2023-07-21T11:11:21.973247Z" } - } + }, + "id": "a46d325952432921" }, { "cell_type": "code", @@ -1018,7 +1019,8 @@ "end_time": "2023-07-21T11:11:22.618507100Z", "start_time": "2023-07-21T11:11:22.593392700Z" } - } + }, + "id": "4adc791ee70c493" }, { "cell_type": "code", @@ -1094,7 +1096,7 @@ " self.f_grad = bm.grad(self.f_loss, grad_vars=self.opt.vars_to_train, return_value=True)\n", "\n", " def f_loss(self):\n", - " self.net.reset_state(num_sample)\n", + " self.net.reset(num_sample)\n", " outs = bm.for_loop(self.net.step_run, (indices, x_data))\n", " return bp.losses.cross_entropy_loss(bm.max(outs, axis=0), y_data)\n", "\n", diff --git a/docs/tutorial_training/bp_training.ipynb b/docs/tutorial_training/bp_training.ipynb index 219b52dd1..01d89ffda 100644 --- a/docs/tutorial_training/bp_training.ipynb +++ b/docs/tutorial_training/bp_training.ipynb @@ -20,13 +20,13 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 13, "outputs": [ { "data": { - "text/plain": "'2.4.0'" + "text/plain": "'2.5.0'" }, - "execution_count": 1, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -37,7 +37,7 @@ "import brainpy_datasets as bd\n", "import numpy as np\n", "\n", - "bm.set_mode(bm.training_mode)\n", + "bm.set_mode(bm.training_mode) # set training mode, the models will compute with the training mode\n", "bm.set_platform('cpu')\n", "\n", "bp.__version__" @@ -45,8 +45,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:19:41.886672Z", - "end_time": "2023-04-15T17:19:42.767681Z" + "end_time": "2024-01-13T09:05:29.721461300Z", + "start_time": "2024-01-13T09:05:29.283925600Z" } } }, @@ -92,8 +92,8 @@ "class ANNModel(bp.DynamicalSystem):\n", " def __init__(self, num_in, num_rec, num_out):\n", " super(ANNModel, self).__init__()\n", - " self.rec = bp.layers.LSTMCell(num_in, num_rec)\n", - " self.out = bp.layers.Dense(num_rec, num_out)\n", + " self.rec = bp.dyn.LSTMCell(num_in, num_rec)\n", + " self.out = bp.dnn.Dense(num_rec, num_out)\n", "\n", " def update(self, x):\n", " return x >> self.rec >> self.out" @@ -101,8 +101,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:19:42.767681Z", - "end_time": "2023-04-15T17:19:42.799139Z" + "end_time": "2024-01-13T08:50:04.157337200Z", + "start_time": "2024-01-13T08:50:04.140080700Z" } } }, @@ -142,8 +142,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:19:42.783368Z", - "end_time": "2023-04-15T17:19:43.159416Z" + "end_time": "2024-01-13T08:50:06.246666200Z", + "start_time": "2024-01-13T08:50:06.210747900Z" } } }, @@ -183,8 +183,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:19:42.861648Z", - "end_time": "2023-04-15T17:19:43.483023Z" + "end_time": "2024-01-13T08:50:09.743113700Z", + "start_time": "2024-01-13T08:50:08.517344500Z" } } }, @@ -196,26 +196,26 @@ "name": "stdout", "output_type": "stream", "text": [ - "Train 0 epoch, use 15.9655 s, loss 0.8331242203712463, acc 0.7072529196739197\n", - "Test 0 epoch, use 1.5463 s, loss 0.5571460127830505, acc 0.7961569428443909\n", - "Train 1 epoch, use 9.1526 s, loss 0.5049400925636292, acc 0.8177083730697632\n", - "Test 1 epoch, use 0.3750 s, loss 0.502030074596405, acc 0.81787109375\n", - "Train 2 epoch, use 9.2934 s, loss 0.46436846256256104, acc 0.8321365714073181\n", - "Test 2 epoch, use 0.3476 s, loss 0.48068222403526306, acc 0.8233513236045837\n", - "Train 3 epoch, use 9.0547 s, loss 0.4441152811050415, acc 0.8387909531593323\n", - "Test 3 epoch, use 0.3461 s, loss 0.4624057412147522, acc 0.8308019638061523\n", - "Train 4 epoch, use 9.2218 s, loss 0.42878103256225586, acc 0.8456172943115234\n", - "Test 4 epoch, use 0.3652 s, loss 0.45214834809303284, acc 0.835742175579071\n", - "Train 5 epoch, use 9.7000 s, loss 0.4177688956260681, acc 0.848858654499054\n", - "Test 5 epoch, use 0.3666 s, loss 0.45152249932289124, acc 0.8364028334617615\n", - "Train 6 epoch, use 9.5577 s, loss 0.4085409343242645, acc 0.8526595830917358\n", - "Test 6 epoch, use 0.3286 s, loss 0.43873366713523865, acc 0.8375632166862488\n", - "Train 7 epoch, use 8.8785 s, loss 0.4013414680957794, acc 0.8544437289237976\n", - "Test 7 epoch, use 0.3287 s, loss 0.4337906837463379, acc 0.8435719609260559\n", - "Train 8 epoch, use 9.0179 s, loss 0.3957517147064209, acc 0.8561835289001465\n", - "Test 8 epoch, use 0.3286 s, loss 0.4259491562843323, acc 0.8464958071708679\n", - "Train 9 epoch, use 8.8762 s, loss 0.389633446931839, acc 0.8590757846832275\n", - "Test 9 epoch, use 0.3286 s, loss 0.4192558228969574, acc 0.8488511443138123\n" + "Train 0 epoch, use 18.3506 s, loss 0.7428755164146423, acc 0.7363530397415161\n", + "Test 0 epoch, use 2.6725 s, loss 0.5576136708259583, acc 0.7941579222679138\n", + "Train 1 epoch, use 16.8257 s, loss 0.49522149562835693, acc 0.8228002786636353\n", + "Test 1 epoch, use 0.8004 s, loss 0.49448657035827637, acc 0.8226505517959595\n", + "Train 2 epoch, use 16.9939 s, loss 0.46214181184768677, acc 0.8340814113616943\n", + "Test 2 epoch, use 0.9073 s, loss 0.4779117703437805, acc 0.829509437084198\n", + "Train 3 epoch, use 16.8647 s, loss 0.44188451766967773, acc 0.8404809832572937\n", + "Test 3 epoch, use 0.8124 s, loss 0.4663679301738739, acc 0.8316060900688171\n", + "Train 4 epoch, use 16.1298 s, loss 0.4282640814781189, acc 0.8446531891822815\n", + "Test 4 epoch, use 0.8153 s, loss 0.4542137086391449, acc 0.8341854214668274\n", + "Train 5 epoch, use 15.6680 s, loss 0.41988351941108704, acc 0.8464982509613037\n", + "Test 5 epoch, use 0.8146 s, loss 0.4481014907360077, acc 0.8375803828239441\n", + "Train 6 epoch, use 14.4913 s, loss 0.4098776876926422, acc 0.8514517545700073\n", + "Test 6 epoch, use 0.5594 s, loss 0.4398559033870697, acc 0.8402113914489746\n", + "Train 7 epoch, use 14.1168 s, loss 0.4020034968852997, acc 0.8549756407737732\n", + "Test 7 epoch, use 0.7845 s, loss 0.4330603778362274, acc 0.8429400324821472\n", + "Train 8 epoch, use 12.5251 s, loss 0.3960183560848236, acc 0.8563995957374573\n", + "Test 8 epoch, use 0.6067 s, loss 0.42536696791648865, acc 0.8437040448188782\n", + "Train 9 epoch, use 12.4504 s, loss 0.3891957700252533, acc 0.8586103916168213\n", + "Test 9 epoch, use 0.7093 s, loss 0.42744284868240356, acc 0.8430147171020508\n" ] } ], @@ -227,8 +227,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:19:43.483023Z", - "end_time": "2023-04-15T17:21:26.989206Z" + "end_time": "2024-01-13T08:26:35.104829700Z", + "start_time": "2024-01-13T08:23:50.886538200Z" } } }, @@ -239,7 +239,7 @@ { "data": { "text/plain": "
", - "image/png": "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K0latmyZLrnkEu++6enpmjFjhvf5ww8/rJdeeklr167V3Xff3e9nLFq0SDfeeKMk6ZFHHtETTzyhDz74QJdddtmgv9pAmTpy8+ijj+q2227T7bffrilTpmjFihXKz8/XqlWr+tz//fffV2Fhob7zne9o3LhxuuCCC/T//t//0+bNm0e48oEpzuvuuwEAIJTMmjXL53lzc7O+973vaerUqUpNTVViYqL27t17ypGb4uJi7+OEhAQlJSWpqqpqWGr2MG3kpr29XVu2bNEDDzzgs33+/PnatGlTn8fMmTNHS5cu1bp167RgwQJVVVXpT3/6k7785S/3+zkOh0MOh8P7vKGhITBfYAC8TcVH6+V0GbLSVAwAkSMm3j2KYsbnBsDJZz3df//9eu211/Tzn/9cEyZMUFxcnK699lq1t7f7Lycmxue5xWKRy+UKSI39MS3cVFdXy+l0Kisry2d7VlaWKisr+zxmzpw5evHFF3XDDTeora1NnZ2duvLKK/XEE0/0+znLly/XQw89FNDaB+qM0YmKt1nV0u7UZ9VNmpCZZEodAAATWCwDnh4yk81mk9PpPOV+Gzdu1KJFi3T11VdLkpqamnTo0KFhrm5oTG8otlh8RzMMw+i1zWP37t36zne+ox/96EfasmWLXn31VX322We68847+33/Bx98UPX19d5bWVlZQOv3xxpl8a5UvJ3F/AAAQaiwsFD/93//p0OHDqm6urrfUZUJEyboL3/5i7Zt26aPP/5YX//614d9BGaoTAs3GRkZslqtvUZpqqqqeo3meCxfvlxz587V/fffr+LiYl166aVauXKlnn32WVVUVPR5jN1uV3Jyss9tJE3PTZVEuAEABKf77rtPVqtVU6dO1ejRo/vtoXnsscc0atQozZkzR1dccYUuvfRSnXPOOSNc7cCYNi1ls9k0c+ZMlZSUeIe4JKmkpERXXXVVn8e0tLT0WkTIarVKco/4BKPpeZwODgAIXpMmTdI//vEPn22LFi3qtV9hYaHefPNNn2133XWXz/OTp6n6+t1cV1c3pDoHw9RpqSVLlujpp5/Ws88+qz179ujee+9VaWmpd5rpwQcf1C233OLd/4orrtBf/vIXrVq1SgcPHtR7772n73znOzrvvPM0ZowJp9sNgGfkZtfRBjldwRnAAAAIJ6auc3PDDTeopqZGy5YtU0VFhYqKirRu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li2Ty+Uyu7SQRrgJgDVr1mjx4sVaunSptm7dqgsvvFALFixQaWmp2aVFpA0bNuiuu+7S+++/r5KSEnV2dmr+/Plqbm42u7SI9+GHH2r16tUqLi42u5SIdeLECc2dO1cxMTF65ZVXtHv3bv3iF79Qamqq2aVFpJ/+9Kf61a9+pSeffFJ79uzRz372M/3nf/6nnnjiCbNLC2mcCh4A559/vs455xytWrXKu23KlClauHChli9fbmJlkKTjx48rMzNTGzZs0Oc//3mzy4lYTU1NOuecc7Ry5Uo9/PDDOuuss7RixQqzy4o4DzzwgN577z1Gl4PEV77yFWVlZemZZ57xbvvqV7+q+Ph4/fa3vzWxstDGyM1pam9v15YtWzR//nyf7fPnz9emTZtMqgo91dfXS5LS0tJMriSy3XXXXfryl7+sL33pS2aXEtHWrl2rWbNm6brrrlNmZqbOPvts/frXvza7rIh1wQUX6I033tD+/fslSR9//LHeffddXX755SZXFtoi7sKZgVZdXS2n06msrCyf7VlZWaqsrDSpKngYhqElS5boggsuUFFRkdnlRKw//OEP+uijj/Thhx+aXUrEO3jwoFatWqUlS5bo+9//vj744AN95zvfkd1u1y233GJ2eRHnX//1X1VfX6/JkyfLarXK6XTqJz/5iW688UazSwtphJsAsVgsPs8Nw+i1DSPv7rvv1vbt2/Xuu++aXUrEKisr03e/+129/vrrio2NNbuciOdyuTRr1iw98sgjkqSzzz5bu3bt0qpVqwg3JlizZo1+97vf6fe//72mTZumbdu2afHixRozZoy+8Y1vmF1eyCLcnKaMjAxZrdZeozRVVVW9RnMwsu655x6tXbtW77zzjvLy8swuJ2Jt2bJFVVVVmjlzpneb0+nUO++8oyeffFIOh0NWq9XECiNLTk6Opk6d6rNtypQp+vOf/2xSRZHt/vvv1wMPPKCvfe1rkqTp06fr8OHDWr58OeHmNNBzc5psNptmzpypkpISn+0lJSWaM2eOSVVFNsMwdPfdd+svf/mL3nzzTY0bN87skiLavHnztGPHDm3bts17mzVrlm666SZt27aNYDPC5s6d22tphP3796ugoMCkiiJbS0uLoqJ8fxVbrVZOBT9NjNwEwJIlS3TzzTdr1qxZmj17tlavXq3S0lLdeeedZpcWke666y79/ve/11//+lclJSV5R9VSUlIUFxdncnWRJykpqVe/U0JCgtLT0+mDMsG9996rOXPm6JFHHtH111+vDz74QKtXr9bq1avNLi0iXXHFFfrJT36isWPHatq0adq6daseffRRffOb3zS7tNBmICB++ctfGgUFBYbNZjPOOeccY8OGDWaXFLEk9Xl77rnnzC4NXb7whS8Y3/3ud80uI2L97W9/M4qKigy73W5MnjzZWL16tdklRayGhgbju9/9rjF27FgjNjbWOOOMM4ylS5caDofD7NJCGuvcAACAsELPDQAACCuEGwAAEFYINwAAIKwQbgAAQFgh3AAAgLBCuAEAAGGFcAMAAMIK4QYAAIQVwg0ASLJYLHr55ZfNLgNAABBuAJhu0aJFslgsvW6XXXaZ2aUBCEFcOBNAULjsssv03HPP+Wyz2+0mVQMglDFyAyAo2O12ZWdn+9xGjRolyT1ltGrVKi1YsEBxcXEaN26c/vjHP/ocv2PHDl188cWKi4tTenq67rjjDjU1Nfns8+yzz2ratGmy2+3KycnR3Xff7fN6dXW1rr76asXHx2vixIlau3bt8H5pAMOCcAMgJPzwhz/UV7/6VX388cf6p3/6J914443as2ePJKmlpUWXXXaZRo0apQ8//FB//OMftX79ep/wsmrVKt1111264447tGPHDq1du1YTJkzw+YyHHnpI119/vbZv367LL79cN910k2pra0f0ewIIALMvSw4A3/jGNwyr1WokJCT43JYtW2YYhmFIMu68806fY84//3zjn//5nw3DMIzVq1cbo0aNMpqamryv//3vfzeioqKMyspKwzAMY8yYMcbSpUv7rUGS8YMf/MD7vKmpybBYLMYrr7wSsO8JYGTQcwMgKHzxi1/UqlWrfLalpaV5H8+ePdvntdmzZ2vbtm2SpD179mjGjBlKSEjwvj537ly5XC7t27dPFotFR48e1bx58/zWUFxc7H2ckJCgpKQkVVVVDfUrATAJ4QZAUEhISOg1TXQqFotFkmQYhvdxX/vExcUN6P1iYmJ6HetyuQZVEwDz0XMDICS8//77vZ5PnjxZkjR16lRt27ZNzc3N3tffe+89RUVFadKkSUpKSlJhYaHeeOONEa0ZgDkYuQEQFBwOhyorK322RUdHKyMjQ5L0xz/+UbNmzdIFF1ygF198UR988IGeeeYZSdJNN92kH//4x/rGN76hf/u3f9Px48d1zz336Oabb1ZWVpYk6d/+7d905513KjMzUwsWLFBjY6Pee+893XPPPSP7RQEMO8INgKDw6quvKicnx2fbmWeeqb1790pyn8n0hz/8Qd/+9reVnZ2tF198UVOnTpUkxcfH67XXXtN3v/tdnXvuuYqPj9dXv/pVPfroo973+sY3vqG2tjY99thjuu+++5SRkaFrr7125L4ggBFjMQzDMLsIAPDHYrHopZde0sKFC80uBUAIoOcGAACEFcINAAAIK/TcAAh6zJ4DGAxGbgAAQFgh3AAAgLBCuAEAAGGFcAMAAMIK4QYAAIQVwg0AAAgrhBsAABBWCDcAACCs/H9AyYfYGOAaFAAAAABJRU5ErkJggg==\n" + "image/png": "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AQEBIlfiuh599FHcdNNNuOGGG8QuxeVt2rQJ6enpuPPOOxEcHIyUlBT84x//ELssl3XVVVfhq6++wvHjxwEABw4cwHfffYfp06eLXJlj42aoQ6C6uhoGgwEhISEWx0NCQlBZWSlSVdRBEAQsWLAAV111FRITE8UuxyV99NFH+Omnn7Bv3z6xSyEAp0+fxsqVK7FgwQI8++yz2Lt3L/7v//4PCoUC9913n9jluZw//OEP0Gg0iI+Ph0wmg8FgwMsvv4y7775b7NIcGgPQEJJIJBbvBUHocoyG3mOPPYaff/4Z3333ndiluKTS0lI88cQT2LZtG5RKpdjlEACj0Yj09HS88sorAICUlBQcOnQIK1euZAASQUFBAd5//318+OGHGDduHIqLizF//nyEh4fj/vvvF7s8h8UANASCgoIgk8m6tPZUVVV1aRWiofX4449j06ZN2LFjByIiIsQuxyXt378fVVVVSEtLMx8zGAzYsWMH3nrrLeh0OshkMhErdD1hYWFISEiwODZ27FisX79epIpc29NPP41nnnkGd911FwBg/PjxOHfuHPLy8hiAbMAxQENALpcjLS0NhYWFFscLCwuRnZ0tUlWuTRAEPPbYY/jss8/w3//+F7GxsWKX5LKmTJmCgwcPori42PxKT0/Hvffei+LiYoYfEeTk5HRZFuL48eOIjo4WqSLX1tTUBKnU8te1TCbjNHgbsQVoiCxYsABz5sxBeno6srKysGrVKpSUlGDevHlil+aSHn30UXz44Yf4/PPP4ePjY26dU6lU8PDwELk61+Lj49Nl7JWXlxcCAwM5JkskTz75JLKzs/HKK69g1qxZ2Lt3L1atWoVVq1aJXZpLuuWWW/Dyyy8jKioK48aNQ1FREd544w389re/Fbs0h8Zp8EMoPz8fr732GtRqNRITE/HXv/6VU65F0t3Yq3fffRcPPPDA0BZDXVx77bWcBi+y//znP1i4cCFOnDiB2NhYLFiwAI888ojYZbmk+vp6LF68GBs2bEBVVRXCw8Nx99134/nnn4dcLhe7PIfFAEREREQuh2OAiIiIyOUwABEREZHLYQAiIiIil8MARERERC6HAYiIiIhcDgMQERERuRwGICIiInI5DEBERETkchiAiIh6QSKRYOPGjWKXQUQDhAGIiOzeAw88AIlE0uU1depUsUsjIgfFzVCJyCFMnToV7777rsUxhUIhUjVE5OjYAkREDkGhUCA0NNTi5e/vD8DUPbVy5UpMmzYNHh4eiI2NxSeffGJx/cGDB3H99dfDw8MDgYGBmDt3LhoaGizOWbNmDcaNGweFQoGwsDA89thjFp9XV1dj5syZ8PT0xKhRo7Bp06bBfWgiGjQMQETkFBYvXozbb78dBw4cwG9+8xvcfffdOHLkCACgqakJU6dOhb+/P/bt24dPPvkE27dvtwg4K1euxKOPPoq5c+fi4MGD2LRpE0aOHGnxHUuWLMGsWbPw888/Y/r06bj33ntRW1s7pM9JRANEICKyc/fff78gk8kELy8vi9fSpUsFQRAEAMK8efMsrsnIyBD+93//VxAEQVi1apXg7+8vNDQ0mD//4osvBKlUKlRWVgqCIAjh4eHCokWLuq0BgPDcc8+Z3zc0NAgSiUTYsmXLgD0nEQ0djgEiIodw3XXXYeXKlRbHAgICzD9nZWVZfJaVlYXi4mIAwJEjR5CUlAQvLy/z5zk5OTAajTh27BgkEgkqKiowZcqUHmuYMGGC+WcvLy/4+Pigqqqqv49ERCJiACIih+Dl5dWlS+pKJBIJAEAQBPPP1s7x8PDo1f3c3d27XGs0GvtUExHZB44BIiKn8P3333d5Hx8fDwBISEhAcXExGhsbzZ/v2rULUqkUo0ePho+PD2JiYvDVV18Nac1EJB62ABGRQ9DpdKisrLQ45ubmhqCgIADAJ598gvT0dFx11VX44IMPsHfvXqxevRoAcO+99+KPf/wj7r//frzwwgu4cOECHn/8ccyZMwchISEAgBdeeAHz5s1DcHAwpk2bhvr6euzatQuPP/740D4oEQ0JBiAicghffvklwsLCLI6NGTMGR48eBWCaofXRRx/hd7/7HUJDQ/HBBx8gISEBAODp6YmtW7fiiSeewMSJE+Hp6Ynbb78db7zxhvle999/P1paWvDXv/4VTz31FIKCgnDHHXcM3QMS0ZCSCIIgiF0EEZEtJBIJNmzYgBkzZohdChE5CI4BIiIiIpfDAEREREQuh2OAiMjhsSefiPqKLUBERETkchiAiIiIyOUwABEREZHLYQAiIiIil8MARERERC6HAYiIiIhcDgMQERERuRwGICIiInI5/x9FAHKFrKtfrQAAAABJRU5ErkJggg==" }, "metadata": {}, "output_type": "display_data" @@ -258,8 +258,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:21:26.990238Z", - "end_time": "2023-04-15T17:21:27.307719Z" + "end_time": "2024-01-13T08:26:35.728528700Z", + "start_time": "2024-01-13T08:26:35.098672100Z" } } }, @@ -290,7 +290,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "outputs": [], "source": [ "class SNNModel(bp.DynamicalSystem):\n", @@ -303,33 +303,32 @@ " self.num_out = num_out\n", "\n", " # neuron groups\n", - " self.i = bp.neurons.InputGroup(num_in)\n", - " self.r = bp.neurons.LIF(num_rec, tau=10, V_reset=0, V_rest=0, V_th=1.)\n", - " self.o = bp.neurons.LeakyIntegrator(num_out, tau=5)\n", + " self.r = bp.dyn.LifRef(num_rec, tau=10, V_reset=0, V_rest=0, V_th=1.)\n", + " self.o = bp.dyn.Leaky(num_out, tau=5)\n", "\n", " # synapse: i->r\n", - " self.i2r = bp.synapses.Exponential(self.i, self.r, bp.conn.All2All(),\n", - " output=bp.synouts.CUBA(),\n", - " tau=10.,\n", - " g_max=bp.init.KaimingNormal(scale=2.))\n", + " self.i2r = bp.dyn.HalfProjAlignPost(comm=bp.dnn.Linear(num_in, num_rec, bp.init.KaimingNormal(scale=2.)),\n", + " syn=bp.dyn.Expon(num_rec, tau=10.),\n", + " out=bp.dyn.CUBA(),\n", + " post=self.r)\n", " # synapse: r->o\n", - " self.r2o = bp.synapses.Exponential(self.r, self.o, bp.conn.All2All(),\n", - " output=bp.synouts.CUBA(),\n", - " tau=10.,\n", - " g_max=bp.init.KaimingNormal(scale=2.))\n", + " self.r2o = bp.dyn.HalfProjAlignPost(comm=bp.dnn.Linear(num_rec, num_out, bp.init.KaimingNormal(scale=2.)),\n", + " syn=bp.dyn.Expon(num_out, tau=10.),\n", + " out=bp.dyn.CUBA(),\n", + " post=self.o)\n", "\n", " def update(self, spike):\n", " self.i2r(spike)\n", - " self.r2o()\n", + " self.r2o(self.r.spike.value)\n", " self.r()\n", " self.o()\n", - " return self.o.V.value" + " return self.o.x.value" ], "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:21:27.307719Z", - "end_time": "2023-04-15T17:21:27.323515Z" + "end_time": "2024-01-13T08:51:17.878791500Z", + "start_time": "2024-01-13T08:51:17.851882800Z" } } }, @@ -344,7 +343,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 6, "outputs": [], "source": [ "def current2firing_time(x, tau=20., thr=0.2, tmax=1.0, epsilon=1e-7):\n", @@ -389,8 +388,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:21:27.323515Z", - "end_time": "2023-04-15T17:21:27.354804Z" + "end_time": "2024-01-13T08:50:19.098345900Z", + "start_time": "2024-01-13T08:50:19.091227600Z" } } }, @@ -405,7 +404,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "outputs": [], "source": [ "def loss_fun(predicts, targets):\n", @@ -433,8 +432,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:21:27.339329Z", - "end_time": "2023-04-15T17:21:27.511189Z" + "end_time": "2024-01-13T08:51:22.363907900Z", + "start_time": "2024-01-13T08:51:21.746626200Z" } } }, @@ -449,22 +448,17 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Train 0 epoch, use 49.9356 s, loss 13.577051162719727, acc 0.3795405924320221\n", - "Train 1 epoch, use 53.5827 s, loss 1.9439359903335571, acc 0.5677751302719116\n", - "Train 2 epoch, use 50.4796 s, loss 1.6432150602340698, acc 0.5903278589248657\n", - "Train 3 epoch, use 52.2995 s, loss 1.4753005504608154, acc 0.6055355072021484\n", - "Train 4 epoch, use 54.8472 s, loss 1.3759807348251343, acc 0.6247329115867615\n", - "Train 5 epoch, use 59.3077 s, loss 1.3128257989883423, acc 0.6393396258354187\n", - "Train 6 epoch, use 54.3296 s, loss 1.2489423751831055, acc 0.6562833786010742\n", - "Train 7 epoch, use 53.8313 s, loss 1.2068374156951904, acc 0.6707565188407898\n", - "Train 8 epoch, use 58.7923 s, loss 1.163095474243164, acc 0.6782184839248657\n", - "Train 9 epoch, use 56.4727 s, loss 1.1365898847579956, acc 0.6831930875778198\n" + "Train 0 epoch, use 81.7961 s, loss 1.7836289405822754, acc 0.26856303215026855\n", + "Train 1 epoch, use 110.9031 s, loss 1.716126561164856, acc 0.28009817004203796\n", + "Train 2 epoch, use 121.7257 s, loss 1.703003168106079, acc 0.28330329060554504\n", + "Train 3 epoch, use 152.4789 s, loss 1.6957000494003296, acc 0.2849225401878357\n", + "Train 4 epoch, use 180.2322 s, loss 1.6888805627822876, acc 0.2862913906574249\n" ] } ], @@ -477,24 +471,24 @@ " batch_size=256,\n", " nb_steps=100,\n", " nb_units=28 * 28),\n", - " num_epoch=10)" + " num_epoch=5)" ], "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:21:27.511189Z", - "end_time": "2023-04-15T17:30:31.500554Z" + "end_time": "2024-01-13T09:02:11.510933Z", + "start_time": "2024-01-13T08:51:23.628031300Z" } } }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 14, "outputs": [ { "data": { "text/plain": "
", - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjMAAAGxCAYAAACXwjeMAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAy5klEQVR4nO3deXzU9Z3H8fdvjkyuyYSEhBANV0JFoSKKWgUrrpaKR4vno55oH4+iFRFk21XrUUsrWe3W0pUVF9dFXUt13VXKHh7oVvGoK4Koa63IIUSOJlxJJsdkjt/+kcwkgSTkmJnfzPxez8djHpn5HTOfEB/O+/E9DdM0TQEAAKQph9UFAAAADAVhBgAApDXCDAAASGuEGQAAkNYIMwAAIK0RZgAAQFojzAAAgLRGmAEAAGnNZXUBiRaJRLR79255vV4ZhmF1OQAAoB9M01RjY6PKy8vlcPTd9pLxYWb37t2qqKiwugwAADAINTU1OvbYY/u8xtIws27dOv3yl7/Uhg0btGfPHr344ouaPXt2j9fedNNNWrFihX79619r4cKF/f4Mr9crqf0fo6CgIA5VAwCARGtoaFBFRUXse7wvloaZpqYmTZ48WTfeeKMuu+yyXq9bvXq1/vd//1fl5eUD/oxo11JBQQFhBgCANNOfISKWhplZs2Zp1qxZfV6za9cu3XrrrXrllVd04YUXJqkyAACQLlJ6zEwkEtF1112nH//4x5o4cWK/7gkEAgoEArHXDQ0NiSoPAACkgJSemv3ggw/K5XLptttu6/c91dXV8vl8sQeDfwEAyGwp2zKzYcMG/eY3v9HGjRsHNKX6rrvu0qJFi2KvowOIAABIVZFIRG1tbVaXkVRut1tOpzMu75WyYeatt95SbW2tRo0aFTsWDof113/911q6dKm+/PLLHu/zeDzyeDxJqhIAgKFpa2vT9u3bFYlErC4l6QoLC1VWVjbkdeBSNsxcd911Ou+887od+/a3v63rrrtON954o0VVAQAQP6Zpas+ePXI6naqoqDjq4nCZwjRNNTc3q7a2VpI0cuTIIb2fpWHG7/dry5Ytsdfbt2/Xpk2bVFRUpFGjRqm4uLjb9W63W2VlZTruuOOSXSoAAHEXCoXU3Nys8vJy5ebmWl1OUuXk5EiSamtrVVpaOqQuJ0vDzAcffKBzzjkn9jo61mXOnDl68sknLaoKAIDkCIfDkqSsrCyLK7FGNMAFg8H0DTMzZsyQaZr9vr63cTIAAKQzu+4dGK/f2x6dcwAAIGMRZgAAwICZpqm5c+eqqKhIhmGosLBwQHsnxlPKzmYCAACp6+WXX9aTTz6pN954Q+PGjZPD4YgN6pWkMWPGaOHChUkJOISZQYpETO061CKX09BIX87RbwAAIINs3bpVI0eO1Jlnnml1KXQzDdbfvvxnnfXQH/T4uu1WlwIAQFLdcMMNmj9/vnbu3CnDMDRmzBjNmDEj1gozY8YM7dixQ7fffrsMw0j4AGdaZgZp7PA8SdKWOr/FlQAAMoVpmmoJhi357By3s9+h4ze/+Y0qKyu1YsUKrV+/Xk6nU1dccUXs/AsvvKDJkydr7ty5+sEPfpCokmMIM4NUVZovSdpaS5gBAMRHSzCsE+57xZLP/tPibys3q3+xwOfzyev1yul0qqys7IjzRUVFcjqd8nq9PZ6PN7qZBqmqpD3M7DrUoqZAyOJqAACwL1pmBmlYXpaK8rJ0oKlN2+qa9PVjfVaXBABIczlup/60+NuWfXa6IswMQVVJvt5vOqCtdX7CDABgyAzD6HdXT6rLysqKbdeQaHQzDUFlx7iZLYybAQCgmzFjxmjdunXatWuX9u3bl9DPIswMQRVhBgCAHi1evFhffvmlKisrVVJSktDPyoy2LIvEwgzTswEANnP46r5vvPFGt/Pf+MY39NFHHyWlFlpmhiAaZr7c16RgOGJxNQAA2BNhZghGFmQrx+1UKGJqx/5mq8sBAMCWCDND4HAYqixtXwl4K11NAABYgjAzRNHF8xgEDACANQgzQ8S2BgCAoTJN0+oSLBGv35swM0TMaAIADJbT2b7qbltbm8WVWKO5uX28qdvtHtL7MDV7iCpLOltmTNNM+DbnAIDM4XK5lJubq7q6Orndbjkc9mhjME1Tzc3Nqq2tVWFhYSzUDRZhZohGF+fJ6TDU1BbW3oZWjfTlWF0SACBNGIahkSNHavv27dqxY4fV5SRdYWFhXHbVJswMUZbLodHFudpW16QttX7CDABgQLKysjR+/HjbdTW53e4ht8hEEWbioKokPxZmzhqf2CWbAQCZx+FwKDs72+oy0pY9OucSjD2aAACwDmEmDggzAABYhzATB7EZTUzPBgAg6QgzcVDZ0TKzz9+mQ832GsAFAIDVCDNxkO9xaaSvfeAWrTMAACQXYSZOGDcDAIA1CDNxUsmGkwAAWIIwEyeVtMwAAGAJwkycVJWw4SQAAFYgzMRJdMzMVwdb1BoMW1wNAAD2QZiJk+H5WfLluGWa0ra6JqvLAQDANggzcWIYRueMJrqaAABIGsJMHFUxowkAgKQjzMRRZWmeJGkrYQYAgKQhzMRRtJuJVYABAEgewkwcVZV4JUnb9jUpHDEtrgYAAHsgzMTRMcNy5HE51BaKqOZAs9XlAABgC4SZOHI6DI1jEDAAAElFmIkzpmcDAJBchJk4qyxpn9FEywwAAMlhaZhZt26dLr74YpWXl8swDK1evTp2LhgM6o477tDXv/515eXlqby8XNdff712795tXcH9wIwmAACSy9Iw09TUpMmTJ2vZsmVHnGtubtbGjRt17733auPGjXrhhRe0efNmfec737Gg0v6r6rJ7tmkyowkAgERzWfnhs2bN0qxZs3o85/P5tHbt2m7HHnnkEZ122mnauXOnRo0alYwSB2zs8Dw5DKmxNaS6xoBKC7KtLgkAgIyWVmNm6uvrZRiGCgsLrS6lVx6XU6OKciUxbgYAgGRImzDT2tqqO++8U1dffbUKCgp6vS4QCKihoaHbI9kqS5jRBABAsqRFmAkGg/re976nSCSiRx99tM9rq6ur5fP5Yo+KiookVdmp67gZAACQWCkfZoLBoK688kpt375da9eu7bNVRpLuuusu1dfXxx41NTVJqrRTJTOaAABIGksHAB9NNMh88cUX+sMf/qDi4uKj3uPxeOTxeJJQXe9omQEAIHksDTN+v19btmyJvd6+fbs2bdqkoqIilZeX6/LLL9fGjRv1n//5nwqHw9q7d68kqaioSFlZWVaVfVTRMPOXhoAaWoMqyHZbXBEAAJnL0m6mDz74QFOmTNGUKVMkSYsWLdKUKVN033336auvvtKaNWv01Vdf6aSTTtLIkSNjj3fffdfKso+qINutUm9769BWWmcAAEgoS1tmZsyY0efCcum86FxlSb5qGwPaUuvXlFHDrC4HAICMlfIDgNNV57YGTRZXAgBAZiPMJAiDgAEASA7CTIKw4SQAAMlBmEmQaJjZsb9JgVDY4moAAMhchJkEKfV6lO9xKWJKX+5rtrocAAAyFmEmQQzDiK0EzLgZAAAShzCTQFUljJsBACDRCDMJxIwmAAASjzCTQIQZAAASjzCTQNEws22fX5FI+q5mDABAKiPMJFDFsBxlOR1qDUa061CL1eUAAJCRCDMJ5HI6NGZ4riS6mgAASBTCTIKxEjAAAIlFmEmw6PRsWmYAAEgMwkyCsXAeAACJRZhJsNj07Dq/TJMZTQAAxBthJsHGDc+XYUiHmoPa39RmdTkAAGQcwkyC5WQ5dUxhjiRpK11NAADEHWEmCbp2NQEAgPgizCQBM5oAAEgcwkwSsEcTAACJQ5hJguj0bMbMAAAQf4SZJIh2M+2ub1VTIGRxNQAAZBbCTBIMy8tScV6WJGlbXZPF1QAAkFkIM0kSWwm4rtHiSgAAyCyEmSRhEDAAAIlBmEkSpmcDAJAYhJkkYcNJAAASgzCTJNFuph37mxUMRyyuBgCAzEGYSZJyX7Zys5wKRUzt2N9sdTkAAGQMwkySGIahSsbNAAAQd4SZJIp2NW1lw0kAAOKGMJNETM8GACD+CDNJVFmSJ4kwAwBAPBFmkqhrN5NpmhZXAwBAZiDMJNHo4jy5HIaa28LaU99qdTkAAGQEwkwSuZ0OjS7OlURXEwAA8UKYSTIGAQMAEF+EmSSLrTXD9GwAAOKCMJNktMwAABBfhJkki4aZbbTMAAAQF4SZJIt2M+3zt+lQc5vF1QAAkP4IM0mW53Gp3Jctia4mAADiwdIws27dOl188cUqLy+XYRhavXp1t/Omaer+++9XeXm5cnJyNGPGDH366afWFBtHlYybAQAgbiwNM01NTZo8ebKWLVvW4/mHHnpIDz/8sJYtW6b169errKxM3/rWt9TY2JjkSuOL3bMBAIgfl5UfPmvWLM2aNavHc6ZpaunSpbr77rt16aWXSpKeeuopjRgxQqtWrdJNN92UzFLjKjajiUHAAAAMWcqOmdm+fbv27t2rmTNnxo55PB6dffbZevfddy2sbOi67tEEAACGxtKWmb7s3btXkjRixIhux0eMGKEdO3b0el8gEFAgEIi9bmhoSEyBQxANM18dbFFrMKxst9PiigAASF8p2zITZRhGt9emaR5xrKvq6mr5fL7Yo6KiItElDlhxXpYKc90yTVpnAAAYqpQNM2VlZZI6W2iiamtrj2it6equu+5SfX197FFTU5PQOgfDMAwGAQMAECcpG2bGjh2rsrIyrV27Nnasra1Nb775ps4888xe7/N4PCooKOj2SEVVHWFmK2EGAIAhsXTMjN/v15YtW2Kvt2/frk2bNqmoqEijRo3SwoULtWTJEo0fP17jx4/XkiVLlJubq6uvvtrCquOjcxBwk8WVAACQ3iwNMx988IHOOeec2OtFixZJkubMmaMnn3xSf/M3f6OWlhbdcsstOnjwoE4//XS9+uqr8nq9VpUcN2w4CQBAfBimaZpWF5FIDQ0N8vl8qq+vT6kup5oDzTrroT8oy+nQnxZ/Wy5nyvb4AQCQdAP5/uYb1CLHFObI43KoLRxRzcEWq8sBACBtEWYs4nAYGseMJgAAhowwYyHGzQAAMHSEGQvFpmezcB4AAINGmLEQLTMAAAwdYcZCsbVmav3K8EllAAAkDGHGQmOG58phSI2BkGobA0e/AQAAHIEwYyGPy6lRRbmS6GoCAGCwCDMW69zWgDADAMBgEGYsVskgYAAAhoQwY7EqFs4DAGBICDMWY3o2AABDQ5ixWLSbqbYxoIbWoMXVAACQfggzFivIdqvU65FE6wwAAINBmEkBXRfPAwAAA0OYSQGxcTNMzwYAYMAIMymAlhkAAAaPMJMCmJ4NAMDgEWZSQHRG084DzWoNhi2uBgCA9EKYSQGlXo+8HpcipvTl/iarywEAIK0QZlKAYRix1pmttYQZAAAGgjCTIlgJGACAwSHMpAimZwMAMDiEmRRRyYwmAAAGhTCTIqItM9vq/ApHTIurAQAgfRBmUkTFsBxlOR0KhCLafajF6nIAAEgbhJkU4XI6NHZ4niS6mgAAGAjCTAphRhMAAANHmEkhlYQZAAAGjDCTQipLOrqZmJ4NAEC/EWZSSNduJtNkRhMAAP1BmEkhlSX5MgypviWo/U1tVpcDAEBaIMykkGy3U8cOy5HEuBkAAPqLMJNiqlgJGACAASHMpBimZwMAMDCEmRQT3aNpKzOaAADoF8JMiqFlBgCAgSHMpJhomNlT3yp/IGRxNQAApD7CTIopzM3S8PwsSe07aAMAgL4RZlJQJTOaAADoN8JMCmKPJgAA+o8wk4JYawYAgP4jzKSg6CBgpmcDAHB0KR1mQqGQ7rnnHo0dO1Y5OTkaN26cFi9erEgkYnVpCRUNMzv2NysYzuzfFQCAoXJZXUBfHnzwQT322GN66qmnNHHiRH3wwQe68cYb5fP5tGDBAqvLS5iRvmzlZTnV1BbWjv1Nqir1Wl0SAAApK6XDzB//+Ed997vf1YUXXihJGjNmjH73u9/pgw8+sLiyxDIMQ5Wl+fr4q3ptqfUTZgAA6ENKdzNNnz5dr7/+ujZv3ixJ+uijj/T222/rggsusLiyxGN6NgAA/ZPSLTN33HGH6uvrNWHCBDmdToXDYT3wwAO66qqrer0nEAgoEAjEXjc0NCSj1LhjWwMAAPonpVtmnnvuOT3zzDNatWqVNm7cqKeeekp/93d/p6eeeqrXe6qrq+Xz+WKPioqKJFYcP50bTjZZXAkAAKnNME3TtLqI3lRUVOjOO+/UvHnzYsd+8Ytf6JlnntGf//znHu/pqWWmoqJC9fX1KigoSHjN8bKl1q/zHn5TuVlO/d/935bDYVhdEgAASdPQ0CCfz9ev7++U7mZqbm6Ww9G98cjpdPY5Ndvj8cjj8SS6tIQbXZwrl8NQc1tYexpadUxhjtUlAQCQklI6zFx88cV64IEHNGrUKE2cOFEffvihHn74YX3/+9+3urSEczsdGjM8T1tq/dpS6yfMAADQi5QOM4888ojuvfde3XLLLaqtrVV5ebluuukm3XfffVaXlhSVJZ1h5uyvlVhdDgAAKWlQYaampkaGYejYY4+VJL3//vtatWqVTjjhBM2dOzduxXm9Xi1dulRLly6N23umk6rSfL3y6V+Y0QQAQB8GNZvp6quv1h/+8AdJ0t69e/Wtb31L77//vn7yk59o8eLFcS3QztijCQCAoxtUmPm///s/nXbaaZKkf/3Xf9WkSZP07rvvatWqVXryySfjWZ+tVZW0r/y7lZYZAAB6NagwEwwGYzOGXnvtNX3nO9+RJE2YMEF79uyJX3U2N64kT5K0v6lNB5vaLK4GAIDUNKgwM3HiRD322GN66623tHbtWp1//vmSpN27d6u4uDiuBdpZnselcl+2JGkLXU0AAPRoUGHmwQcf1D/+4z9qxowZuuqqqzR58mRJ0po1a2LdT4iPSrY1AACgT4OazTRjxgzt27dPDQ0NGjZsWOz43LlzlZubG7fi0D4I+K0v9jFuBgCAXgyqZaalpUWBQCAWZHbs2KGlS5fq888/V2lpaVwLtLvYhpN0MwEA0KNBhZnvfve7evrppyVJhw4d0umnn65f/epXmj17tpYvXx7XAu2uqoRuJgAA+jKoMLNx40adddZZkqR/+7d/04gRI7Rjxw49/fTT+vu///u4Fmh30ZaZXYda1NIWtrgaAABSz6DCTHNzs7ze9jVQXn31VV166aVyOBz6xje+oR07dsS1QLsrystSYa5bpsnieQAA9GRQYaaqqkqrV69WTU2NXnnlFc2cOVOSVFtbe9RtujEwhmHEupoIMwAAHGlQYea+++7Tj370I40ZM0annXaazjjjDEntrTRTpkyJa4Hosq0B42YAADjCoKZmX3755Zo+fbr27NkTW2NGks4991xdcsklcSsO7ZjRBABA7wYVZiSprKxMZWVl+uqrr2QYho455hgWzEsQFs4DAKB3g+pmikQiWrx4sXw+n0aPHq1Ro0apsLBQP//5zxWJROJdo+1Fx8xs39ekUJh/XwAAuhpUy8zdd9+tJ554Qn/7t3+radOmyTRNvfPOO7r//vvV2tqqBx54IN512toxhTnKdjvUGoxo54FmjesINwAAYJBh5qmnntI//dM/xXbLlqTJkyfrmGOO0S233EKYiTOHw9C44fn6054Gban1E2YAAOhiUN1MBw4c0IQJE444PmHCBB04cGDIReFIsRlNdU0WVwIAQGoZVJiZPHmyli1bdsTxZcuW6cQTTxxyUThSFYOAAQDo0aC6mR566CFdeOGFeu2113TGGWfIMAy9++67qqmp0X//93/Hu0aI6dkAAPRmUC0zZ599tjZv3qxLLrlEhw4d0oEDB3TppZfq008/1cqVK+NdIyRVlnQunGeapsXVAACQOgwzjt+MH330kU4++WSFw6mzIWJDQ4N8Pp/q6+vTequFQCis4+99WRFTeu+uc1Xmy7a6JAAAEmYg39+DaplB8nlcTo0uzpPEHk0AAHRFmEkj0a4mBgEDANCJMJNGmNEEAMCRBjSb6dJLL+3z/KFDh4ZSC46CMAMAwJEGFGZ8Pt9Rz19//fVDKgi9qyxpHzPD9GwAADoNKMww7dpa0d2z6xoDqm8JypfjtrgiAACsx5iZNFKQ7daIAo8kZjQBABBFmEkzjJsBAKA7wkyaqeqyEjAAACDMpJ1KWmYAAOiGMJNmoi0zzGgCAKAdYSbNRMfM1BxoVmswdfbAAgDAKoSZNFPi9cib7VLElL7c32R1OQAAWI4wk2YMw2BGEwAAXRBm0lAVG04CABBDmElDzGgCAKATYSYN0TIDAEAnwkwaio6Z2b6vSeGIaXE1AABYizCThiqKcpXlcigQimjXwRarywEAwFKEmTTkdBgaNzxPkrSlrtHiagAAsBZhJk1VMm4GAABJaRBmdu3apWuvvVbFxcXKzc3VSSedpA0bNlhdluWY0QQAQDuX1QX05eDBg5o2bZrOOeccvfTSSyotLdXWrVtVWFhodWmWY+E8AADapXSYefDBB1VRUaGVK1fGjo0ZM8a6glJIdHr21rommaYpwzAsrggAAGukdDfTmjVrNHXqVF1xxRUqLS3VlClT9Pjjj1tdVkoYV5Inw5DqW4La52+zuhwAACyT0mFm27ZtWr58ucaPH69XXnlFN998s2677TY9/fTTvd4TCATU0NDQ7ZGJst1OVQzLlURXEwDA3lI6zEQiEZ188slasmSJpkyZoptuukk/+MEPtHz58l7vqa6uls/niz0qKiqSWHFyVZZEp2cTZgAA9pXSYWbkyJE64YQTuh07/vjjtXPnzl7vueuuu1RfXx971NTUJLpMy0QHAW+lZQYAYGMpPQB42rRp+vzzz7sd27x5s0aPHt3rPR6PRx6PJ9GlpYRYmKFlBgBgYyndMnP77bfrvffe05IlS7RlyxatWrVKK1as0Lx586wuLSUwPRsAgBQPM6eeeqpefPFF/e53v9OkSZP085//XEuXLtU111xjdWkpoarEK0naU98qfyBkcTUAAFgjpbuZJOmiiy7SRRddZHUZKcmX69bwfI/2+QPaWuvX5IpCq0sCACDpUrplBkcXm9FEVxMAwKYIM2kuNm6GQcAAAJsizKQ5pmcDAOyOMJPmaJkBANgdYSbNRcPMjv3NagtFLK4GAIDkI8ykubKCbOVlORWOmNqxv8nqcgAASDrCTJozDEOVLJ4HALAxwkwGqCohzAAA7IswkwEq2aMJAGBjhJkMwIwmAICdEWYyQOdaM02KREyLqwEAILkIMxlgVFGuXA5DLcGwdte3WF0OAABJRZjJAG6nQ2OGs0cTAMCeCDMZIjqjaWsda80AAOyFMJMhqlhrBgBgU4SZDMGGkwAAuyLMZAimZwMA7IowkyHGlbQPAD7Q1KYDTW0WVwMAQPIQZjJEbpZLxxTmSGLcDADAXggzGYRtDQAAdkSYySBsOAkAsCPCTAZhejYAwI4IMxmksoRVgAEA9kOYySDRlpldh1rU3BayuBoAAJKDMJNBivM9GpbrliRtY1sDAIBNEGYyTBUzmgAANkOYyTAMAgYA2A1hJsNUMj0bAGAzhJkMU0nLDADAZggzGSa6cN6X+5sUCkcsrgYAgMQjzGSYYwpzlON2Khg2tfNAs9XlAACQcISZDONwGLEdtOlqAgDYAWEmA8VmNDE9GwBgA4SZDMSMJgCAnRBmMlBs4TzCDADABggzGahzFeAmmaZpcTUAACQWYSYDjSnOk9NhyB8I6S8NAavLAQAgoQgzGSjL5dDoolxJjJsBAGQ+wkyG6lwJuNHiSgAASCzCTIaKzWhiejYAIMMRZjIUu2cDAOyCMJOhOsNMk8WVAACQWISZDFXZsaXBPn9A9c1Bi6sBACBx0irMVFdXyzAMLVy40OpSUp43262ygmxJjJsBAGS2tAkz69ev14oVK3TiiSdaXUraYCVgAIAdpEWY8fv9uuaaa/T4449r2LBhVpeTNqJdTbTMAAAyWVqEmXnz5unCCy/UeeedZ3UpaYUZTQAAO3BZXcDRPPvss9q4caPWr1/fr+sDgYACgc4l/BsaGhJVWsqrjO3RRJgBAGSulG6Zqamp0YIFC/TMM88oOzu7X/dUV1fL5/PFHhUVFQmuMnVFW2ZqDjSrNRi2uBoAABLDMFN4W+XVq1frkksukdPpjB0Lh8MyDEMOh0OBQKDbOannlpmKigrV19eroKAgabWnAtM0Nflnr6qhNaSXFpyl40fa6/cHAKSvhoYG+Xy+fn1/p3Q307nnnqtPPvmk27Ebb7xREyZM0B133HFEkJEkj8cjj8eTrBJTmmEYqizN14c7D2lLrZ8wAwDISCkdZrxeryZNmtTtWF5enoqLi484jp5VlXSGGQAAMlFKj5nB0MVmNDEIGACQoVK6ZaYnb7zxhtUlpBUWzgMAZDpaZjJcNMxs29ekcCRlx3oDADBohJkMd+ywXGW5HGoLRfTVwWarywEAIO4IMxnO6TA0bnjHtgZ0NQEAMhBhxgYq2dYAAJDBCDM2UFVCmAEAZC7CjA1UsUcTACCDEWZsoOvu2Sm8ewUAAINCmLGBscPzZBhSQ2tIdf7A0W8AACCNEGZsINvtVMWwXEmMmwEAZB7CjE2wEjAAIFMRZmyicxBwk8WVAAAQX4QZm2B6NgAgUxFmbIKF8wAAmYowYxPRlpm9Da1qbA1aXA0AAPFDmLEJX65bw/M9khg3AwDILIQZG6kqZcNJAEDmIczYCNsaAAAyEWHGRpjRBADIRIQZG6kq9Upi4TwAQGYhzNhIZceYmR0HmtUWilhcDQAA8UGYsZGygmzle1wKR0x9uZ8ZTQCAzECYsRHDMFRZ0t46Q1cTACBTEGZshpWAAQCZhjBjM9Hp2VuYng0AyBCEGZupZHo2ACDDEGZspuvCeZGIaXE1AAAMHWHGZkYX5crtNNQajGjXoRarywEAYMgIMzbjcjo0prhjRhPjZgAAGYAwY0NVzGgCAGQQwowNseEkACCTEGZsiBlNAIBMQpixIbqZAACZhDBjQ+M6tjQ42BzUfn/A4moAABgawowN5Wa5dExhjiRpax0bTgIA0hthxqboagIAZArCjE0RZgAAmYIwY1OxGU1MzwYApDnCjE3F1pqhZQYAkOYIMzYVDTO7DrWouS1kcTUAAAweYcamivKyVJSXJUnaxowmAEAaI8zYWBUrAQMAMgBhxsYqS9sXzyPMAADSGWHGxtijCQCQCVI6zFRXV+vUU0+V1+tVaWmpZs+erc8//9zqsjJGbK0ZpmcDANJYSoeZN998U/PmzdN7772ntWvXKhQKaebMmWpqYsBqPETDzI79TQqGIxZXAwDA4LisLqAvL7/8crfXK1euVGlpqTZs2KBvfvObFlWVOcp9OcpxO9USDGvngeZYtxMAAOkkpVtmDldfXy9JKioqsriSzOBwGAwCBgCkvbQJM6ZpatGiRZo+fbomTZrU63WBQEANDQ3dHugdg4ABAOkupbuZurr11lv18ccf6+233+7zuurqav3sZz9LUlXpL7rWzFPvfqnNf2nU+NJ8VZXmq6rUq9HFuXI70ybvAgBsyjBN07S6iKOZP3++Vq9erXXr1mns2LF9XhsIBBQIBGKvGxoaVFFRofr6ehUUFCS61LTzwZcHdOU//lGRHv4rcDsNjSnOU1VpvsaX5quyNF/jS70aV5KnbLcz+cUCAGyjoaFBPp+vX9/fKR1mTNPU/Pnz9eKLL+qNN97Q+PHjB/weA/nHsKvdh1r06e4Gban164vaRm2p9WtLrV/NbeEerzcMaVRRrqpKoq04nQ9vtjvJ1QMAMlHGhJlbbrlFq1at0u9//3sdd9xxseM+n085OTn9eg/CzOCYpqnd9a3tAecvjdpa59cXf/Hri1q/6luCvd5XVpCt8SPyVVmSr/Ej8lVVkq/xI7yxfaAAAOiPjAkzhmH0eHzlypW64YYb+vUehJn4Mk1T+/xtHa03jR2tOe0tObWNgV7vK8rLirXejI/99GpEgafXvzMAwL4yJszEA2Emeepbgj2GnK8OtvR6j9fjUmUPIeeYYTlyOgg5AGBXhJkuCDPWa24LaVtdU2w8zhd/8WtLnV879jcr3NPIY0kel0OVJYeFnBH5Gl2cxwwrALABwkwXhJnUFQiFtWN/c3u46TL4eNu+JrWFet5eweUwNGZ4XmzwcXR8TmVJvnKymGEFAJliIN/fabPODDKPx+XU10Z49bUR3m7HwxFTNQeaY91UX9Q2amvH86a2cGy2lT7tvMcwpGOH5eiYwhwNz/doeL5HJV6PSvI9Gu7Nih0bnu9RlouWHQDIJLTMIG2Ypqk99a2xkNN1bM6h5t5nWB3Ol+PW8PyOgBMNPPlZKvF2Bp7h3vZjHhetPQBgBbqZuiDMZD7TNLW/qX2G1V8aWlXXGNA+f5v2+QPa5w90vA5ov79NoV7G6PTGm+2KhZxo6Im2+nQNPcPzPSwkCABxRDcTbMUwjFiLSl8iEVP1LcH2gBMLOR2hpyPw7PO3qa4xoP1NAQXDphpbQ2psbR/AfDRej6tLyMnq1t01/LAgRPABgPghzMA2HA5Dw/KyNCwvS+MPG6dzONPsEnwa27q18ERDTzQE1fk7gk8gpMZASNv2HT345MeCT/fxPNFjhblZyve42h/Z7T8Z6wMAPSPMAD0wDEOFue2hoqq072tN01RDS0h1/sARXVv7Gtu6BaA6f0BtoYj8gZD8gZC29yP4RGU5HbFgc3jQyfO45O36vI9z+R4Xa/gAyCiEGWCIDMOQL9ctX65bVaX5fV5rmqYaWkNduraOHNtT529TY0tQjYGQ/K0htQTb98hqC0d0oKlNB5rahlxzbpaz59DT8ToaerzZLuVltR/zRsNQdud1OW4nKzgDsBxhBkgiwzDky3HLl+NWZUnfwScqFI6oqS0sfyCkpkD7GB5/R9Bp6uja8reG1NTW9VxQTYFw+7lAx/PWoILh9gHQzW1hNbeFVdfHFhT94TAUC0F5XYJR9JGb5VS22ymP2ymPy6Fst1PZboeyXU55On5Gj3lcHec6rvV0HM9yOghMAPpEmAFSnMvpkC/HIV/O0HckD4TCagqE5W8NqTEQPCIENXUEo8bo80Dv5yKmFDEVGySdKIahziDk6h58uockp7Jdjm4hqWuA6vnansOVx+WQg644IG0QZgAb8bic8ricQ97F3DRNtQTD3YNPDyGopS2s1mBYgVBErcGwWkMRBTp+tgbDCnQ9F4woEGr/2RoKK7pohGmq/VgwIqn/6wkNVZazIxgd3nJ0WGtS7JrDWpZirVBuZ2f46nJNT+9LgAIGhzADYMAMw1Bulku5WS4dZXz0oJimqbZwJBZ0AsFI91DUNfgEw2oNdVwT6jwXvafX+zqu6fo+XdchagtH1BaOJLTV6XBdA9Th3XJdjx0eoLqHpM4A1dna1PmebqdDWR0/XU5DWc725wwKRzojzABIOYZhxFqRCrKH3r3WX6EuASrWihQLSUeGn9aurUxdA1MPASt2fbD9M6LXRMcxSdYEqCiHIbk7go3bacSeZ7kccjk6Xrscyuo453J2Pu+81pDL0fHa1RmUuoamw9/f7TQ63rfjczqe93Ud4QuHI8wAQAdXx5d0nid5/2sMR8zDwtBhAaprqOoSoAJdrokGqM4g1v369uPtQSwUNhUMR45YDTtiqv2zetnkNdVEw1dWR8iKBp9YEHJ1CWRdg5HrsNexlqoernc5ur1n9LrOz+zyuksdhwc3BrAnHmEGACzkdBjK87iU1/cC1nEXiZgKRiIKhk2FOlqEgmFTwVBEwY7X0eDT9VwoElFbl+uC0XPh6H0dYanjeFs40nltpOt9HeeO+JyIgiGz/XNCne/dZ/ga2qS8hHMf3oLVEZRcjvaWLKfDkMtpyGEYcjkMObs8XN2etw9Mjx0zDDmd7a8Pv9flMLpc65DTITkdjsOOt7+Hy9nl/brV4uijlu7v4812x2WSwmARZgDAhhwOQx6HU0lshBqSSMRUKNIRekKRWBDrGr5ioSp02Otw92AUuz7UGaLaDgtn3UJYl+AVPOy+WJjr+My2cESH73jY/rlhSWFL/u2S4YczKnXH+RMs+/w0+c8YAGBnDoehLIehLJcj6a1YAxWOdAk7XUJU15anaICKmO0hLRrWwpGIwhEpFIkoHDFjj1DEbL823HHM7Dgejj6PHPY+h9172PHYZ5lqvzdsxmqJvm/X1533tdd3+Oe5ndZut0KYAQAgjtq7YpxsKJtE7FwHAADSGmEGAACkNcIMAABIa4QZAACQ1ggzAAAgrRFmAABAWiPMAACAtEaYAQAAaY0wAwAA0hphBgAApDXCDAAASGuEGQAAkNYIMwAAIK0RZgAAQFpzWV1AopmmKUlqaGiwuBIAANBf0e/t6Pd4XzI+zDQ2NkqSKioqLK4EAAAMVGNjo3w+X5/XGGZ/Ik8ai0Qi2r17t7xerwzDiOt7NzQ0qKKiQjU1NSooKIjre2Pg+HukFv4eqYW/R2rh73F0pmmqsbFR5eXlcjj6HhWT8S0zDodDxx57bEI/o6CggP8YUwh/j9TC3yO18PdILfw9+na0FpkoBgADAIC0RpgBAABpjTAzBB6PRz/96U/l8XisLgXi75Fq+HukFv4eqYW/R3xl/ABgAACQ2WiZAQAAaY0wAwAA0hphBgAApDXCzCA9+uijGjt2rLKzs3XKKaforbfesrokW6qurtapp54qr9er0tJSzZ49W59//rnVZaFDdXW1DMPQwoULrS7F1nbt2qVrr71WxcXFys3N1UknnaQNGzZYXZYthUIh3XPPPRo7dqxycnI0btw4LV68WJFIxOrS0hphZhCee+45LVy4UHfffbc+/PBDnXXWWZo1a5Z27txpdWm28+abb2revHl67733tHbtWoVCIc2cOVNNTU1Wl2Z769ev14oVK3TiiSdaXYqtHTx4UNOmTZPb7dZLL72kP/3pT/rVr36lwsJCq0uzpQcffFCPPfaYli1bps8++0wPPfSQfvnLX+qRRx6xurS0xmymQTj99NN18skna/ny5bFjxx9/vGbPnq3q6moLK0NdXZ1KS0v15ptv6pvf/KbV5diW3+/XySefrEcffVS/+MUvdNJJJ2np0qVWl2VLd955p9555x1aj1PERRddpBEjRuiJJ56IHbvsssuUm5urf/mXf7GwsvRGy8wAtbW1acOGDZo5c2a34zNnztS7775rUVWIqq+vlyQVFRVZXIm9zZs3TxdeeKHOO+88q0uxvTVr1mjq1Km64oorVFpaqilTpujxxx+3uizbmj59ul5//XVt3rxZkvTRRx/p7bff1gUXXGBxZekt4/dmird9+/YpHA5rxIgR3Y6PGDFCe/futagqSO2bki1atEjTp0/XpEmTrC7Htp599llt3LhR69evt7oUSNq2bZuWL1+uRYsW6Sc/+Ynef/993XbbbfJ4PLr++uutLs927rjjDtXX12vChAlyOp0Kh8N64IEHdNVVV1ldWlojzAzS4Ttwm6YZ9125MTC33nqrPv74Y7399ttWl2JbNTU1WrBggV599VVlZ2dbXQ4kRSIRTZ06VUuWLJEkTZkyRZ9++qmWL19OmLHAc889p2eeeUarVq3SxIkTtWnTJi1cuFDl5eWaM2eO1eWlLcLMAA0fPlxOp/OIVpja2tojWmuQPPPnz9eaNWu0bt26hO+Sjt5t2LBBtbW1OuWUU2LHwuGw1q1bp2XLlikQCMjpdFpYof2MHDlSJ5xwQrdjxx9/vP793//doors7cc//rHuvPNOfe9735Mkff3rX9eOHTtUXV1NmBkCxswMUFZWlk455RStXbu22/G1a9fqzDPPtKgq+zJNU7feeqteeOEF/c///I/Gjh1rdUm2du655+qTTz7Rpk2bYo+pU6fqmmuu0aZNmwgyFpg2bdoRyxVs3rxZo0ePtqgie2tubpbD0f2r1+l0MjV7iGiZGYRFixbpuuuu09SpU3XGGWdoxYoV2rlzp26++WarS7OdefPmadWqVfr9738vr9cbazHz+XzKycmxuDr78Xq9R4xXysvLU3FxMeOYLHL77bfrzDPP1JIlS3TllVfq/fff14oVK7RixQqrS7Oliy++WA888IBGjRqliRMn6sMPP9TDDz+s73//+1aXlt5MDMo//MM/mKNHjzazsrLMk08+2XzzzTetLsmWJPX4WLlypdWlocPZZ59tLliwwOoybO0//uM/zEmTJpkej8ecMGGCuWLFCqtLsq2GhgZzwYIF5qhRo8zs7Gxz3Lhx5t13320GAgGrS0trrDMDAADSGmNmAABAWiPMAACAtEaYAQAAaY0wAwAA0hphBgAApDXCDAAASGuEGQAAkNYIMwAAIK0RZgDYjmEYWr16tdVlAIgTwgyApLrhhhtkGMYRj/PPP9/q0gCkKTaaBJB0559/vlauXNntmMfjsagaAOmOlhkASefxeFRWVtbtMWzYMEntXUDLly/XrFmzlJOTo7Fjx+r555/vdv8nn3yiv/qrv1JOTo6Ki4s1d+5c+f3+btf88z//syZOnCiPx6ORI0fq1ltv7XZ+3759uuSSS5Sbm6vx48drzZo1if2lASQMYQZAyrn33nt12WWX6aOPPtK1116rq666Sp999pkkqbm5Weeff76GDRum9evX6/nnn9drr73WLawsX75c8+bN09y5c/XJJ59ozZo1qqqq6vYZP/vZz3TllVfq448/1gUXXKBrrrlGBw4cSOrvCSBOrN62G4C9zJkzx3Q6nWZeXl63x+LFi03TNE1J5s0339ztntNPP9384Q9/aJqmaa5YscIcNmyY6ff7Y+f/67/+y3Q4HObevXtN0zTN8vJy8+677+61BknmPffcE3vt9/tNwzDMl156KW6/J4DkYcwMgKQ755xztHz58m7HioqKYs/POOOMbufOOOMMbdq0SZL02WefafLkycrLy4udnzZtmiKRiD7//HMZhqHdu3fr3HPP7bOGE088MfY8Ly9PXq9XtbW1g/2VAFiIMAMg6fLy8o7o9jkawzAkSaZpxp73dE1OTk6/3s/tdh9xbyQSGVBNAFIDY2YApJz33nvviNcTJkyQJJ1wwgnatGmTmpqaYuffeecdORwOfe1rX5PX69WYMWP0+uuvJ7VmANahZQZA0gUCAe3du7fbMZfLpeHDh0uSnn/+eU2dOlXTp0/Xb3/7W73//vt64oknJEnXXHONfvrTn2rOnDm6//77VVdXp/nz5+u6667TiBEjJEn333+/br75ZpWWlmrWrFlqbGzUO++8o/nz5yf3FwWQFIQZAEn38ssva+TIkd2OHXfccfrzn/8sqX2m0bPPPqtbbrlFZWVl+u1vf6sTTjhBkpSbm6tXXnlFCxYs0Kmnnqrc3Fxddtllevjhh2PvNWfOHLW2turXv/61fvSjH2n48OG6/PLLk/cLAkgqwzRN0+oiACDKMAy9+OKLmj17ttWlAEgTjJkBAABpjTADAADSGmNmAKQUer4BDBQtMwAAIK0RZgAAQFojzAAAgLRGmAEAAGmNMAMAANIaYQYAAKQ1wgwAAEhrhBkAAJDWCDMAACCt/T9DtJiTefsVQQAAAABJRU5ErkJggg==\n" + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkAAAAGwCAYAAABB4NqyAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABD50lEQVR4nO3deXRV9b3//9c5J3PIyJABMgAqo4QQJKAgUKmVelHEoVVAsFJFbeuwur5fqUNv7a/S9nbiXr5i0SDOthVB71UseksCCogMQRBEEzKRwQCZE8hwzv79ceC0MQGSnCT7DM/HWnstzz6fc/L++FHy4vP57L0thmEYAgAA8CNWswsAAADobwQgAADgdwhAAADA7xCAAACA3yEAAQAAv0MAAgAAfocABAAA/E6A2QV4IofDobKyMkVERMhisZhdDgAA6ALDMFRfX6/ExERZrRee4yEAdaKsrExJSUlmlwEAAHqgpKREw4YNu2AbAlAnIiIiJDn/BUZGRppcDQAA6Iq6ujolJSW5fo9fCAGoE+eWvSIjIwlAAAB4ma5sX2ETNAAA8DsEIAAA4HcIQAAAwO+wBwgAAC9lt9vV2tpqdhn9Kigo6KKXuHcFAQgAAC9jGIYqKipUU1Njdin9zmq1avjw4QoKCnLrewhAAAB4mXPhZ8iQIQoLC/Obm/aeu1FxeXm5kpOT3eo3AQgAAC9it9td4WfgwIFml9PvBg8erLKyMrW1tSkwMLDH38MmaAAAvMi5PT9hYWEmV2KOc0tfdrvdre8hAAEA4IX8Zdnrm3qr3wQgAADgdwhAAADA7xCAAABAvzAMQ/fcc49iY2NlsVgUHR2thx56yJRauAqsn5XXnlZNU6vGJPCQVQCAf3n//fe1fv16ZWdna8SIEbJarQoNDXW9n5qaqoceeqhfQhEBqB9tPliun7yxX+OHRumt+6702w1sAAD/lJ+fr4SEBF155ZVml0IA6k8ZqTGyWCzaX1yjTwqqNHWE/92/AQDQ+wzD0OlW9y4L74nQQFuX/zK/dOlSvfjii5KcV3KlpKQoNTVVEydO1J/+9CfNmjVLRUVFevjhh/Xwww9LcvarrxCA+tGQiBDdNnmYXtlVrDXZ+QQgAECvON1q19gn/97vP/fwU99RWFDXosSqVas0cuRIrV27Vp9++qlsNptuvfVW1/tvvfWW0tLSdM899+iHP/xhX5XswibofnbPjJGyWqScL0/oUGmt2eUAANAvoqKiFBERIZvNpvj4eA0ePLjd+7GxsbLZbIqIiFB8fLzi4+P7tB5mgPpZ8sAwzUtL1Nu5ZXo2J1+r75hkdkkAAC8XGmjT4ae+Y8rP9VYEIBMsnzlSb+eW6b2D5So82ajUQeFmlwQA8GIWi6XLS1FwYgnMBGMSIvWt0UPkMKQ/bztmdjkAAHiEoKAgt5/x1VUEIJPcP2ukJGnD3uP6uu6MydUAAGC+1NRUbdu2TaWlpTp58mSf/iwCkEkmp8bqitQYtdgdyvqowOxyAAAw3VNPPaXCwkKNHDmywybp3mYx+vIiey9VV1enqKgo1dbWKjKy7+7YvPWLSt21/lOFB9m049FrFBUW2Gc/CwDgG86cOaOCggINHz5cISEhZpfT7y7U/+78/jZ1Bmjbtm2aN2+eEhMTZbFYtGnTpgu2X7p0qSwWS4dj3Lhx7dr96U9/0qhRoxQaGqqkpCQ9/PDDOnPG85aZZo0arNHxEWpsseulnYVmlwMAgN8wNQA1NjYqLS1Nq1ev7lL7VatWqby83HWUlJQoNja23Y2UXn31VT366KP6+c9/riNHjigrK0t/+ctftGLFir7qRo9ZLBbdd3Yv0As7CnW6pf/v4gkAgD8y9Zq5uXPnau7cuV1uHxUVpaioKNfrTZs2qbq6WnfddZfr3M6dO3XVVVfpjjvukOTcUHX77bdr9+7dvVd4L7r+8gT9fsuXKq5q0l8+LdbSq4abXRIAAD7PqzdBZ2Vlac6cOUpJSXGdmz59uvbu3esKPMeOHdN7772n66+//rzf09zcrLq6unZHfwmwWXXP1SMkSc9tL1Cr3dFvPxsA4L38dQtvb/XbawNQeXm5Nm/erGXLlrU7//3vf1+//OUvNX36dAUGBmrkyJGaPXu2Hn300fN+18qVK12zS1FRUUpKSurr8tu5JWOYBg0IVmnNab2TW9avPxsA4F0CA50XzDQ1NZlciTlaWlokSTabe3eh9trbRq5fv17R0dGaP39+u/PZ2dn61a9+pWeeeUaZmZnKy8vTgw8+qISEBD3xxBOdfteKFSv0yCOPuF7X1dX1awgKCbTp7unD9Zv3v9CzOfm6KX2orNauPV0XAOBfbDaboqOjVVlZKUkKCwvr8hPZvZ3D4dCJEycUFhamgAD3IoxXBiDDMLRu3TotXrxYQUFB7d574okntHjxYtfM0OWXX67Gxkbdc889euyxx2S1dpz0Cg4OVnBwcL/Ufj6Lpibrmew8fVXZoA+PfK1rx/XtQ+AAAN7r3INCz4Ugf2K1WpWcnOx26PPKAJSTk6O8vDzdfffdHd5ramrqEHJsNpsMw/Do9dKIkEAtnpqiZ7Lz9Ux2vr49Ns5vEj0AoHssFosSEhI0ZMgQtba2ml1OvwoKCup0MqO7TA1ADQ0NysvLc70uKChQbm6uYmNjlZycrBUrVqi0tFQvvfRSu89lZWUpMzNT48eP7/Cd8+bN0x/+8Aelp6e7lsCeeOIJ3XDDDW6vF/a1u64arqyPCpRbUqNdx6o0beRAs0sCAHgwm83m8b/bPJWpAWjPnj2aPXu26/W5fThLlizR+vXrVV5eruLi4nafqa2t1YYNG7Rq1apOv/Pxxx+XxWLR448/rtLSUg0ePFjz5s3Tr371q77rSC8ZHBGs2yYn6eVdRXomO48ABABAH+FRGJ3or0dhdKakqkmzfpctu8PQ//x4usYPjbr4hwAAgPc8CgMdJcWGad6EBEnSmux8k6sBAMA3EYA80PKzj8d471C5Ck42mlwNAAC+hwDkgUbHR+qa0UNkGNKfc5gFAgCgtxGAPNT9s52zQBv2HVdFrec9yR4AAG9GAPJQGSmxmpIaq1a7oayPjpldDgAAPoUA5MHuOzsL9OonxappajG5GgAAfAcByIPNumywxiREqqnFrpd2FpldDgAAPoMA5MEsFovuO3tF2AsfF6ippc3kigAA8A0EIA/33fHxShkYpuqmVv3l0xKzywEAwCcQgDxcgM2qe64eIUl6btsxtbQ5TK4IAADvRwDyAjdPGqbBEcEqqz2jdw6UmV0OAABejwDkBUICbbp7+nBJ0rM5+XI4eHwbAADuIAB5iYWZyYoICVBeZYM+OPK12eUAAODVCEBeIiIkUHdOS5EkPZOdL8NgFggAgJ4iAHmRu64aruAAqw6U1Ghn/imzywEAwGsRgLzIoAHB+v4VSZKkNTwkFQCAHiMAeZllM0bIZrVo+1cndfB4rdnlAADglQhAXiYpNkw3piVKktbk5JlcDQAA3okA5IWWn308xuZDFco/0WByNQAAeB8CkBe6LC5Cc8bEyTCktTnHzC4HAACvQwDyUucekvrW/uMqrz1tcjUAAHgXApCXykiJUebwWLXaDWVtLzC7HAAAvAoByIudmwV6bXexqhtbTK4GAADvQQDyYjMvG6xxiZFqarHrxZ2FZpcDAIDXIAB5MYvF4poFWr+jUE0tbSZXBACAdyAAebm54xOUOjBMNU2ten13idnlAADgFQhAXs5mtejemc5ZoOe3H1NLm8PkigAA8HwEIB+wYNJQDYkIVnntGW3KLTW7HAAAPB4ByAcEB9i0bMZwSdKzOflyOAyTKwIAwLMRgHzEHZkpigwJ0LETjdpyuMLscgAA8GgEIB8xIDhAS65MlSStyc6XYTALBADA+RCAfMjSK1MVEmjVgeO12pF/yuxyAADwWAQgHzJwQLC+f0WyJOmZ7DyTqwEAwHMRgHzMshnDFWC16OO8UzpQUmN2OQAAeCQCkI8ZFhOmGyYmSnLuBQIAAB0RgHzQfWdvjPj3wxXKq2wwuRoAADwPAcgHXRoXoW+PjZNhSH/OYRYIAIBvIgD5qHMPSd2UW6qymtMmVwMAgGchAPmoSckxmjoiVq12Q89vLzC7HAAAPAoByIfdP+sSSdLru4tV3dhicjUAAHgOApAPm3HpII1LjNTpVrvW7yg0uxwAADwGAciHWSwW1yzQizsL1djcZnJFAAB4BgKQj7tufLyGDwpXTVOrXt9dbHY5AAB4BAKQj7NZLbr36hGSpOe3F6i5zW5yRQAAmI8A5AdumjRUcZHBqqg7o7f3l5ldDgAApiMA+YHgAJuWTXfOAj2bky+7wzC5IgAAzEUA8hO3ZyYrKjRQx042asvnFWaXAwCAqQhAfmJAcICWTEuRJD2TnS/DYBYIAOC/CEB+ZOlVwxUSaNXB0lp9nHfK7HIAADANAciPxIYH6ftXJEuSnsnOM7kaAADMQwDyMz+8eoQCrBbtyD+l3JIas8sBAMAUBCA/MzQ6VPPTh0qS1jALBADwUwQgP7R85ghZLNLfP/9aeZX1ZpcDAEC/IwD5oUuGROjasXGSpGdzjplcDQAA/Y8A5KfuO/uQ1E37S1Vac9rkagAA6F8EID81MSlaV44cqDaHoee3MwsEAPAvBCA/dt+skZKkN3aXqKqxxeRqAADoPwQgPzb9kkG6fGiUTrfatX5HodnlAADQbwhAfsxisbhmgV7cUaiG5jaTKwIAoH8QgPzcd8bFa8SgcNWebtUbu4vNLgcAgH5hagDatm2b5s2bp8TERFksFm3atOmC7ZcuXSqLxdLhGDduXLt2NTU1euCBB5SQkKCQkBCNGTNG7733Xh/2xHvZrBbdO3OEJOm57cfU3GY3uSIAAPqeqQGosbFRaWlpWr16dZfar1q1SuXl5a6jpKREsbGxuvXWW11tWlpa9O1vf1uFhYV68803dfToUT333HMaOnRoX3XD692UPkzxkSH6uq5ZG/eVml0OAAB9LsDMHz537lzNnTu3y+2joqIUFRXler1p0yZVV1frrrvucp1bt26dqqqqtGPHDgUGBkqSUlJSeq9oHxQUYNWyGcP1/717RH/edky3Tk6SzWoxuywAAPqMV+8BysrK0pw5c9oFnHfeeUfTpk3TAw88oLi4OI0fP15PP/207PbzL+00Nzerrq6u3eFvbp+SrOiwQBWcbNT7hyrMLgcAgD7ltQGovLxcmzdv1rJly9qdP3bsmN58803Z7Xa99957evzxx/X73/9ev/rVr877XStXrnTNLkVFRSkpKamvy/c44cEBWjItVZK0JidPhmGYWxAAAH3IawPQ+vXrFR0drfnz57c773A4NGTIEK1du1YZGRn6/ve/r8cee0xr1qw573etWLFCtbW1rqOkpKSPq/dMS69MVWigTYdK67T9q5NmlwMAQJ/xygBkGIbWrVunxYsXKygoqN17CQkJuuyyy2Sz2VznxowZo4qKCrW0dH634+DgYEVGRrY7/FFMeJBun5IsSVqTnW9yNQAA9B2vDEA5OTnKy8vT3Xff3eG9q666Snl5eXI4HK5zX375pRISEjqEJXS0bMZwBdos2nnslPYXV5tdDgAAfcLUANTQ0KDc3Fzl5uZKkgoKCpSbm6viYucN+VasWKE777yzw+eysrKUmZmp8ePHd3jvvvvu06lTp/Tggw/qyy+/1Lvvvqunn35aDzzwQJ/2xVckRodq/kTnLQOYBQIA+CpTA9CePXuUnp6u9PR0SdIjjzyi9PR0Pfnkk5KcG53PhaFzamtrtWHDhk5nfyQpKSlJW7Zs0aeffqoJEyboJz/5iR588EE9+uijfdsZH3LvzJGyWKQth7/WV1/Xm10OAAC9zmJwuU8HdXV1ioqKUm1trd/uB1r+8l69/3mFFkwaqj/cNtHscgAAuKju/P72yj1A6HvnHpL6Tm6Zjlc3mVwNAAC9iwCETqUlReuqSwaqzWHo+e0FZpcDAECvIgDhvO6fdYkk6Y1Pi3WqodnkagAA6D0EIJzXlSMHasKwKJ1pdWj9jkKzywEAoNcQgHBeFotF95/dC/TijkI1NLeZXBEAAL2DAIQLunZsvEYMDlfdmTa99kmR2eUAANArCEC4IKvVouUznbNAz28vUHOb3eSKAABwHwEIFzV/4lAlRIWosr5Zb+0rNbscAADcRgDCRQUFWLVsxghJ0p9z8mV3cO9MAIB3IwChS26fkqTosEAVnmrS5kPlZpcDAIBbCEDokrCgAC29MlWS9MzWfPEEFQCANyMAocuWTEtVWJBNh8vrtO2rk2aXAwBAjxGA0GUx4UG6fUqyJOmZrXkmVwMAQM8RgNAty2YMV6DNok8KqrS3qNrscgAA6BECELolISpUN6UPlSStyc43uRoAAHqGAIRuu3fmSFks0odHvtaXX9ebXQ4AAN1GAEK3jRw8QNeNi5ckPcssEADACxGA0CP3z7pEkvT2gTKVVDWZXA0AAN1DAEKPXD4sSjMuHSS7w9Dz24+ZXQ4AAN1CAEKP3Xf2IalvfFqikw3NJlcDAEDXEYDQY9NGDlRaUrSa2xxa/3Gh2eUAANBlBCD0mMVicc0CvbizUPVnWk2uCACAriEAwS3Xjo3TyMHhqj/Tptc+KTa7HAAAuoQABLdYrRYtPzsL9PxHBTrTaje5IgAALo4ABLfdOHGoEqNCdKK+WW/tKzW7HAAALooABLcFBVi1bMYISdKft+Wrze4wuSIAAC6MAIRe8f0pSYoJC1TRqSa9d6jC7HIAALggAhB6RVhQgO66argk50NSDcMwuSIAAM6PAIRec+e0FIUH2XSkvE7ZX54wuxwAAM6LAIReEx0WpDsykyU5Z4EAAPBUBCD0qrunj1CgzaLdBVXaW1RldjkAAHSKAIReFR8VopsnDZPELBAAwHMRgNDr7rl6hCwW6cMjlTpaUW92OQAAdEAAQq8bMXiAvjs+QZL0bA6zQAAAz0MAQp+4b5bz8RjvHChTSVWTydUAANAeAQh9YvzQKM24dJDsDkNrtx0zuxwAANohAKHP3D/rEknSX/eU6ER9s8nVAADwTwQg9JmpI2I1MSlazW0OvfBxgdnlAADgQgBCn7FYLLr/7F6gl3cWqe5Mq8kVAQDgRABCn5ozJk6XDhmg+uY2vbqr2OxyAACQRABCH7NaLVo+0zkLlPVRgc602k2uCAAAAhD6wQ0TEzU0OlQnG5r15t7jZpcDAAABCH0v0GbVD2cMlySt3XZMbXaHyRUBAPwdAQj94ntXJCs2PEjFVU1692C52eUAAPwcAQj9IjTIpruuTJXkfEiqYRjmFgQA8GsEIPSbO6elKjzIpi8q6pV99ITZ5QAA/BgBCP0mKixQC6emSJKeyc4zuRoAgD8jAKFf3T19uIJsVn1aWK1PC6vMLgcA4KcIQOhXcZEhujljqCTnXiAAAMxAAEK/u/fqkbJapH98Uakj5XVmlwMA8EMEIPS71EHhmnt5giTp2RxmgQAA/Y8ABFPcd/bxGP99oEzFp5pMrgYA4G8IQDDF+KFRuvqywXIY0trtzAIBAPoXAQimuX+Wcxbor3uOq7L+jMnVAAD8CQEIpskcHqv05Gi1tDn0wseFZpcDAPAjBCCYxmKx6P5Zl0iSXtlZpLozrSZXBADwFwQgmOqa0UN0WdwA1Te36ZVdRWaXAwDwEwQgmMpqtWj52SvC1n1UoDOtdpMrAgD4AwIQTDcvLVFDo0N1sqFFf9t73OxyAAB+gAAE0wXarLrn6hGSpLXb8tVmd5hcEQDA15kagLZt26Z58+YpMTFRFotFmzZtumD7pUuXymKxdDjGjRvXafs33nhDFotF8+fP7/3i0atum5ykgeFBKqk6rXcPlptdDgDAx5kagBobG5WWlqbVq1d3qf2qVatUXl7uOkpKShQbG6tbb721Q9uioiL99Kc/1YwZM3q7bPSB0CCb7roqVZLzIamGYZhbEADApwWY+cPnzp2ruXPndrl9VFSUoqKiXK83bdqk6upq3XXXXe3a2e12LVy4UL/4xS+0fft21dTU9FbJ6EOLp6Xq2Zxj+qKiXv/4olLXjIkzuyQAgI/y6j1AWVlZmjNnjlJSUtqdf+qppzR48GDdfffdXfqe5uZm1dXVtTvQ/6JCA7UwM1mScxYIAIC+4rUBqLy8XJs3b9ayZcvanf/444+VlZWl5557rsvftXLlStfsUlRUlJKSknq7XHTR3dOHKyjAqj1F1dpdUGV2OQAAH+W1AWj9+vWKjo5ut8G5vr5eixYt0nPPPadBgwZ1+btWrFih2tpa11FSUtIHFaMrhkSG6JaMYZKkNdl5JlcDAPBVPdoDVFJSIovFomHDnL+odu/erddee01jx47VPffc06sFdsYwDK1bt06LFy9WUFCQ63x+fr4KCws1b9481zmHw3lJdUBAgI4ePaqRI0d2+L7g4GAFBwf3ed3omnuvHqE3dhdr69ETOlxWp7GJkWaXBADwMT2aAbrjjju0detWSVJFRYW+/e1va/fu3frZz36mp556qlcL7ExOTo7y8vI67PEZPXq0Dh48qNzcXNdxww03aPbs2crNzWVpy0ukDAzX9RMSJUnP5rAXCADQ+3oUgA4dOqQpU6ZIkv76179q/Pjx2rFjh1577TWtX7++y9/T0NDgCiqSVFBQoNzcXBUXF0tyLk3deeedHT6XlZWlzMxMjR8/vt35kJAQjR8/vt0RHR2tiIgIjR8/vt1sETzb8pnOGyP+z2dlKjrVaHI1AABf06MA1Nra6loy+vDDD3XDDTdIcs7AlJd3/SZ2e/bsUXp6utLT0yVJjzzyiNLT0/Xkk09Kcm50PheGzqmtrdWGDRu6fIUXvNO4xCjNGjVYDkNau+2Y2eUAAHyMxejBHecyMzM1e/ZsXX/99br22mu1a9cupaWladeuXbrlllt0/Lh3P8+prq5OUVFRqq2tVWQk+0/M8smxU/re2l0KCrDqo/87W0MiQswuCQDgwbrz+7tHM0C/+c1v9Oc//1mzZs3S7bffrrS0NEnSO++841oaA9w1ZXisMlJi1NLmUNZHBWaXAwDwIT2aAZKcd1uuq6tTTEyM61xhYaHCwsI0ZMiQXivQDMwAeY4PD3+tZS/t0YDgAH386LcUFRpodkkAAA/V5zNAp0+fVnNzsyv8FBUV6U9/+pOOHj3q9eEHnuVbo4doVFyEGprb9MquIrPLAQD4iB4FoBtvvFEvvfSSJKmmpkaZmZn6/e9/r/nz52vNmjW9WiD8m9Vq0X2znPduWvdRgc602k2uCADgC3oUgPbt2+d6yvqbb76puLg4FRUV6aWXXtJ//ud/9mqBwL9NSNCwmFCdamzRX/dwl24AgPt6FICampoUEREhSdqyZYsWLFggq9WqqVOnqqiIZQr0rgCbVfde7bwv0J9zjqnV7jC5IgCAt+tRALrkkku0adMmlZSU6O9//7uuvfZaSVJlZSWbhtEnbp2cpEEDglRac1r/81mZ2eUAALxcjwLQk08+qZ/+9KdKTU3VlClTNG3aNEnO2aBzNzUEelNIoE13XTVckrQmO18OR48uXgQAQJIbl8FXVFSovLxcaWlpslqdOWr37t2KjIzU6NGje7XI/sZl8J6p9nSrrvr1P9TQ3Kbn75ysOWPjzC4JAOBB+vwyeEmKj49Xenq6ysrKVFpaKkmaMmWK14cfeK6o0EAtmpoiSXomO089zO4AAPQsADkcDj311FOKiopSSkqKkpOTFR0drV/+8pdyONigir7zg+mpCgqwal9xjXYXVJldDgDAS/UoAD322GNavXq1fv3rX2v//v3at2+fnn76af3Xf/2Xnnjiid6uEXAZEhGiWzOGSZKeyc43uRoAgLfq0R6gxMREPfvss66nwJ/z9ttv6/7773ctiXkr9gB5tuJTTZr1u61yGNK7P5mucYlRZpcEAPAAfb4HqKqqqtO9PqNHj1ZVFcsS6FvJA8P0bxMSJTmvCAMAoLt6FIDS0tK0evXqDudXr16tCRMmuF0UcDHnHo/x3sFyFZ5sNLkaAIC3CejJh37729/q+uuv14cffqhp06bJYrFox44dKikp0XvvvdfbNQIdjEmI1OxRg7X16An9edsxrVxwudklAQC8SI9mgGbOnKkvv/xSN910k2pqalRVVaUFCxbo888/1wsvvNDbNQKdun/2JZKkDXuPq7LujMnVAAC8SY9vhNiZAwcOaNKkSbLbvfuJ3WyC9h63rNmhPUXVuvfqEVrx3TFmlwMAMFG/3AgR8AT3z3buBXplV5Fqm1pNrgYA4C0IQPBqs0cN0ej4CDW22PXyrkKzywEAeAkCELyaxWJxXRG27uNCnW7x7uVXAED/6NZVYAsWLLjg+zU1Ne7UAvTI9Zcn6Hdbjqqk6rT+uqdES65MNbskAICH69YMUFRU1AWPlJQU3XnnnX1VK9CpAJtV91ztnAVau+2YWu08jw4AcGHdmgHiEnd4qlszhmnVh1+ptOa0/vtAmRZMGmZ2SQAAD8YeIPiEkECbfjA9VZLz8RgOR6/d3QEA4IMIQPAZi6amKCI4QF9VNuh/v6g0uxwAgAcjAMFnRIYEatG0FEnSM9l56sV7fAIAfAwBCD7lB1cNV1CAVfuLa7TrWJXZ5QAAPBQBCD5lcESwbpvs3AC9Jiff5GoAAJ6KAASfc+/VI2WzWrTtyxM6VFprdjkAAA9EAILPSYoN07wJCZKYBQIAdI4ABJ+0/OzjMTYfLFfByUaTqwEAeBoCEHzS6PhIXTN6iByGtHYbs0AAgPYIQPBZ5x6SumFvqb6uO2NyNQAAT0IAgs+anBqrKamxarE7lPVRgdnlAAA8CAEIPu3cLNCru4pU29RqcjUAAE9BAIJPmzVqsEbHR6ixxa4XdxaaXQ4AwEMQgODTLBaLaxbohY8L1NTSZnJFAABPQACCz7v+8gQlx4apuqlVf/m0xOxyAAAegAAEnxdgs+remSMkSc9tO6ZWu8PkigAAZiMAwS/cPGmYBkcEq6z2jN7OLTO7HACAyQhA8AshgTbdPX24JOnZnHw5HIbJFQEAzEQAgt9YmJmsiJAA5VU26IMjX5tdDgDARAQg+I2IkEDdOS1FkvRMdr4Mg1kgAPBXBCD4lbuuGq7gAKsOlNRo57FTZpcDADAJAQh+ZdCAYH3viiRJ0ppsHpIKAP6KAAS/88MZI2SzWrT9q5M6eLzW7HIAACYgAMHvJMWG6Ya0REnSmpw8k6sBAJiBAAS/tHym8/EYmw9V6NiJBpOrAQD0NwIQ/NKo+AjNGTNEhiH9OeeY2eUAAPoZAQh+675Zl0iS3tp/XBW1Z0yuBgDQnwhA8FsZKTGaMjxWrXZDz29nFggA/AkBCH7t/lnOvUCv7S5WTVOLydUAAPoLAQh+beZlgzU2IVJNLXa9uKPI7HIAAP2EAAS/ZrFYdN/ZWaD1OwrU1NJmckUAgP5AAILfmzs+XikDw1Td1Ko3dpeYXQ4AoB8QgOD3AmxW3Xu1cxboue3H1NLmMLkiAEBfIwABkhZMGqrBEcEqrz2jt3NLzS4HANDHCECApJBAm5ZNHy5JejYnXw6HYXJFAIC+RAACzrojM1mRIQHKP9GoLYe/NrscAEAfMjUAbdu2TfPmzVNiYqIsFos2bdp0wfZLly6VxWLpcIwbN87V5rnnntOMGTMUExOjmJgYzZkzR7t37+7jnsAXRIQE6s5pqZKkNdl5MgxmgQDAV5kagBobG5WWlqbVq1d3qf2qVatUXl7uOkpKShQbG6tbb73V1SY7O1u33367tm7dqp07dyo5OVnXXnutSkvZ14GLu+uqVIUEWnXgeK125p8yuxwAQB+xGB7y11yLxaKNGzdq/vz5Xf7Mpk2btGDBAhUUFCglJaXTNna7XTExMVq9erXuvPPOLn1vXV2doqKiVFtbq8jIyC7XA9/w87cP6cWdRZp+ySC9sizT7HIAAF3Und/fXr0HKCsrS3PmzDlv+JGkpqYmtba2KjY29rxtmpubVVdX1+6A//rh1SNks1r0Ud5JfXa8xuxyAAB9wGsDUHl5uTZv3qxly5ZdsN2jjz6qoUOHas6cOedts3LlSkVFRbmOpKSk3i4XXmRYTJhuTEuUJK3Jzje5GgBAX/DaALR+/XpFR0dfcMnst7/9rV5//XW99dZbCgkJOW+7FStWqLa21nWUlHA3YH+3/OzjMd7/vEJ5lQ0mVwMA6G1eGYAMw9C6deu0ePFiBQUFddrmd7/7nZ5++mlt2bJFEyZMuOD3BQcHKzIyst0B/3ZZXITmjImTYUhrtzELBAC+xisDUE5OjvLy8nT33Xd3+v5//Md/6Je//KXef/99TZ48uZ+rg6+4f7ZzFmjj/lKV1542uRoAQG8yNQA1NDQoNzdXubm5kqSCggLl5uaquLhYknNpqrMrt7KyspSZmanx48d3eO+3v/2tHn/8ca1bt06pqamqqKhQRUWFGhpYxkD3TEqO0dQRsWq1G3p+e4HZ5QAAepGpAWjPnj1KT09Xenq6JOmRRx5Renq6nnzySUnOjc7nwtA5tbW12rBhw3lnf5555hm1tLTolltuUUJCguv43e9+17edgU+6b9YlkqTXdxerurHF5GoAAL3FY+4D5Em4DxDOMQxD//ZfH+nzsjo9NOdSPTTnMrNLAgCch9/cBwjoaxaLRfedvSJs/Y5CNTa3mVwRAKA3EICAi5g7PkGpA8NU09SqNz7lFgkA4AsIQMBF2KwW3TvTOQv0/PZjamlzmFwRAMBdBCCgCxZMGqohEcEqrz2jTft5sC4AeDsCENAFwQE2LZsxXJL07LZ82R1cOwAA3owABHTRHZkpigoN1LETjfrjB1+q9nSr2SUBAHqIAAR00YDgAP3gKucs0Oqtecp8+kP93zc/06HSWpMrAwB0F/cB6gT3AcL5OByGXv+0WC/vLNIXFfWu82lJ0Vo8NUX/NiFBIYE2EysEAP/Vnd/fBKBOEIBwMYZhaE9RtV7eWaTNh8rVanf+bxQdFqhbM4ZpYWaKUgeFm1wlAPgXApCbCEDojhP1zfrrnhK99kmxSmv++dDUqy8brEWZyfrW6CEKsLHaDAB9jQDkJgIQesLuMJR9tFIv7ypSzpcndO7/rMSoEN2RmazbrkjSkIgQc4sEAB9GAHITAQjuKjrVqNc+KdZf95Sousl5tViA1aLrxsdr8dQUTRkeK4vFYnKVAOBbCEBuIgCht5xpteu9g+V6eVeR9hfXuM5fFjdAi6am6Kb0oYoICTSvQADwIQQgNxGA0BcOldbq1U+KtGl/mU632iVJYUE23ZQ+VIumpmhMAv+tAYA7CEBuIgChL9WebtXGfcf18q4i5Z9odJ2fnBKjxdNSdN34eAUHcCk9AHQXAchNBCD0B8MwtPPYKb26q1h//7xCbWcfrzEwPEi3XZGkO6YkKyk2zOQqAcB7EIDcRABCf/u67oze2F2i13cXq6LujCTJYpG+NWqIFk1N0dWXDZbNyqZpALgQApCbCEAwS5vdoQ+PVOqVXUX6KO+k63xSbKgWZqbotslJig0PMrFCAPBcBCA3EYDgCY6daNCrnxTrb3tKVHemTZIUZLPq+gkJWjQ1WZOSY7iUHgD+BQHITQQgeJLTLXb994EyvbyrSAf/5cGrYxIitXhqim6cmKjw4AATKwQAz0AAchMBCJ7qQEmNXt5VpP8+UKbmNockKSI4QAsmOS+lvzQuwuQKAcA8BCA3EYDg6WqaWvTm3uN6ZVeRCk81uc5PHRGrRVNTdO3YeAUF8PwxAP6FAOQmAhC8hcNh6OP8k3p5Z5E+PPK1zl5Jr8ERwbr9iiTdnpmshKhQc4sEgH5CAHITAQjeqKzmtF7fXazXd5foZEOzJMlqkeaMidPiaSm6auQgWbmUHoAPIwC5iQAEb9bS5tCWwxV6eWeRPimocp0fPihcCzOTdUvGMEWHcSk9AN9DAHITAQi+4suv6/XqriJt2FeqhmbnpfTBAVbdkJaoRVNTlJYUbW6BANCLCEBuIgDB1zQ2t+nt3DK9tLNQX1TUu85PGBalRVNTNG9CokKDeP4YAO9GAHITAQi+yjAM7Suu1ss7i/TewQq12J2X0keGBOjWyUlamJmsEYMHmFwlAPQMAchNBCD4g1MNzfrrnuN69ZMiHa8+7To/49JBWpiZojljhijAxqX0ALwHAchNBCD4E7vD0LYvT+jlXUXaerRS5/5EiI8M0R2Zyfr+FUkaEhlibpEA0AUEIDcRgOCvSqqa9NruYv3l0xJVNbZIkgKsFn1nXLwWTk3WtBEDef4YAI9FAHITAQj+rrnNrvcPOS+l31NU7Tp/yZABWpSZrAUZwxQZEmhihQDQEQHITQQg4J8Ol9XplU+KtGl/qZpa7JKk0ECb5qc7L6UflxhlcoUA4EQAchMBCOio/kyrNu4v1cs7i/RVZYPr/KTkaC2amqLvXp6gkEAupQdgHgKQmwhAwPkZhqHdBVV6eVeR3j9UobazDyCLCQvUbVckaeGUFCUPDDO5SgD+iADkJgIQ0DWV9Wf0l90len13scpqz0iSLBZp5mWDtXhqimaNGiIbzx8D0E8IQG4iAAHd02Z36B9fVOrlXUXa/tVJ1/mh0aG6IzNZ37siSYMGBJtYIQB/QAByEwEI6LmCk4167ZMi/XXPcdWebpUkBdos+u7lCVo0NUWTU2K4lB5AnyAAuYkABLjvTKtd//NZuV7eVaQDJTWu86PjI7Roaormpw/VgOAA8woE4HMIQG4iAAG967PjNXplV5HeOVCmM63O548NCA7QTelDtWhqikbFR5hcIQBfQAByEwEI6Bu1Ta16c99xvbqrSMdONrrOTxkeq0VTU3TduHgFBfD8MQA9QwByEwEI6FuGYWhH/im9vLNIHxz5Wvazl9IPGhCk712RpDsyUzQ0OtTkKgF4GwKQmwhAQP+pqD2j13cX6/Xdxaqsb5YkWS3St0bHadHUZF196WBZuZQeQBcQgNxEAAL6X6vdoQ8Pf62XdxVpR/4p1/mUgWFamJmsWzOSFBMeZGKFADwdAchNBCDAXHmV9XplV7E27Duu+jNtkqSgAKv+bUKCFk9N0cSkaC6lB9ABAchNBCDAMzS1tOmd3DK9vKtIn5fVuc6PHxqpRZkpumFiosKCuJQegBMByE0EIMCzGIah3JIavbyrSP/zWbla2pyX0keEBOiWjGFamJmiS4YMMLlKAGYjALmJAAR4rqrGFv1tT4le/aRYxVVNrvNXjhyoxVNTNGdsnAJtXEoP+CMCkJsIQIDnczgMbfvqhF7ZVaR/fFGps1fSa0hEsG6fkqzbpyQrPirE3CIB9CsCkJsIQIB3OV7dpNd3F+svn5boZEOLJMlmtejasXFaNDVFV44cyKZpwA8QgNxEAAK8U0ubQ+9/XqFXdhZpd2GV6/yIweFalJmimzOGKSo00MQKAfQlApCbCECA9/uiok6v7CrSxn2lamyxS5JCAq26MW2ovj8lSROGRcvGDRYBn0IAchMBCPAdDc1t2ri/VK/uKtIXFfWu8xHBAZqYHK3JKbGanBqjiUnRCufp9IBXIwC5iQAE+B7DMLSnqFov7yzS/x752jUrdI7NatGYhAhlJMcoIzVWk1NilMjzyACvQgByEwEI8G1tdoe+qKjXvuJq7Sms1t6iapXWnO7QLjEqxBWGMlJiNDo+QgFcYg94LAKQmwhAgP8prz3tCkN7i6p1uLzO9ZT6c8KDbJqYHK2MFGcompgcrcgQNlUDnoIA5CYCEIDG5jYdKKnRnqJq7Smq1v6iatU3t7VrY7FIo+IiNDk1RpNTYpWREqNhMaFccg+YhADkJgIQgG+yOwx9VVnvmiXaU1SlkqqOy2ZxkcHKSIlxzRKNTYzkztRAPyEAuYkABKArKuvOnA1DzuPz0lq1fWPZLDTQprSkKGWkOGeJJiXHKCqMZTOgLxCA3EQAAtATp1vsOnC8xrWPaG9RtWpPt3Zod1ncANcMUUZKjFIGhrFsBvQCrwlA27Zt03/8x39o7969Ki8v18aNGzV//vzztl+6dKlefPHFDufHjh2rzz//3PV6w4YNeuKJJ5Sfn6+RI0fqV7/6lW666aYu10UAAtAbHA5D+ScatOdfAlHBycYO7QYNCFZGivOeRBmpMRqXGKngAJsJFQPerTu/v02961djY6PS0tJ011136eabb75o+1WrVunXv/6163VbW5vS0tJ06623us7t3LlT3/ve9/TLX/5SN910kzZu3KjbbrtNH330kTIzM/ukHwDQGavVokvjInRpXIRun5IsSTrZ0OwKQ3sKq3SotE4nG5r198+/1t8//1qSFBRgVdqwqHazRDHhQWZ2BfA5HrMEZrFYLjoD9E2bNm3SggULVFBQoJSUFEnS9773PdXV1Wnz5s2udtddd51iYmL0+uuvd/o9zc3Nam5udr2uq6tTUlISM0AA+tyZVrsOldY69xEVVmtfcbWqGls6tBsxOFyTz+4jykiN0YhB4SybAd/gNTNA7srKytKcOXNc4UdyzgA9/PDD7dp95zvf0Z/+9Kfzfs/KlSv1i1/8oq/KBIDzCgm0aXJqrCanxkoznXesLjjZ6Fw2K3RebZZ/olHHzh5/3XNckhQbHqRJyc7ZocmpMbp8aJRCAlk2A7rKawNQeXm5Nm/erNdee63d+YqKCsXFxbU7FxcXp4qKivN+14oVK/TII4+4Xp+bAQKA/maxWDRi8ACNGDxAt012/jlU3djivGv12VB04HiNqhpb9OGRr/XhkbPLZjarxg+N1ORU55Vmk1NjNGhAsJldATya1wag9evXKzo6utMls29OCxuGccGp4uDgYAUH8wcFAM8UEx6ka8bE6Zoxzr/ctbQ5dKisVvvOLpvtKarWyYZm7Suu0b7iGtfnUgeGOfcRpTpnii4ZPEBWK8tmgOSlAcgwDK1bt06LFy9WUFD7jYHx8fEdZnsqKys7zAoBgLcKCrBqUnKMJiXHaNkM55+JxVVNrjC0r6haX1bWq/BUkwpPNWnDPueyWVRooCYlR2tyqvOu1WnDohUaxLIZ/JNXBqCcnBzl5eXp7rvv7vDetGnT9MEHH7TbB7RlyxZdeeWV/VkiAPQbi8WilIHhShkYrpszhkmSak+3al+xc8lsb1G1cktqVHu6VVuPntDWoyckSQFWi8YlRrpmiSanxGhIZIiZXQH6jakBqKGhQXl5ea7XBQUFys3NVWxsrJKTk7VixQqVlpbqpZdeave5rKwsZWZmavz48R2+88EHH9TVV1+t3/zmN7rxxhv19ttv68MPP9RHH33U5/0BAE8RFRqo2aOGaPaoIZKkVrtDR8rr2j3K4+u6Zh04XqsDx2u17uMCSVJSbKjzjtUpzkB0WVyEbCybwQeZehl8dna2Zs+e3eH8kiVLtH79ei1dulSFhYXKzs52vVdbW6uEhAStWrVKP/zhDzv93jfffFOPP/64jh075roR4oIFC7pcFzdCBODrDMNQac3ps/cjci6dHa2o0zee5KGI4AClnw1DGSkxmpgUrfBgr1w8gB/wmjtBeyoCEAB/VH+mVbklNa5Zov3F1WpssbdrY7NaNCYhwnk/orOX4CdEhZpUMdAeAchNBCAAkNrsDn1RUe+8BP9sKCqtOd2hXWJUiDJS/3nX6tHxEQqwWU2oGP6OAOQmAhAAdK689rQrDO0tqtbh8jrZv7FuFh5k08TkaNejPNKToxUREmhSxfAnBCA3EYAAoGsam9t0oKTG+SiPomrtL6pWfXNbuzZWizQqPtI1Q5SREqNhMaE8ygO9jgDkJgIQAPSM3WHoq8r6dleblVR1XDaLiwx27SPKSInR2MRIBbJsBjcRgNxEAAKA3lNZd+ZsGHIen5fWqu0by2ahgTalJUW5HvY6KTlGUaEsm6F7CEBuIgABQN853WLXgeM1rn1Ee4uqVXu6tV0bi0W6dMgA1z6iyakxSo4NY9kMF0QAchMBCAD6j8NhKP9Eg/Nhr2ePgpONHdoNGhCsjJRo140axyVGKiSQR3ngnwhAbiIAAYC5TjY0u8LQnsIqHSqtU4vd0a5NoM2iMQmRmpgU7TpSB4bzwFc/RgByEwEIADzLmVa7DpXWOvcRFVYrt6RaJxtaOrSLDAlQWlK00pOiNTE5WhOTYhQbHtTJN8IXEYDcRAACAM9mGIaOV59WbkmN6zhUWqvmNkeHtsmxYf+cJUqO1tgEls58FQHITQQgAPA+rXaHjlbUa39JjXKLa5RbUq38Ex33EgXaLBqbEKm0f1k6Gz4onA3WPoAA5CYCEAD4htrTrfrs+LlA5DxONXZcOosKDXQFovSkaKUlRbN05oUIQG4iAAGAbzq3dLa/pEYHLrJ0ljIwrN0G67GJkQoOYOnMkxGA3EQAAgD/0Wp36IvyeuWWVDuXz0pqdOwCS2cT/2WDdepA7k3kSQhAbiIAAYB/q21q1YHjNe02WVd1snQWHRaotGH/3GA9cVi0Ylg6Mw0ByE0EIADAvzIMQyVVp7W/pFq5Z5fPDpXVqaWTpbPUs0tnaSyd9TsCkJsIQACAi2lpc+iLijrnDNHZTdbHOrmDdZDNqjGJkc57E509Ulg66xMEIDcRgAAAPVHb1Krc4/+8DD+3pEbVTa0d2sWEBba7DH9iUrSiw1g6cxcByE0EIABAbzAMQ8VVTe32En3eyWM9pH8unTn3E8VobEKkggKsJlTtvQhAbiIAAQD6SkubQ0fK69qFos4e/hpks2psovOqs/RkZzBKjmXp7EIIQG4iAAEA+lNNU0u7QHTgPEtnseFBShsWpYlJMUpLimLp7BsIQG4iAAEAzGQYhopOtV86O1zW+dLZ8EHh7fYSjfHjpTMCkJsIQAAAT9PcZteR8nrlFle7QlHhqaYO7YICrBp3dunM+WiPGCXFhvrF0hkByE0EIACAN6hubPmXq85qdOB4jWousnR27oaNUWGBJlTctwhAbiIAAQC80TeXzvaX1OhwWa1a7R1/1Y84t3R2doP16HjvXzojALmJAAQA8BXNbXYdLmt/1VnReZbOxidGujZYe+PSGQHITQQgAIAvq2ps0YGzM0TnrjqrPd1x6WxgeFC7GzamJUUrKtRzl84IQG4iAAEA/IlhGCo81eS8e/XZ/USHy+s6XzobHH52c3W0JibFaHRChAJtnrF0RgByEwEIAODvzrTadbi8zhWIcktqVFzVceks2HXVmXODdXpStIbFmLN0RgByEwEIAICOTjU068DZq872n106qzvT1qHdoAFBShsW7dpkPWFY/yydEYDcRAACAODiDMNQwcnGDjdsbHN0jBYjB4e3uwy/L5bOCEBuIgABANAzZ1rt+rzdVWfVKqk63aHd8EHh2vrTWb36s7vz+zugV38yAADwayGBNmWkxCgjJcZ17mRDsw78yyxRbkmNRsdHmFglAQgAAPSxQQOCdc2YOF0zJk6S5HAYamjpuHeoP3nGdWsAAMBvWK0WRYaYez8hAhAAAPA7BCAAAOB3CEAAAMDvEIAAAIDfIQABAAC/QwACAAB+hwAEAAD8DgEIAAD4HQIQAADwOwQgAADgdwhAAADA7xCAAACA3yEAAQAAvxNgdgGeyDAMSVJdXZ3JlQAAgK4693v73O/xCyEAdaK+vl6SlJSUZHIlAACgu+rr6xUVFXXBNhajKzHJzzgcDpWVlSkiIkIWi6VXv7uurk5JSUkqKSlRZGRkr363J/D1/km+30f65/18vY/0z/v1VR8Nw1B9fb0SExNltV54lw8zQJ2wWq0aNmxYn/6MyMhIn/0PW/L9/km+30f65/18vY/0z/v1RR8vNvNzDpugAQCA3yEAAQAAv0MA6mfBwcH6+c9/ruDgYLNL6RO+3j/J9/tI/7yfr/eR/nk/T+gjm6ABAIDfYQYIAAD4HQIQAADwOwQgAADgdwhAAADA7xCA+sAzzzyj4cOHKyQkRBkZGdq+ffsF2+fk5CgjI0MhISEaMWKEnn322X6qtGe607/s7GxZLJYOxxdffNGPFXfdtm3bNG/ePCUmJspisWjTpk0X/Yw3jV93++dt47dy5UpdccUVioiI0JAhQzR//nwdPXr0op/zpjHsSR+9aRzXrFmjCRMmuG6QN23aNG3evPmCn/Gm8etu/7xp7DqzcuVKWSwWPfTQQxdsZ8YYEoB62V/+8hc99NBDeuyxx7R//37NmDFDc+fOVXFxcaftCwoK9N3vflczZszQ/v379bOf/Uw/+clPtGHDhn6uvGu6279zjh49qvLyctdx6aWX9lPF3dPY2Ki0tDStXr26S+29bfy6279zvGX8cnJy9MADD2jXrl364IMP1NbWpmuvvVaNjY3n/Yy3jWFP+niON4zjsGHD9Otf/1p79uzRnj179K1vfUs33nijPv/8807be9v4dbd/53jD2H3Tp59+qrVr12rChAkXbGfaGBroVVOmTDGWL1/e7tzo0aONRx99tNP2/+f//B9j9OjR7c7de++9xtSpU/usRnd0t39bt241JBnV1dX9UF3vkmRs3Ljxgm28bfz+VVf6583jZxiGUVlZaUgycnJyztvGm8fQMLrWR28fx5iYGOP555/v9D1vHz/DuHD/vHXs6uvrjUsvvdT44IMPjJkzZxoPPvjgeduaNYbMAPWilpYW7d27V9dee22789dee6127NjR6Wd27tzZof13vvMd7dmzR62trX1Wa0/0pH/npKenKyEhQddcc422bt3al2X2K28aP3d46/jV1tZKkmJjY8/bxtvHsCt9PMfbxtFut+uNN95QY2Ojpk2b1mkbbx6/rvTvHG8buwceeEDXX3+95syZc9G2Zo0hAagXnTx5Una7XXFxce3Ox8XFqaKiotPPVFRUdNq+ra1NJ0+e7LNae6In/UtISNDatWu1YcMGvfXWWxo1apSuueYabdu2rT9K7nPeNH494c3jZxiGHnnkEU2fPl3jx48/bztvHsOu9tHbxvHgwYMaMGCAgoODtXz5cm3cuFFjx47ttK03jl93+udtYydJb7zxhvbt26eVK1d2qb1ZY8jT4PuAxWJp99owjA7nLta+s/Oeojv9GzVqlEaNGuV6PW3aNJWUlOh3v/udrr766j6ts7942/h1hzeP349+9CN99tln+uijjy7a1lvHsKt99LZxHDVqlHJzc1VTU6MNGzZoyZIlysnJOW9I8Lbx607/vG3sSkpK9OCDD2rLli0KCQnp8ufMGENmgHrRoEGDZLPZOsyGVFZWdki358THx3faPiAgQAMHDuyzWnuiJ/3rzNSpU/XVV1/1dnmm8Kbx6y3eMH4//vGP9c4772jr1q0aNmzYBdt66xh2p4+d8eRxDAoK0iWXXKLJkydr5cqVSktL06pVqzpt643j153+dcaTx27v3r2qrKxURkaGAgICFBAQoJycHP3nf/6nAgICZLfbO3zGrDEkAPWioKAgZWRk6IMPPmh3/oMPPtCVV17Z6WemTZvWof2WLVs0efJkBQYG9lmtPdGT/nVm//79SkhI6O3yTOFN49dbPHn8DMPQj370I7311lv6xz/+oeHDh1/0M942hj3pY2c8eRy/yTAMNTc3d/qet41fZy7Uv8548thdc801OnjwoHJzc13H5MmTtXDhQuXm5spms3X4jGlj2KdbrP3QG2+8YQQGBhpZWVnG4cOHjYceesgIDw83CgsLDcMwjEcffdRYvHixq/2xY8eMsLAw4+GHHzYOHz5sZGVlGYGBgcabb75pVhcuqLv9++Mf/2hs3LjR+PLLL41Dhw4Zjz76qCHJ2LBhg1lduKD6+npj//79xv79+w1Jxh/+8Adj//79RlFRkWEY3j9+3e2ft43ffffdZ0RFRRnZ2dlGeXm562hqanK18fYx7EkfvWkcV6xYYWzbts0oKCgwPvvsM+NnP/uZYbVajS1bthiG4f3j193+edPYnc83rwLzlDEkAPWB//f//p+RkpJiBAUFGZMmTWp3eeqSJUuMmTNntmufnZ1tpKenG0FBQUZqaqqxZs2afq64e7rTv9/85jfGyJEjjZCQECMmJsaYPn268e6775pQddecu+T0m8eSJUsMw/D+8etu/7xt/DrrmyTjhRdecLXx9jHsSR+9aRx/8IMfuP58GTx4sHHNNde4woFheP/4dbd/3jR25/PNAOQpY2gxjLM7jQAAAPwEe4AAAIDfIQABAAC/QwACAAB+hwAEAAD8DgEIAAD4HQIQAADwOwQgAADgdwhAAADA7xCAAKALLBaLNm3aZHYZAHoJAQiAx1u6dKksFkuH47rrrjO7NABeKsDsAgCgK6677jq98MIL7c4FBwebVA0Ab8cMEACvEBwcrPj4+HZHTEyMJOfy1Jo1azR37lyFhoZq+PDh+tvf/tbu8wcPHtS3vvUthYaGauDAgbrnnnvU0NDQrs26des0btw4BQcHKyEhQT/60Y/avX/y5EnddNNNCgsL06WXXqp33nmnbzsNoM8QgAD4hCeeeEI333yzDhw4oEWLFun222/XkSNHJElNTU267rrrFBMTo08//VR/+9vf9OGHH7YLOGvWrNEDDzyge+65RwcPHtQ777yjSy65pN3P+MUvfqHbbrtNn332mb773e9q4cKFqqqq6td+Auglff68eQBw05IlSwybzWaEh4e3O5566inDMAxDkrF8+fJ2n8nMzDTuu+8+wzAMY+3atUZMTIzR0NDgev/dd981rFarUVFRYRiGYSQmJhqPPfbYeWuQZDz++OOu1w0NDYbFYjE2b97ca/0E0H/YAwTAK8yePVtr1qxpdy42Ntb1z9OmTWv33rRp05SbmytJOnLkiNLS0hQeHu56/6qrrpLD4dDRo0dlsVhUVlama6655oI1TJgwwfXP4eHhioiIUGVlZU+7BMBEBCAAXiE8PLzDktTFWCwWSZJhGK5/7qxNaGhol74vMDCww2cdDke3agLgGdgDBMAn7Nq1q8Pr0aNHS5LGjh2r3NxcNTY2ut7/+OOPZbVaddlllykiIkKpqan63//9336tGYB5mAEC4BWam5tVUVHR7lxAQIAGDRokSfrb3/6myZMna/r06Xr11Ve1e/duZWVlSZIWLlyon//851qyZIn+/d//XSdOnNCPf/xjLV68WHFxcZKkf//3f9fy5cs1ZMgQzZ07V/X19fr444/14x//uH87CqBfEIAAeIX3339fCQkJ7c6NGjVKX3zxhSTnFVpvvPGG7r//fsXHx+vVV1/V2LFjJUlhYWH6+9//rgcffFBXXHGFwsLCdPPNN+sPf/iD67uWLFmiM2fO6I9//KN++tOfatCgQbrlllv6r4MA+pXFMAzD7CIAwB0Wi0UbN27U/PnzzS4FgJdgDxAAAPA7BCAAAOB32AMEwOuxkg+gu5gBAgAAfocABAAA/A4BCAAA+B0CEAAA8DsEIAAA4HcIQAAAwO8QgAAAgN8hAAEAAL/z/wOdKlFK1OiCCQAAAABJRU5ErkJggg==" }, "metadata": {}, "output_type": "display_data" @@ -510,8 +504,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:30:31.500554Z", - "end_time": "2023-04-15T17:30:31.563414Z" + "end_time": "2024-01-13T09:05:36.267895100Z", + "start_time": "2024-01-13T09:05:36.138927700Z" } } }, @@ -533,12 +527,11 @@ ], "metadata": { "collapsed": false - }, - "execution_count": 25 + } }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 15, "outputs": [], "source": [ "# packages we need\n", @@ -548,14 +541,14 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:30:31.563414Z", - "end_time": "2023-04-15T17:30:31.579050Z" + "end_time": "2024-01-13T09:05:39.545832Z", + "start_time": "2024-01-13T09:05:39.538563Z" } } }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 16, "outputs": [], "source": [ "# define the model\n", @@ -564,14 +557,14 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:30:31.579050Z", - "end_time": "2023-04-15T17:30:31.657612Z" + "end_time": "2024-01-13T09:05:41.104484500Z", + "start_time": "2024-01-13T09:05:39.959724100Z" } } }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 17, "outputs": [], "source": [ "# define the loss function\n", @@ -586,14 +579,14 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:30:31.657612Z", - "end_time": "2023-04-15T17:30:31.675404Z" + "end_time": "2024-01-13T09:05:41.116952500Z", + "start_time": "2024-01-13T09:05:41.107734700Z" } } }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 18, "outputs": [], "source": [ "# define the gradient function which computes the\n", @@ -606,14 +599,14 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:30:31.675404Z", - "end_time": "2023-04-15T17:30:31.706738Z" + "end_time": "2024-01-13T09:05:41.783758700Z", + "start_time": "2024-01-13T09:05:41.775583Z" } } }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 19, "outputs": [], "source": [ "# define the optimizer we need\n", @@ -622,14 +615,14 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:30:31.706738Z", - "end_time": "2023-04-15T17:30:31.859345Z" + "end_time": "2024-01-13T09:05:42.802779100Z", + "start_time": "2024-01-13T09:05:42.679333700Z" } } }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 20, "outputs": [], "source": [ "# training function\n", @@ -643,42 +636,42 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:30:31.770882Z", - "end_time": "2023-04-15T17:30:31.859345Z" + "end_time": "2024-01-13T09:05:43.129074800Z", + "start_time": "2024-01-13T09:05:43.121707300Z" } } }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 21, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Step 100, Used 10.7392 s, Loss 0.9717, Acc 0.6601\n", - "Step 200, Used 8.6341 s, Loss 0.5624, Acc 0.7991\n", - "Step 300, Used 7.8616 s, Loss 0.5135, Acc 0.8158\n", - "Step 400, Used 5.1792 s, Loss 0.4775, Acc 0.8266\n", - "Step 500, Used 5.1241 s, Loss 0.4563, Acc 0.8346\n", - "Step 600, Used 5.5137 s, Loss 0.4494, Acc 0.8342\n", - "Step 700, Used 5.1346 s, Loss 0.4356, Acc 0.8417\n", - "Step 800, Used 5.2631 s, Loss 0.4338, Acc 0.8414\n", - "Step 900, Used 5.3202 s, Loss 0.4043, Acc 0.8520\n", - "Step 1000, Used 5.2687 s, Loss 0.4055, Acc 0.8528\n", - "Step 1100, Used 5.9954 s, Loss 0.4005, Acc 0.8543\n", - "Step 1200, Used 5.9213 s, Loss 0.3982, Acc 0.8542\n", - "Step 1300, Used 6.0832 s, Loss 0.3845, Acc 0.8595\n", - "Step 1400, Used 5.5973 s, Loss 0.3902, Acc 0.8575\n", - "Step 1500, Used 5.5119 s, Loss 0.3781, Acc 0.8624\n", - "Step 1600, Used 5.4341 s, Loss 0.3743, Acc 0.8632\n", - "Step 1700, Used 5.5067 s, Loss 0.3764, Acc 0.8626\n", - "Step 1800, Used 5.6223 s, Loss 0.3689, Acc 0.8645\n", - "Step 1900, Used 5.4748 s, Loss 0.3648, Acc 0.8672\n", - "Step 2000, Used 5.2963 s, Loss 0.3683, Acc 0.8674\n", - "Step 2100, Used 5.4844 s, Loss 0.3571, Acc 0.8699\n", - "Step 2200, Used 5.7304 s, Loss 0.3518, Acc 0.8726\n", - "Step 2300, Used 5.0767 s, Loss 0.3588, Acc 0.8666\n" + "Step 100, Used 58.4698 s, Loss 1.0859, Acc 0.6189\n", + "Step 200, Used 54.3465 s, Loss 0.5739, Acc 0.7942\n", + "Step 300, Used 56.5062 s, Loss 0.5237, Acc 0.8098\n", + "Step 400, Used 50.5268 s, Loss 0.4835, Acc 0.8253\n", + "Step 500, Used 50.2707 s, Loss 0.4628, Acc 0.8318\n", + "Step 600, Used 50.5184 s, Loss 0.4580, Acc 0.8305\n", + "Step 700, Used 50.7511 s, Loss 0.4345, Acc 0.8420\n", + "Step 800, Used 51.9514 s, Loss 0.4368, Acc 0.8414\n", + "Step 900, Used 51.5502 s, Loss 0.4128, Acc 0.8491\n", + "Step 1000, Used 51.4087 s, Loss 0.4140, Acc 0.8493\n", + "Step 1100, Used 50.1260 s, Loss 0.4113, Acc 0.8484\n", + "Step 1200, Used 50.2568 s, Loss 0.4038, Acc 0.8523\n", + "Step 1300, Used 51.7090 s, Loss 0.3912, Acc 0.8555\n", + "Step 1400, Used 51.2418 s, Loss 0.3937, Acc 0.8554\n", + "Step 1500, Used 50.1411 s, Loss 0.3870, Acc 0.8577\n", + "Step 1600, Used 50.4968 s, Loss 0.3765, Acc 0.8625\n", + "Step 1700, Used 50.8128 s, Loss 0.3811, Acc 0.8599\n", + "Step 1800, Used 52.4883 s, Loss 0.3744, Acc 0.8648\n", + "Step 1900, Used 55.2034 s, Loss 0.3686, Acc 0.8652\n", + "Step 2000, Used 51.4456 s, Loss 0.3738, Acc 0.8631\n", + "Step 2100, Used 51.8214 s, Loss 0.3593, Acc 0.8697\n", + "Step 2200, Used 50.2470 s, Loss 0.3571, Acc 0.8694\n", + "Step 2300, Used 51.7452 s, Loss 0.3623, Acc 0.8680\n" ] } ], @@ -715,8 +708,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "start_time": "2023-04-15T17:30:31.785862Z", - "end_time": "2023-04-15T17:32:51.154177Z" + "end_time": "2024-01-13T09:26:02.838665200Z", + "start_time": "2024-01-13T09:05:43.623356100Z" } } } diff --git a/docs/tutorial_training/build_training_models.ipynb b/docs/tutorial_training/build_training_models.ipynb index 67e876fb5..381efd668 100644 --- a/docs/tutorial_training/build_training_models.ipynb +++ b/docs/tutorial_training/build_training_models.ipynb @@ -267,7 +267,7 @@ } ], "source": [ - "rnn = bp.layers.RNNCell(1, 3, train_state=True, mode=bm.training_mode)\n", + "rnn = bp.dyn.RNNCell(1, 3, train_state=True, mode=bm.training_mode)\n", "\n", "rnn.state2train" ], @@ -285,7 +285,7 @@ "Note the difference between the *.state2train* and the original *.state*:\n", "\n", "1. *.state2train* has no batch axis.\n", - "2. When using `node.reset_state()` function, all values in the *.state* will be filled with *.state2train*." + "2. When using `node.reset()` function, all values in the *.state* will be filled with *.state2train*." ], "metadata": { "collapsed": false @@ -305,7 +305,7 @@ } ], "source": [ - "rnn.reset_state(batch_size=5)\n", + "rnn.reset(batch_size=5)\n", "rnn.state" ], "metadata": { diff --git a/docs/tutorial_training/esn_introduction.ipynb b/docs/tutorial_training/esn_introduction.ipynb index 15108c12e..f112e1832 100644 --- a/docs/tutorial_training/esn_introduction.ipynb +++ b/docs/tutorial_training/esn_introduction.ipynb @@ -15,7 +15,8 @@ ], "metadata": { "collapsed": false - } + }, + "id": "52bcffbb3719ddb8" }, { "cell_type": "code", @@ -71,7 +72,8 @@ "start_time": "2023-04-15T17:22:42.799905Z", "end_time": "2023-04-15T17:22:42.925296Z" } - } + }, + "id": "9b48823591979154" }, { "cell_type": "code", @@ -86,7 +88,8 @@ "start_time": "2023-04-15T17:22:42.909670Z", "end_time": "2023-04-15T17:22:43.342335Z" } - } + }, + "id": "27c24a791cc1b886" }, { "cell_type": "markdown", @@ -152,7 +155,8 @@ ], "metadata": { "collapsed": false - } + }, + "id": "f197ae9a685506f2" }, { "cell_type": "markdown", @@ -336,7 +340,8 @@ "start_time": "2023-04-15T17:22:45.452077Z", "end_time": "2023-04-15T17:22:45.545837Z" } - } + }, + "id": "3b6f5d5866d3fc77" }, { "cell_type": "code", @@ -418,7 +423,8 @@ "start_time": "2023-04-15T17:22:45.795921Z", "end_time": "2023-04-15T17:22:45.863307Z" } - } + }, + "id": "f111f4dcc4a24a3c" }, { "cell_type": "markdown", @@ -434,7 +440,7 @@ "outputs": [], "source": [ "model = ESN(1, 100, 1)\n", - "model.reset_state(1)\n", + "model.reset(1)\n", "trainer = bp.RidgeTrainer(model, alpha=1e-6)" ], "metadata": { @@ -443,7 +449,8 @@ "start_time": "2023-04-15T17:22:45.813349Z", "end_time": "2023-04-15T17:22:47.185659Z" } - } + }, + "id": "8ee754bea54618b5" }, { "cell_type": "code", @@ -472,7 +479,8 @@ "start_time": "2023-04-15T17:22:47.185659Z", "end_time": "2023-04-15T17:22:47.336957Z" } - } + }, + "id": "17b9abcfe4b14bb8" }, { "cell_type": "code", @@ -513,7 +521,8 @@ "start_time": "2023-04-15T17:22:47.336957Z", "end_time": "2023-04-15T17:22:51.431086Z" } - } + }, + "id": "f1911033693f39b8" }, { "cell_type": "markdown", @@ -582,7 +591,8 @@ "start_time": "2023-04-15T17:22:54.421317Z", "end_time": "2023-04-15T17:22:54.641561Z" } - } + }, + "id": "11c902d44d6e492" }, { "cell_type": "markdown", @@ -704,7 +714,7 @@ "outputs": [], "source": [ "model = ESN(1, 100, 1, sr=1.1)\n", - "model.reset_state(1)\n", + "model.reset(1)\n", "trainer = bp.RidgeTrainer(model, alpha=1e-6)" ] }, @@ -762,7 +772,8 @@ "start_time": "2023-04-15T17:22:56.170280Z", "end_time": "2023-04-15T17:22:59.795564Z" } - } + }, + "id": "d4a6bd45ef9a95fb" }, { "cell_type": "code", @@ -922,7 +933,7 @@ "plt.figure(figsize=(15, len(all_radius) * 3))\n", "for i, s in enumerate(all_radius):\n", " model = ESN(1, 100, 1, sr=s)\n", - " model.reset_state(1)\n", + " model.reset(1)\n", " runner = bp.DSTrainer(model, monitors={'state': model.r.state})\n", " _ = runner.predict(x_test[:, :10000])\n", " states = bm.as_numpy(runner.mon['state'])\n", @@ -1015,7 +1026,7 @@ "plt.figure(figsize=(15, len(all_radius) * 3))\n", "for i, s in enumerate(all_input_scaling):\n", " model = ESN(1, 100, 1, sr=1., Win_initializer=bp.init.Uniform(max_val=s))\n", - " model.reset_state(1)\n", + " model.reset(1)\n", " runner = bp.DSTrainer(model, monitors={'state': model.r.state})\n", " _ = runner.predict(x_test[:, :10000])\n", " states = bm.as_numpy(runner.mon['state'])\n", @@ -1032,7 +1043,8 @@ "start_time": "2023-04-15T17:23:03.672621Z", "end_time": "2023-04-15T17:23:05.593166Z" } - } + }, + "id": "767f67739348d608" }, { "cell_type": "markdown", @@ -1123,7 +1135,7 @@ "for i, s in enumerate(all_rates):\n", " model = ESN(1, 100, 1, sr=1., leaky_rate=s,\n", " Win_initializer=bp.init.Uniform(max_val=1.), )\n", - " model.reset_state(1)\n", + " model.reset(1)\n", " runner = bp.DSTrainer(model, monitors={'state': model.r.state})\n", " _ = runner.predict(x_test[:, :10000])\n", " states = bm.as_numpy(runner.mon['state'])\n", @@ -1140,7 +1152,8 @@ "start_time": "2023-04-15T17:23:05.583860Z", "end_time": "2023-04-15T17:23:07.952611Z" } - } + }, + "id": "7b16e199059d72c6" }, { "cell_type": "markdown", @@ -1226,7 +1239,7 @@ "for i, s in enumerate(all_rates):\n", " model = ESN(1, 100, 1, sr=1., leaky_rate=s,\n", " Win_initializer=bp.init.Uniform(max_val=.2), )\n", - " model.reset_state(1)\n", + " model.reset(1)\n", " runner = bp.DSTrainer(model, monitors={'state': model.r.state})\n", " _ = runner.predict(x_test[:, :10000])\n", " states = bm.as_numpy(runner.mon['state'])\n", @@ -1276,7 +1289,8 @@ "start_time": "2023-04-15T17:23:10.429696Z", "end_time": "2023-04-15T17:23:10.638953Z" } - } + }, + "id": "d942eb4d0a5a27d5" }, { "cell_type": "code", @@ -1305,7 +1319,8 @@ "start_time": "2023-04-15T17:23:10.529119Z", "end_time": "2023-04-15T17:23:10.732996Z" } - } + }, + "id": "1132c7e051073064" }, { "cell_type": "code", @@ -1313,7 +1328,7 @@ "outputs": [], "source": [ "model = ESN(1, 100, 1, sr=1.1, Win_initializer=bp.init.Uniform(max_val=.2), )\n", - "model.reset_state(1)\n", + "model.reset(1)\n", "trainer = bp.RidgeTrainer(model, alpha=1e-7)" ], "metadata": { @@ -1322,7 +1337,8 @@ "start_time": "2023-04-15T17:23:10.701426Z", "end_time": "2023-04-15T17:23:10.732996Z" } - } + }, + "id": "24f5afb89676f85d" }, { "cell_type": "code", @@ -1393,7 +1409,8 @@ "start_time": "2023-04-15T17:23:10.717352Z", "end_time": "2023-04-15T17:23:11.805928Z" } - } + }, + "id": "f0e83001b366259" }, { "cell_type": "code", @@ -1426,7 +1443,8 @@ "start_time": "2023-04-15T17:23:11.800931Z", "end_time": "2023-04-15T17:23:11.998557Z" } - } + }, + "id": "1cc52727c49eb6e9" }, { "cell_type": "code", @@ -1441,7 +1459,8 @@ "start_time": "2023-04-15T17:23:11.998557Z", "end_time": "2023-04-15T17:23:12.081165Z" } - } + }, + "id": "ae4549cad507015e" }, { "cell_type": "code", @@ -1462,7 +1481,8 @@ "start_time": "2023-04-15T17:23:12.017029Z", "end_time": "2023-04-15T17:23:12.351736Z" } - } + }, + "id": "13c7def22a1da6e0" }, { "cell_type": "code", @@ -1490,7 +1510,8 @@ "start_time": "2023-04-15T17:23:12.340448Z", "end_time": "2023-04-15T17:23:12.496935Z" } - } + }, + "id": "b415c3a3f2a6dfe5" }, { "cell_type": "markdown", diff --git a/docs/tutorial_training/offline_training.ipynb b/docs/tutorial_training/offline_training.ipynb index 8d4bc7111..d0cb6b82d 100644 --- a/docs/tutorial_training/offline_training.ipynb +++ b/docs/tutorial_training/offline_training.ipynb @@ -479,7 +479,7 @@ ], "source": [ "model = ESN(3, 100, 3)\n", - "model.reset_state(1)\n", + "model.reset(1)\n", "trainer = bp.OfflineTrainer(model, fit_method=bp.algorithms.LinearRegression())\n", "\n", "_ = trainer.predict(X_warmup)\n", diff --git a/docs/tutorial_training/online_training.ipynb b/docs/tutorial_training/online_training.ipynb index 4c6894aa3..f5a90194b 100644 --- a/docs/tutorial_training/online_training.ipynb +++ b/docs/tutorial_training/online_training.ipynb @@ -209,7 +209,7 @@ "outputs": [], "source": [ "model = NGRC(3)\n", - "model.reset_state(1)" + "model.reset(1)" ], "metadata": { "collapsed": false,