đ Common API#
- class serket.Sequential(*a, **k)[source]#
A sequential container for layers.
- Parameters:
layers â a tuple or a list of layers. if a list is passed, it will be casted to a tuple to maintain immutable behavior.
Example
>>> import jax.numpy as jnp >>> import jax.random as jr >>> import serket as sk >>> layers = sk.Sequential(lambda x: x + 1, lambda x: x * 2) >>> print(layers(jnp.array([1, 2, 3]), key=jr.key(0))) [4 6 8]
Note
Layer might be a function or a class with a
__call__method, additionally it might have a key argument for random number generation.
- serket.tree_state(tree, **kwargs)[source]#
Build state for a tree of layers.
Some layers require state to be initialized before training. For example,
nn.BatchNormlayers requiresrunning_meanandrunning_varto be initialized before training. This function initializes the state for a tree of layers, based on the layer definedstaterule usingtree_state.def_state.tree_state()objective is to provide a simple and consistent way to initialize state for a tree of layers. Specifically, it provides a way to separate the state initialization logic from the layer definition. This allows for a more clear separation of concerns, and makes it easier to define new layers.- Parameters:
tree (
TypeVar(T)) â A tree of layers.kwargs â Keyword arguments to pass to the state initialization rule. of the tree layers.
- Return type:
TypeVar(T)- Returns:
A tree of state leaves if it has state, otherwise
NoStateplaceholder.
Note
To define a state initialization rule for a custom layer, use the decorator
tree_state.def_state()on a function that accepts the layer as the first argument, for any additional arguments, use keyword only arguments.>>> import jax >>> import serket as sk >>> class LayerWithState(sk.TreeClass): ... pass >>> # state function accept the `layer` and input array >>> @sk.tree_state.def_state(LayerWithState) ... def _(leaf, *, input: jax.Array) -> jax.Array: ... return jax.random.normal(jax.random.key(0), input.shape) >>> sk.tree_state(LayerWithState(), input=jax.numpy.ones((1, 1))).shape (1, 1)
Example
>>> import jax.numpy as jnp >>> import serket as sk >>> import jax.random as jr >>> tree = [1, 2, sk.nn.BatchNorm(5, key=jr.key(0))] >>> sk.tree_state(tree) [NoState(), NoState(), BatchNormState( running_mean=f32[5](Îŧ=0.00, Ī=0.00, â[0.00,0.00]), running_var=f32[5](Îŧ=1.00, Ī=0.00, â[1.00,1.00]) )]
- serket.tree_eval(tree)[source]#
Modify tree layers to disable any trainning related behavior.
For example,
nn.Dropoutlayer is replaced by annn.Identitylayer andnn.BatchNormlayer is replaced byEvalBatchNormlayer when evaluating the tree.tree_eval()objective is to provide a simple and consistent way to disable any trainning related behavior for a tree of layers. Specifically, it provides a way to separate the evaluation logic from the layer definition. This allows for a more clear separation of concerns, and makes it easier to define new layers that has a single behavior.- Parameters:
tree â A tree of layers.
- Returns:
A tree of layers with evaluation behavior of same structure as
tree.
Example
>>> # dropout is replaced by an identity layer in evaluation mode >>> # by registering `tree_eval.def_eval(sk.nn.Dropout, sk.nn.Identity)` >>> import jax.numpy as jnp >>> import serket as sk >>> layer = sk.nn.Dropout(0.5) >>> sk.tree_eval(layer) Identity()
Note
To define evaluation rule for a custom layer, use the decorator
tree_eval.def_eval()on a function that accepts the layer. The function should return the evaluation layer.>>> import serket as sk >>> import jax >>> class AddOne(sk.TreeClass): ... def __call__(self, input: jax.Array) -> jax.Array: ... return input + 1 >>> input = jax.numpy.ones([3, 3]) >>> add_one = AddOne() >>> print(add_one(input)) # add one to each element [[2. 2. 2.] [2. 2. 2.] [2. 2. 2.]] >>> class AddOneEval(sk.TreeClass): ... def __call__(self, input: jax.Array) -> jax.Array: ... return input # no-op >>> # register `AddOne` to be replaced by `AddOneEval` in evaluation mode >>> @sk.tree_eval.def_eval(AddOne) ... def _(_: AddOne) -> AddOneEval: ... return AddOneEval() >>> print(sk.tree_eval(add_one)(input)) [[1. 1. 1.] [1. 1. 1.] [1. 1. 1.]]