Normalization#
- class serket.nn.LayerNorm(normalized_shape, *, key, weight_init='ones', bias_init='zeros', dtype=<class 'jax.numpy.float32'>, eps=1e-05)[source]#
Layer Normalization
Transform the input by scaling and shifting to have zero mean and unit variance.
- Parameters:
normalized_shape (
int|tuple[int,...] |None) â the shape of the input to be normalized.key (
Array) â a random key for initialization of the scale and shift.weight_init (
Union[Literal['he_normal','he_uniform','glorot_normal','glorot_uniform','lecun_normal','lecun_uniform','normal','uniform','ones','zeros','xavier_normal','xavier_uniform','orthogonal'],Callable[[Array,Tuple[int,...],Union[dtype,str,Any]],Array|None]]) â a function to initialize the scale. Defaults to ones. ifNone, the scale is not trainable.bias_init (
Union[Literal['he_normal','he_uniform','glorot_normal','glorot_uniform','lecun_normal','lecun_uniform','normal','uniform','ones','zeros','xavier_normal','xavier_uniform','orthogonal'],Callable[[Array,Tuple[int,...],Union[dtype,str,Any]],Array|None]]) â a function to initialize the shift. Defaults to zeros. ifNone, the shift is not trainable.dtype (
Union[dtype,str,Any]) â dtype of the weights and biases.float32eps (
float) â a value added to the denominator for numerical stability.
Example
>>> import serket as sk >>> import jax.random as jr >>> import jax.numpy as jnp >>> import numpy.testing as npt >>> C, H, W = 4, 5, 6 >>> k1, k2 = jr.split(jr.key(0), 2) >>> input = jr.uniform(k1, shape=(C, H, W)) >>> layer = sk.nn.LayerNorm((H, W), key=k2) >>> output = layer(input) >>> mean = jnp.mean(input, axis=(1, 2), keepdims=True) >>> var = jnp.var(input, axis=(1, 2), keepdims=True) >>> npt.assert_allclose((input - mean) / jnp.sqrt(var + 1e-5), output, atol=1e-5)
Note
LayerNormsupports lazy initialization, meaning that the weights and biases are not initialized until the first call to the layer. This is useful when the input shape is not known at initialization time.To use lazy initialization, pass
Noneas thenormalized_shapeargument and usevalue_and_tree()to call the layer and return the method output and the material layer.>>> import serket as sk >>> import jax.numpy as jnp >>> import jax.random as jr >>> input = jnp.ones((5,10)) >>> key = jr.key(0) >>> lazy = sk.nn.LayerNorm(None, key=key) >>> _, material = sk.value_and_tree(lambda lazy: lazy(input))(lazy) >>> material(input).shape (5, 10)
- Reference:
-
eps:
float# - Field Information:
Name:
eps- Callbacks:
On setting attribute:
Range(min_val=0, max_val=inf, min_inclusive=False, max_inclusive=True)ScalarLike()
- class serket.nn.InstanceNorm(in_features, *, key, eps=1e-05, weight_init='ones', bias_init='zeros', dtype=<class 'jax.numpy.float32'>)[source]#
Instance Normalization
Transform the input by scaling and shifting to have zero mean and unit variance.
- Parameters:
in_features â the shape of the input to be normalized.
key (
Array) â a random key for initialization.eps (
float) â a value added to the denominator for numerical stability.weight_init (
Union[Literal['he_normal','he_uniform','glorot_normal','glorot_uniform','lecun_normal','lecun_uniform','normal','uniform','ones','zeros','xavier_normal','xavier_uniform','orthogonal'],Callable[[Array,Tuple[int,...],Union[dtype,str,Any]],Array|None]]) â a function to initialize the scale. Defaults to ones. if None, the scale is not trainable.bias_init (
Union[Literal['he_normal','he_uniform','glorot_normal','glorot_uniform','lecun_normal','lecun_uniform','normal','uniform','ones','zeros','xavier_normal','xavier_uniform','orthogonal'],Callable[[Array,Tuple[int,...],Union[dtype,str,Any]],Array|None]]) â a function to initialize the shift. Defaults to zeros. if None, the shift is not trainable.dtype (
Union[dtype,str,Any]) â dtype of the weights and biases.float32
Example
>>> import serket as sk >>> import jax.numpy as jnp >>> import jax.random as jr >>> key = jr.key(0) >>> layer = sk.nn.InstanceNorm(5, key=key) >>> input = jnp.ones((5,10)) >>> layer(input).shape (5, 10)
Note
InstanceNormsupports lazy initialization, meaning that the weights and biases are not initialized until the first call to the layer. This is useful when the input shape is not known at initialization time.To use lazy initialization, pass
Noneas thein_featuresargument and usevalue_and_tree()to call the layer and return the method output and the material layer.>>> import serket as sk >>> import jax.numpy as jnp >>> import jax.random as jr >>> key = jr.key(0) >>> lazy = sk.nn.InstanceNorm(None, key=key) >>> input = jnp.ones((5,10)) >>> _, material = sk.value_and_tree(lambda lazy: lazy(input))(lazy) >>> material(input).shape (5, 10)
- Reference:
-
eps:
float# - Field Information:
Name:
eps- Callbacks:
On setting attribute:
Range(min_val=0, max_val=inf, min_inclusive=True, max_inclusive=True)ScalarLike()
- class serket.nn.GroupNorm(in_features, *, key, groups, eps=1e-05, weight_init='ones', bias_init='zeros', dtype=<class 'jax.numpy.float32'>)[source]#
Group Normalization
Transform the input by scaling and shifting to have zero mean and unit variance.
- Parameters:
in_features â the shape of the input to be normalized.
key (
Array) â a random key for initialization.groups (
int) â number of groups to separate the channels into.eps (
float) â a value added to the denominator for numerical stability.weight_init (
Union[Literal['he_normal','he_uniform','glorot_normal','glorot_uniform','lecun_normal','lecun_uniform','normal','uniform','ones','zeros','xavier_normal','xavier_uniform','orthogonal'],Callable[[Array,Tuple[int,...],Union[dtype,str,Any]],Array|None]]) â a function to initialize the scale. Defaults to ones. if None, the scale is not trainable.bias_init (
Union[Literal['he_normal','he_uniform','glorot_normal','glorot_uniform','lecun_normal','lecun_uniform','normal','uniform','ones','zeros','xavier_normal','xavier_uniform','orthogonal'],Callable[[Array,Tuple[int,...],Union[dtype,str,Any]],Array|None]]) â a function to initialize the shift. Defaults to zeros. if None, the shift is not trainable.dtype (
Union[dtype,str,Any]) â dtype of the weights and biases.float32
Example
>>> import serket as sk >>> import jax.numpy as jnp >>> import jax.random as jr >>> key = jr.key(0) >>> layer = sk.nn.GroupNorm(5, groups=1, key=key) >>> input = jnp.ones((5,10)) >>> layer(input).shape (5, 10)
Note
GroupNormsupports lazy initialization, meaning that the weights and biases are not initialized until the first call to the layer. This is useful when the input shape is not known at initialization time.To use lazy initialization, pass
Noneas thein_featuresargument and usevalue_and_tree()to call the layer and return the method output and the material layer.>>> import serket as sk >>> import jax.numpy as jnp >>> import jax.random as jr >>> key = jr.key(0) >>> lazy = sk.nn.GroupNorm(None, groups=5, key=key) >>> input = jnp.ones((5,10)) >>> _, material = sk.value_and_tree(lambda lazy: lazy(input))(lazy) >>> material(input).shape (5, 10)
- Reference:
-
eps:
float# - Field Information:
Name:
eps- Callbacks:
On setting attribute:
Range(min_val=0, max_val=inf, min_inclusive=True, max_inclusive=True)ScalarLike()
- class serket.nn.BatchNorm(in_features, *, key, momentum=0.99, eps=1e-05, weight_init='ones', bias_init='zeros', axis=1, axis_name=None, dtype=<class 'jax.numpy.float32'>)[source]#
Applies normalization over batched inputs`
Warning
- Works under
jax.vmap(BatchNorm(...), in_axes=(0, None), out_axes=(0, None))(input, state)
otherwise will be a no-op.
- Training behavior:
output = (input - batch_mean) / sqrt(batch_var + eps)running_mean = momentum * running_mean + (1 - momentum) * batch_meanrunning_var = momentum * running_var + (1 - momentum) * batch_var
For evaluation, use
tree_eval()to convert the layer toEvalBatchNorm.- Parameters:
in_features (
int) â the shape of the input to be normalized.key (
Array) â a random key to initialize the parameters.momentum (
float) â the value used for therunning_meanandrunning_varcomputation. must be a number between0and1.eps (
float) â a value added to the denominator for numerical stability.weight_init (
Union[Literal['he_normal','he_uniform','glorot_normal','glorot_uniform','lecun_normal','lecun_uniform','normal','uniform','ones','zeros','xavier_normal','xavier_uniform','orthogonal'],Callable[[Array,Tuple[int,...],Union[dtype,str,Any]],Array|None]]) â a function to initialize the scale. Defaults to ones. if None, the scale is not trainable.bias_init (
Union[Literal['he_normal','he_uniform','glorot_normal','glorot_uniform','lecun_normal','lecun_uniform','normal','uniform','ones','zeros','xavier_normal','xavier_uniform','orthogonal'],Callable[[Array,Tuple[int,...],Union[dtype,str,Any]],Array|None]]) â a function to initialize the shift. Defaults to zeros. if None, the shift is not trainable.axis (
int) â the feature axis that should be normalized. Defaults to 1. i.e. the other axes are reduced over.axis_name (
Optional[str]) â the axis name passed tojax.lax.pmean. Defaults to None.dtype (
Union[dtype,str,Any]) â dtype of the weights and biases.float32
Example
>>> import jax >>> import serket as sk >>> import jax.random as jr >>> bn = sk.nn.BatchNorm(10, key=jr.key(0)) >>> state = sk.tree_state(bn) >>> key = jr.key(0) >>> input = jr.uniform(key, shape=(5, 10)) >>> output, state = jax.vmap(bn, in_axes=(0, None), out_axes=(0, None))(input, state)
Example
Working with
BatchNormwith threading the state.>>> import jax >>> import serket as sk >>> import jax.random as jr >>> import jax.numpy as jnp >>> class ThreadedBatchNorm(sk.TreeClass): ... def __init__(self, *, key: jax.Array): ... k1, k2 = jax.random.split(key) ... self.bn1 = sk.nn.BatchNorm(5, axis=-1, key=k1) ... self.bn2 = sk.nn.BatchNorm(5, axis=-1, key=k2) ... def __call__(self, input, state): ... input, bn1 = self.bn1(input, state.bn1) ... input = input + 1.0 ... input, bn2 = self.bn2(input, state.bn2) ... # update the output state ... state = state.at["bn1"].set(bn1).at["bn2"].set(bn2) ... return input, state >>> net: ThreadedBatchNorm = ThreadedBatchNorm(key=jr.key(0)) >>> # initialize state as the same structure as tree >>> state: ThreadedBatchNorm = sk.tree_state(net) >>> inputs = jnp.linspace(-jnp.pi, jnp.pi, 50 * 20).reshape(20, 10, 5) >>> for input in inputs: ... output, state = jax.vmap(net, in_axes=(0, None), out_axes=(0, None))(input, state)
Example
Working with
BatchNormwithout threading the state.Instead of threading a state in and out of the layerâs
__call__method as previously shown, this example demonstrates a state that is integrated within the layer, akin to the approaches used in Keras or PyTorch. However, since the state is embedded in the layer, some additional work is required to make sure the layer works within the functional paradigm by using theatfunctionality, which is illustrated in the example below.>>> import jax >>> import serket as sk >>> import jax.random as jr >>> import functools as ft >>> class UnthreadedBatchNorm(sk.TreeClass): ... def __init__(self, *, key: jax.Array): ... k1, k2 = jax.random.split(key) ... self.bn1 = sk.nn.BatchNorm(5, axis=-1, key=k1) ... self.bn1_state = sk.tree_state(self.bn1) ... self.bn2 = sk.nn.BatchNorm(5, axis=-1, key=k2) ... self.bn2_state = sk.tree_state(self.bn2) ... def __call__(self, input): ... # this method will raise `AttributeError` if used directly ... # because this method mutates the state ... # instead, use `value_and_tree` to call the layer and return ... # the output and updated state in a functional manner ... input, self.bn1_state = self.bn1(input, self.bn1_state) ... input = input + 1.0 ... input, self.bn2_state = self.bn2(input, self.bn2_state) ... return input >>> # define a function to mask and unmask the net across `vmap` >>> # this is necessary because `vmap` needs the output to be of `jaxtype` >>> def mask_vmap(net, input): ... @ft.partial(jax.vmap, out_axes=(0, None)) ... def forward(input): ... output, new_net = sk.value_and_tree(lambda net: net(input))(net) ... return output, sk.tree_mask(new_net) ... return sk.tree_unmask(forward(input)) >>> net: UnthreadedBatchNorm = UnthreadedBatchNorm(key=jr.key(0)) >>> inputs = jnp.linspace(-jnp.pi, jnp.pi, 50 * 20).reshape(20, 10, 5) >>> for input in inputs: ... output, net = mask_vmap(net, input)
Note
BatchNormsupports lazy initialization, meaning that the weights and biases are not initialized until the first call to the layer. This is useful when the input shape is not known at initialization time.To use lazy initialization, pass
Noneas thein_featuresargument and usevalue_and_tree()to call the layer and return the method output and the material layer.>>> import serket as sk >>> import jax.numpy as jnp >>> import jax.random as jr >>> key = jr.key(0) >>> lazy = sk.nn.BatchNorm(None, key=key) >>> input = jnp.ones((5,10)) >>> _ , material = sk.value_and_tree(lambda lazy: lazy(input, None))(lazy) >>> state = sk.tree_state(material) >>> output, state = jax.vmap(material, in_axes=(0, None), out_axes=(0, None))(input, state) >>> output.shape (5, 10)
Note
If
axis_nameis specified, thenaxis_nameargument must be passed tojax.vmaporjax.pmap.- Reference:
- class serket.nn.EvalBatchNorm(in_features, *, key, momentum=0.99, eps=1e-05, weight_init='ones', bias_init='zeros', axis=1, axis_name=None, dtype=<class 'jax.numpy.float32'>)[source]#
Applies normalization evlaution step over batched inputs`
This layer intended to be the evaluation step of
BatchNorm. and to be used withjax.vmap. It will be a no-op when unbatched.Warning
- Works under
jax.vmap(BatchNorm(...), in_axes=(0, None), out_axes=(0, None))(input, state)
otherwise will be a no-op.
- Evaluation behavior:
output = (input - running_mean) / sqrt(running_var + eps)
- Parameters:
in_features (
int) â the shape of the input to be normalized.key (
Array) â a random key to initialize the parameters.momentum (
float) â the value used for therunning_meanandrunning_varcomputation. must be a number between0and1. this value is ignored in evaluation mode, but kept for conversion tonn.BatchNorm.eps (
float) â a value added to the denominator for numerical stability.weight_init (
Union[Literal['he_normal','he_uniform','glorot_normal','glorot_uniform','lecun_normal','lecun_uniform','normal','uniform','ones','zeros','xavier_normal','xavier_uniform','orthogonal'],Callable[[Array,Tuple[int,...],Union[dtype,str,Any]],Array|None]]) â a function to initialize the scale. Defaults to ones. if None, the scale is not trainable.bias_init (
Union[Literal['he_normal','he_uniform','glorot_normal','glorot_uniform','lecun_normal','lecun_uniform','normal','uniform','ones','zeros','xavier_normal','xavier_uniform','orthogonal'],Callable[[Array,Tuple[int,...],Union[dtype,str,Any]],Array|None]]) â a function to initialize the shift. Defaults to zeros. if None, the shift is not trainable.axis (
int) â the axis that should be normalized. Defaults to 1.axis_name (
Optional[str]) â the axis name passed tojax.lax.pmean. Defaults to None.dtype (
Union[dtype,str,Any]) â dtype of the weights and biases.float32
Example
>>> import jax >>> import serket as sk >>> import jax.random as jr >>> bn = sk.nn.BatchNorm(10, key=jr.key(0)) >>> state = sk.tree_state(bn) >>> input = jax.random.uniform(jr.key(0), shape=(5, 10)) >>> output, state = jax.vmap(bn, in_axes=(0, None), out_axes=(0, None))(input, state) >>> # convert to evaluation mode >>> bn = sk.tree_eval(bn) >>> output, state = jax.vmap(bn, in_axes=(0, None), out_axes=(0,None))(input, state)
Note
If
axis_nameis specified, thenaxis_nameargument must be passed tojax.vmaporjax.pmap.
- serket.nn.layer_norm(input, weight, bias, normalized_shape, eps=None)[source]#
Layer Normalization
Normalizes the input by scaling and shifting to have zero mean and unit variance over the last
len(normalized_shape)dimensions.- Parameters:
input (
Array) â the input to be normalized.weight (
Array|None) â the scale. if None, the scale is not trainable.bias (
Array|None) â the shift. if None, the shift is not trainable.normalized_shape (
Sequence[int]) â the shape of the input to be normalized. Accepts a tuple of integers to denote the shape of the input to be normalized. The lastlen(normalized_shape)dimensions will be normalized.eps (
Optional[float]) â a value added to the denominator for numerical stability. defaults tojnp.finfo(input.dtype).epsifNoneis passed.
- Return type:
Array
- serket.nn.instance_norm(input, weight, bias, eps)[source]#
Instance Normalization
- Parameters:
input (
Array) â the input to be normalized.weight (
Array|None) â the scale. if None, the scale is not trainable.bias (
Array|None) â the shift. if None, the shift is not trainable.eps (
float) â a value added to the denominator for numerical stability.
- Return type:
Array
- serket.nn.group_norm(input, weight, bias, eps, groups)[source]#
Group Normalization
- Parameters:
input (
Array) â the input to be normalized.weight (
Array|None) â the scale. if None, the scale is not trainable.bias (
Array|None) â the shift. if None, the shift is not trainable.eps (
float) â a value added to the denominator for numerical stability.groups (
int) â number of groups to separate the features into.
- Return type:
Array
- serket.nn.batch_norm(input, running_mean, running_var, momentum=0.1, eps=0.001, weight=None, bias=None, axis=1, axis_name=None)[source]#
Batch Normalization
- Computes:
output = (input - batch_mean) / sqrt(batch_var + eps)running_mean = momentum * running_mean + (1 - momentum) * batch_meanrunning_var = momentum * running_var + (1 - momentum) * batch_var
- Parameters:
input (
Array) â the input to be normalized.running_mean (
Array) â the running mean of the input.running_var (
Array) â the running variance of the input.momentum (
float) â the value used for therunning_meanandrunning_varcomputation. must be a number between0and1.eps (
float) â a value added to the denominator for numerical stability.weight (
Optional[Array]) â the scale. if None, the scale is not trainable.bias (
Optional[Array]) â the shift. if None, the shift is not trainable.axis (
int) â the axis that should be normalized. Defaults to 1.axis_name (
Optional[str]) â the axis name passed tojax.lax.pmean. Defaults to None.
- Return type:
tuple[Array,Array,Array]- Returns:
normalized_inputrunning_meanrunning_var
- serket.nn.eval_batch_norm(input, running_mean, running_var, momentum=0.1, eps=0.001, weight=None, bias=None, axis=1, axis_name=None)[source]#
Batch Normalization Evaluation Step
- Computes:
output = (input - running_mean) / sqrt(running_var + eps)
- Parameters:
input (
Array) â the input to be normalized.running_mean (
Array) â the running mean of the input.running_var (
Array) â the running variance of the input.momentum (
float) â the value used for therunning_meanandrunning_varcomputation. must be a number between0and1.eps (
float) â a value added to the denominator for numerical stability.weight (
Optional[Array]) â the scale. if None, the scale is not trainable.bias (
Optional[Array]) â the shift. if None, the shift is not trainable.axis (
int) â the axis that should be normalized. Defaults to 1.axis_name (
Optional[str]) â the axis name passed tojax.lax.pmean. Defaults to None.
- Return type:
tuple[Array,Array,Array]- Returns:
normalized_inputrunning_meanrunning_var
- serket.nn.weight_norm(leaf, axis=-1, eps=1e-12)[source]#
Apply L2 weight normalization to an input.
- Parameters:
leaf (
TypeVar(T)) â the input to be normalized. Ifleafis not an array, then it will be returned as is.axis (
int|None) â the feature axis to be normalized. defaults to -1.eps (
float) â the epsilon value to be added to the denominator. defaults to 1e-12.
- Return type:
TypeVar(T)
Example
Normalize
weightarrays of two-layer linear network but notbias>>> import jax >>> import jax.numpy as jnp >>> import serket as sk >>> class Net(sk.TreeClass): ... def __init__(self, *, key: jax.Array): ... k1, k2 = jax.random.split(key) ... self.l1 = sk.nn.Linear(2, 4, key=k1) ... self.l2 = sk.nn.Linear(4, 2, key=k2) ... def __call__(self, inputs: jax.Array) -> jax.Array: ... # `...` selects all the first level nodes of `Net` (e.g. `l1`, `l2`) ... # then the `weight` attribute of each layer at the second level ... self = self.at[...]["weight"].apply(sk.nn.weight_norm) ... return self.l2(self.l1(inputs))
- Reference: