snn.layers¶
Base¶
Dense¶
- class snn.layers.Dense(units, activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', name=None)[source]¶
Bases:
LayerFully-connected (dense) layer.
- Parameters:
units (int) – Number of output neurons.
activation (str or Activation, optional) – Activation function applied after the linear transform.
use_bias (bool) – Whether to include a bias vector.
kernel_initializer (str or callable) – Initializer for the weight matrix W.
bias_initializer (str or callable) – Initializer for the bias vector b.
- property params¶
- property grads¶
Conv2D¶
- class snn.layers.Conv2D(filters, kernel_size=3, stride=1, padding='valid', activation=None, use_bias=True, kernel_initializer='he_normal', bias_initializer='zeros', name=None)[source]¶
Bases:
Layer2D Convolutional layer.
Expects input shape: (N, H, W, C_in) — channels-last convention.
- Parameters:
filters (int) – Number of output filters (channels).
kernel_size (int or (int, int)) – Size of the convolution kernel.
stride (int) – Stride of the convolution.
padding (str or int) – ‘same’, ‘valid’, or an explicit integer pad.
activation (str or Activation) – Applied after convolution + bias.
use_bias (bool)
kernel_initializer (str or callable)
bias_initializer (str or callable)
- property params¶
- property grads¶
Pooling¶
- class snn.layers.MaxPooling2D(pool_size=2, stride=None, name=None)[source]¶
Bases:
Layer2D Max Pooling layer (channels-last: N, H, W, C).
- class snn.layers.AveragePooling2D(pool_size=2, stride=None, name=None)[source]¶
Bases:
Layer2D Average Pooling layer (channels-last: N, H, W, C).
Normalisation¶
- class snn.layers.BatchNormalization(axis=-1, momentum=0.99, epsilon=1e-05, center=True, scale=True, name=None)[source]¶
Bases:
LayerBatch Normalization layer.
Normalizes activations over the batch dimension. During training uses batch statistics; during inference uses running (exponential moving average) statistics.
- Parameters:
axis (int) – Axis to normalize (usually the features/channels axis). For Dense output (N, F) use axis=-1. For Conv2D output (N, H, W, C) use axis=-1.
momentum (float) – Momentum for the moving average (typically 0.99).
epsilon (float) – Small constant for numerical stability.
center (bool) – If True, add learnable beta offset.
scale (bool) – If True, multiply by learnable gamma scale.
- property params¶
- property grads¶
Regularisation¶
- class snn.layers.Dropout(rate=0.5, seed=None, name=None)[source]¶
Bases:
LayerDropout regularization layer.
During training, randomly sets a fraction rate of inputs to zero and scales the remaining values by 1 / (1 - rate) (inverted dropout). During inference, the layer is a pass-through.
- Parameters:
rate (float) – Fraction of units to drop (0 <= rate < 1).
seed (int, optional) – Random seed for reproducibility.
Shape Manipulation¶
Conv1D¶
- class snn.layers.Conv1D(filters, kernel_size, stride=1, padding='valid', activation=None, use_bias=True, kernel_initializer='glorot_uniform', name=None)[source]¶
Bases:
Layer1-D Convolution layer (channels-last: batch, length, channels).
Slides a bank of
filterskernels of widthkernel_sizealong the time/sequence axis. Useful for local pattern detection in sequences (text, audio, time-series).- Parameters:
filters (int) – Number of output channels (kernels).
kernel_size (int) – Width of each convolutional kernel.
stride (int) – Step between successive windows (default 1).
padding (str) –
"valid"— no padding, output shorter than input."same"— zero-pad so output length equals input length (only whenstride=1).activation (str or Activation) – Applied after the convolution.
use_bias (bool) – Whether to include a bias term.
kernel_initializer (str) – Weight initialiser (default
"glorot_uniform").shape (Input / output)
--------------------
``(batch (→) –
length
in_channels)``
``(batch –
out_length
filters)``
1. (where out_length = (length + 2*pad - kernel_size) // stride +)
Examples
>>> conv = Conv1D(filters=32, kernel_size=3, activation='relu') >>> x = np.random.randn(4, 50, 8) # (batch, seq, channels) >>> out = conv.forward(x) # (4, 48, 32) with valid padding
- property params¶
- property grads¶
1D Pooling¶
- class snn.layers.MaxPooling1D(pool_size=2, stride=None, name=None)[source]¶
Bases:
Layer1-D Max Pooling over the time/sequence axis.
- Parameters:
pool_size (int) – Size of the pooling window (default 2).
stride (int) – Step between windows (default equals
pool_size).shape (Input / output)
--------------------
``(batch (channels)`` →) –
length
``(batch –
out_length
channels)``
- class snn.layers.AveragePooling1D(pool_size=2, stride=None, name=None)[source]¶
Bases:
Layer1-D Average Pooling over the time/sequence axis.
- Parameters:
pool_size (int) – Width of each pooling window (default 2).
stride (int) – Step between windows (default equals
pool_size).
- class snn.layers.GlobalAveragePooling1D(trainable=True, name=None)[source]¶
Bases:
LayerGlobal Average Pooling over the time/sequence axis.
Reduces
(batch, seq_len, features)to(batch, features)by averaging overseq_len. Standard way to collapse a Transformer or LSTM output into a fixed-size representation for classification.Examples
>>> gap = GlobalAveragePooling1D() >>> x = np.random.randn(8, 20, 64) # (batch, seq, features) >>> out = gap.forward(x) # (8, 64)
- class snn.layers.GlobalMaxPooling1D(trainable=True, name=None)[source]¶
Bases:
LayerGlobal Max Pooling over the time/sequence axis.
Reduces
(batch, seq_len, features)to(batch, features)by taking the maximum overseq_len.Examples
>>> gmp = GlobalMaxPooling1D() >>> x = np.random.randn(8, 20, 64) >>> out = gmp.forward(x) # (8, 64)
Recurrent¶
- class snn.layers.SimpleRNN(units, activation='tanh', return_sequences=False, return_state=False, kernel_initializer='glorot_uniform', recurrent_initializer='orthogonal', bias_initializer='zeros', name=None)[source]¶
Bases:
LayerVanilla (Elman) Recurrent Neural Network cell.
- Parameters:
units (int) – Number of hidden units.
activation (str or Activation) – Activation applied to the hidden state (default: ‘tanh’).
return_sequences (bool) – If True, return output at every time step; else only the last.
return_state (bool) – If True, return (output, last_hidden_state) tuple.
kernel_initializer (str or callable)
recurrent_initializer (str or callable)
bias_initializer (str or callable)
- property params¶
- property grads¶
- class snn.layers.LSTM(units, return_sequences=False, return_state=False, kernel_initializer='glorot_uniform', recurrent_initializer='orthogonal', bias_initializer='zeros', name=None)[source]¶
Bases:
LayerLong Short-Term Memory (LSTM) layer.
- Implements the standard LSTM equations:
f_t = sigmoid(x_t @ Wf + h_{t-1} @ Uf + bf) i_t = sigmoid(x_t @ Wi + h_{t-1} @ Ui + bi) g_t = tanh(x_t @ Wg + h_{t-1} @ Ug + bg) o_t = sigmoid(x_t @ Wo + h_{t-1} @ Uo + bo) c_t = f_t * c_{t-1} + i_t * g_t h_t = o_t * tanh(c_t)
- Parameters:
units (int)
return_sequences (bool)
return_state (bool)
- property params¶
- property grads¶
- class snn.layers.GRU(units, return_sequences=False, return_state=False, kernel_initializer='glorot_uniform', bias_initializer='zeros', name=None)[source]¶
Bases:
LayerGated Recurrent Unit (GRU) layer.
- Equations:
z_t = sigmoid(x_t @ Wz + h_{t-1} @ Uz + bz) # update gate r_t = sigmoid(x_t @ Wr + h_{t-1} @ Ur + br) # reset gate n_t = tanh(x_t @ Wn + (r_t * h_{t-1}) @ Un + bn) # new gate h_t = (1 - z_t) * n_t + z_t * h_{t-1}
- Parameters:
units (int)
return_sequences (bool)
return_state (bool)
- property params¶
- property grads¶
Language / Attention¶
- class snn.layers.Embedding(vocab_size, embed_dim, embeddings_initializer='random_normal', name=None)[source]¶
Bases:
LayerToken embedding layer.
Maps integer token indices to dense float vectors. This is the standard first layer for any NLP or sequence model.
- Parameters:
vocab_size (int) – Number of unique tokens (size of the vocabulary).
embed_dim (int) – Dimensionality of the embedding vectors.
embeddings_initializer (str) – Initialiser for the embedding matrix (default
"random_normal").shape (Output)
-----------
``(batch –
``[0 (seq_len)`` — integer token indices in) –
vocab_size)``.
shape
------------
``(batch –
seq_len
vectors. (embed_dim)`` — dense embedding)
Examples
>>> emb = Embedding(vocab_size=1000, embed_dim=64) >>> x = np.array([[1, 5, 23, 0], [4, 2, 9, 7]]) # (2, 4) integer tokens >>> out = emb.forward(x) # (2, 4, 64)
- property params¶
- property grads¶
- class snn.layers.PositionalEncoding(max_seq_len=512, name=None)[source]¶
Bases:
LayerSinusoidal Positional Encoding (Vaswani et al. 2017).
Adds a fixed, non-learned position signal to a sequence embedding so that the model can distinguish token order. The encoding is defined by:
PE[pos, 2i] = sin(pos / 10000^(2i/d)) PE[pos, 2i+1] = cos(pos / 10000^(2i/d))
This layer has no trainable parameters — it just adds the PE matrix to the incoming embedding and passes the gradient straight through.
- Parameters:
max_seq_len (int) – Maximum sequence length to pre-compute (default 512).
shape (Input / output)
--------------------
``(batch –
seq_len
in-place). (embed_dim)`` → same shape (PE added)
Examples
>>> pe = PositionalEncoding(max_seq_len=128) >>> x = np.random.randn(4, 20, 64) # (batch, seq, embed_dim) >>> out = pe.forward(x) # (4, 20, 64) — PE added
- class snn.layers.MultiHeadAttention(embed_dim, num_heads, dropout_rate=0.0, name=None)[source]¶
Bases:
LayerMulti-Head Self-Attention (Vaswani et al. 2017).
Computes scaled dot-product attention in parallel over
num_headsheads, then projects the concatenated result back toembed_dim.Attention(Q, K, V) = softmax(Q·Kᵀ / √d_k) · V
Each head operates on a
head_dim = embed_dim // num_headssubspace.- Parameters:
embed_dim (int) – Total embedding dimensionality (must be divisible by
num_heads).num_heads (int) – Number of parallel attention heads.
dropout_rate (float) – Dropout applied to the attention weight matrix during training.
shape (Output)
-----------
``(batch –
seq_len
embed_dim)``
shape
------------
``(batch –
seq_len
embed_dim)``
Examples
>>> attn = MultiHeadAttention(embed_dim=64, num_heads=4) >>> x = np.random.randn(2, 10, 64) >>> out = attn.forward(x) # (2, 10, 64)
- property params¶
- property grads¶
- class snn.layers.TransformerBlock(embed_dim, num_heads, ff_dim, dropout_rate=0.1, activation='gelu', name=None)[source]¶
Bases:
LayerTransformer encoder block (Pre-LayerNorm variant).
Architecture per block:
x → LayerNorm → MultiHeadAttention → Dropout → + x (residual) → LayerNorm → FFN(ff_dim) → Dropout → + x (residual)
The FFN consists of two Dense layers:
Dense(ff_dim, activation) → Dense(embed_dim).Pre-LN (applied before each sub-layer) is more numerically stable than Post-LN and typically requires no learning-rate warmup.
- Parameters:
embed_dim (int) – Model dimensionality.
num_heads (int) – Number of attention heads.
ff_dim (int) – Hidden size of the feed-forward network (usually 2–4 × embed_dim).
dropout_rate (float) – Dropout applied inside attention and after each sub-layer.
activation (str) – Activation used in the FFN hidden layer (default
"gelu").shape (Input / output)
--------------------
``(batch –
seq_len
shape. (embed_dim)`` → same)
Examples
Simple language classifier:
model = Sequential([ Embedding(vocab_size=5000, embed_dim=64), PositionalEncoding(), TransformerBlock(embed_dim=64, num_heads=4, ff_dim=128), GlobalAveragePooling1D(), Dense(2, activation="softmax"), ])
- property params¶
- property grads¶
Gated Linear Units¶
- class snn.layers.GLU(units, use_bias=True, kernel_initializer='glorot_uniform', name=None)[source]¶
Bases:
LayerGated Linear Unit (Dauphin et al. 2017).
Projects the input to 2 ×
units, splits into two halves(a, b), and returnsa ⊙ σ(b):z = x @ W + bias # shape (..., 2*units) a, b = z[..., :units], z[..., units:] output = a * sigmoid(b) # shape (..., units)
This halves the effective hidden size while adding a learnable gating mechanism. Widely used in CNNs and early Transformer variants.
- Parameters:
units (int) – Output dimensionality (half of the internal projection width).
use_bias (bool) – Whether to add a bias term (default True).
kernel_initializer (str) – Weight initialiser (default
"glorot_uniform").
Examples
>>> glu = GLU(units=32) >>> x = np.random.randn(4, 20, 64) >>> out = glu.forward(x) # (4, 20, 32)
- property params¶
- property grads¶
- class snn.layers.SwiGLU(units, use_bias=True, kernel_initializer='glorot_uniform', name=None)[source]¶
Bases:
LayerSwiGLU — Swish-Gated Linear Unit (Shazeer 2020).
Like
GLUbut replaces the sigmoid gate with Swish (SiLU):z = x @ W + bias a, b = z[..., :units], z[..., units:] output = a ⊙ swish(b) where swish(b) = b * σ(b)
SwiGLU is the standard FFN activation in LLaMA, PaLM, Mistral, and Gemma. It outperforms ReLU and GELU on most language tasks despite having 50% more parameters than a plain Dense layer (offset by removing one bias in the original papers).
- Parameters:
units (int) – Output dimensionality.
use_bias (bool) – Whether to include a bias (default True).
Examples
Replace a standard FFN sub-layer:
# Standard Dense(ff_dim, activation="gelu") → Dense(embed_dim) # SwiGLU drop-in (ff_dim must be 2/3 of original for equal params) SwiGLU(units=ff_dim) → Dense(embed_dim)
- property params¶
- property grads¶
Merge & Skip Connections¶
- class snn.layers.Residual(layers, activation='relu', shortcut=None, name=None)[source]¶
Bases:
LayerResidual (skip-connection) block — for use inside Sequential.
Wraps a sequence of sub-layers and adds a skip connection:
output = activation(sub_layers(x) + shortcut(x))
If the input and output feature sizes differ, a learnable linear projection is built lazily and used as the shortcut.
- Parameters:
Examples
Basic residual block inside Sequential:
model = Sequential([ Dense(64, activation='relu'), Residual([ Dense(64, activation='relu'), Dense(64), # no activation — applied after sum ]), Dense(10, activation='softmax'), ])
Two blocks of different sizes (auto-projection):
model = Sequential([ Dense(128, activation='relu'), Residual([Dense(64, activation='relu'), Dense(64)]), # shortcut Dense(64) auto-added because 128 ≠ 64 Dense(10, activation='softmax'), ])
- property params¶
- property grads¶
- class snn.layers.Add(trainable=True, name=None)[source]¶
Bases:
LayerElement-wise addition of multiple inputs.
Used in residual / skip-connection architectures. All inputs must have the same shape.
In Sequential context, wrap it in a
Residualblock. In GraphModel context, call it with a list of Tensor nodes:h1 = Dense(64, 'relu')(x) h2 = Dense(64, 'relu')(x) merged = Add()([h1, h2])
Input / output shape¶
List of arrays, each
(batch, …)→ same shape.
- class snn.layers.Concatenate(axis=-1, name=None)[source]¶
Bases:
LayerConcatenate multiple inputs along one axis.
# GraphModel usage h1 = Dense(32, 'relu')(x) h2 = Dense(32, 'relu')(x) merged = Concatenate(axis=-1)([h1, h2]) # shape (..., 64)
- Parameters:
axis (int) – Axis along which to concatenate (default
-1).
- class snn.layers.TimeDistributed(layer, name=None)[source]¶
Bases:
LayerApply a layer independently to each time step of a sequence.
Reshapes
(batch, time, features)→(batch*time, features), runs the wrapped layer, then reshapes back. This lets you apply any layer (Dense, Conv1D, …) to every position in a sequence without writing a Python loop.- Parameters:
layer (Layer) – The layer to apply at each time step.
shape (Input / output)
--------------------
``(batch (in_features)`` →) –
time
``(batch –
time
out_features)``
Examples
>>> td = TimeDistributed(Dense(32, activation='relu')) >>> x = np.random.randn(8, 20, 64) >>> out = td.forward(x) # (8, 20, 32)
Typical use — dense classification head over RNN output:
model = Sequential([ LSTM(64, return_sequences=True), # (batch, seq, 64) TimeDistributed(Dense(32, 'relu')), # (batch, seq, 32) TimeDistributed(Dense(vocab_size, 'softmax')), ])
- property params¶
- property grads¶