A Field Guide to Embedded Neural Network Algorithms
August 08, 2026
A neural network is a parameterized function \(f_\theta: \mathbb{R}^n \to \mathbb{R}^m\) built by composing simple, differentiable transformations called layers. Each layer applies an affine map followed by a non-linear activation, and the whole composition is trained end-to-end by gradient-based optimization.
Neural networks are powerful because of the universal approximation theorem: a single hidden layer with enough neurons can approximate any continuous function on a compact set to arbitrary accuracy. In practice, depth (many layers) is more parameter-efficient than width for learning hierarchical features.
This library provides a minimal, statically-sized neural network framework designed for embedded inference and on-device training — no heap allocation, no dynamic shapes, full compile-time dimension checking.
Given \(L\) layers, the network computes:
\[a_0 = x\] \[z_\ell = W_\ell \, a_{\ell-1} + b_\ell, \quad \ell = 1, \ldots, L\] \[a_\ell = f_\ell(z_\ell)\] \[\hat{y} = a_L\]
where \(W_\ell \in \mathbb{R}^{n_\ell \times n_{\ell-1}}\) are weights, \(b_\ell \in \mathbb{R}^{n_\ell}\) are biases, and \(f_\ell\) is the activation function for layer \(\ell\).
Training minimizes a scalar loss \(\mathcal{L}(\hat{y}, y)\) that measures how far the prediction \(\hat{y}\) is from the target \(y\). Common choices:
| Loss | Formula | Use Case |
|---|---|---|
| MSE | \(\frac{1}{m}\sum(\hat{y}_i - y_i)^2\) | Regression |
| BCE | \(-\sum[y_i \log \hat{y}_i + (1-y_i)\log(1-\hat{y}_i)]\) | Binary classification |
| CCE | \(-\sum y_i \log \hat{y}_i\) | Multi-class classification |
Backpropagation efficiently computes \(\nabla_\theta \mathcal{L}\) via the chain rule, working from the output layer backward:
\[\delta_L = \nabla_{a_L}\mathcal{L} \odot f_L'(z_L)\] \[\delta_\ell = (W_{\ell+1}^T \delta_{\ell+1}) \odot f_\ell'(z_\ell)\]
The gradients with respect to parameters are:
\[\frac{\partial \mathcal{L}}{\partial W_\ell} = \delta_\ell \, a_{\ell-1}^T, \qquad \frac{\partial \mathcal{L}}{\partial b_\ell} = \delta_\ell\]
An optimizer uses the gradients to update the parameter vector \(\theta\):
\[\theta_{t+1} = \theta_t - \eta \, \nabla_\theta \mathcal{L}\]
where \(\eta\) is the learning rate. More sophisticated optimizers (momentum, Adam) modify this basic rule.
| Phase | Time | Space |
|---|---|---|
| Forward pass | \(O\!\left(\sum_{\ell=1}^L n_\ell \cdot n_{\ell-1}\right)\) | \(O\!\left(\sum n_\ell\right)\) activations |
| Backward pass | Same as forward | Same + gradient storage |
| Parameter update | \(O(P)\) | \(O(P)\) optimizer state |
where \(P = \sum_\ell (n_\ell \cdot n_{\ell-1} + n_\ell)\) is the total parameter count. For small embedded networks (\(P < 10{,}000\)), both passes complete in microseconds.
Network: 2 inputs → 2 hidden (ReLU) → 1 output (Sigmoid). Learning XOR.
Architecture:
graph LR
x1((x₁)) --> h1((h₁))
x1 --> h2((h₂))
x2((x₂)) --> h1
x2 --> h2
h1 --> y((ŷ))
h2 --> y
Epoch 0 — Forward pass with input \(x = [1, 0]^T\), target \(y = 1\):
| Step | Computation | Result |
|---|---|---|
| Hidden pre-activation | \(z_1 = W_1 x + b_1\) | \([0.3, -0.1]^T\) |
| Hidden activation | \(a_1 = \text{ReLU}(z_1)\) | \([0.3, 0.0]^T\) |
| Output pre-activation | \(z_2 = W_2 a_1 + b_2\) | \([0.15]\) |
| Output activation | \(\hat{y} = \sigma(z_2)\) | \([0.537]\) |
| Loss | \(\mathcal{L} = -(y\log\hat{y} + (1-y)\log(1-\hat{y}))\) | \(0.621\) |
Epoch 0 — Backward pass:
| Step | Computation | Result |
|---|---|---|
| Output gradient | \(\delta_2 = \hat{y} - y\) | \([-0.463]\) |
| \(\nabla W_2\) | \(\delta_2 \cdot a_1^T\) | \([-0.139, 0]\) |
| Hidden gradient | \(\delta_1 = W_2^T \delta_2 \odot \text{ReLU}'(z_1)\) | \([-0.231, 0]^T\) |
| \(\nabla W_1\) | \(\delta_1 \cdot x^T\) | \([[-0.231, 0], [0, 0]]\) |
Update: \(W \leftarrow W - 0.1 \cdot \nabla W\). After ~500 epochs, the network correctly classifies all four XOR inputs.
| Variant | Key Difference |
|---|---|
| Convolutional Neural Network (CNN) | Layers share weights spatially; efficient for image/signal data |
| Recurrent Neural Network (RNN) | Layers share weights across time steps; models sequences |
| Residual Network (ResNet) | Skip connections mitigate vanishing gradients in very deep networks |
| Transformer | Attention-based; no recurrence; state-of-the-art for sequences |
| Quantized Neural Network | Weights and activations in low-bit integers; optimal for MCU deployment |
graph TD
NN["Neural Network"]
Layer["Dense Layer"]
Act["Activation Functions"]
Loss["Loss Functions"]
Opt["Optimizer"]
Reg["Regularization"]
Model["Model"]
LR["Linear Regression"]
Layer --> NN
Act --> NN
Loss --> NN
Opt --> NN
Reg --> NN
NN --> Model
NN -.->|"single-layer, linear activation, MSE loss"| LR
| Component | Relationship |
|---|---|
| Dense Layer | The fundamental building block; computes affine transformations |
| Activation Functions | Introduce non-linearity after each layer |
| Loss Functions | Define the training objective |
| Optimizer (numerical-toolbox-cpp) | Drives parameter updates via gradient descent |
| Regularization (numerical-toolbox-cpp) | Penalizes complexity to prevent overfitting |
| Model | Composes layers into a trainable pipeline |
| Linear Regression (numerical-toolbox-cpp) | Special case: single layer, identity activation, MSE loss |
A dense (fully-connected) layer is the most fundamental building block of a neural network. It maps an input vector \(a_{\text{in}} \in \mathbb{R}^n\) to an output vector \(a_{\text{out}} \in \mathbb{R}^m\) through a learnable affine transformation followed by a non-linear activation:
\[a_{\text{out}} = f(W \, a_{\text{in}} + b)\]
Every input neuron is connected to every output neuron — hence “fully connected.” The layer’s parameters are the weight matrix \(W\) and bias vector \(b\); training adjusts these to minimize the loss.
In this library, input size, output size, and parameter count are all compile-time constants, enabling stack allocation and dimension checking with zero runtime overhead.
\[z = W \, a_{\text{in}} + b, \qquad a_{\text{out}} = f(z)\]
where \(W \in \mathbb{R}^{m \times n}\), \(b \in \mathbb{R}^m\), and \(f\) is the activation function.
Given the gradient of the loss with respect to the output \(\frac{\partial \mathcal{L}}{\partial a_{\text{out}}}\):
Pre-activation gradient: \[\delta = \frac{\partial \mathcal{L}}{\partial a_{\text{out}}} \odot f'(z)\]
Weight gradient: \[\frac{\partial \mathcal{L}}{\partial W} = \delta \, a_{\text{in}}^T\]
Bias gradient: \[\frac{\partial \mathcal{L}}{\partial b} = \delta\]
Input gradient (propagated to the previous layer): \[\frac{\partial \mathcal{L}}{\partial a_{\text{in}}} = W^T \delta\]
\[P = m \times n + m = m(n + 1)\]
For a layer with 128 inputs and 64 outputs: \(P = 64 \times 129 = 8{,}256\) parameters.
| Operation | Time | Space |
|---|---|---|
| Forward (\(W a + b\)) | \(O(m \cdot n)\) | \(O(m)\) output + \(O(m)\) cached \(z\) |
| Backward (\(\delta\), \(\nabla W\), \(\nabla b\)) | \(O(m \cdot n)\) | \(O(m \cdot n)\) weight gradient |
| Total parameters | — | \(O(m \cdot n + m)\) |
The matrix-vector product dominates both passes. For embedded networks (e.g. \(n = 32, m = 16\)), a single forward pass takes ~512 multiply-accumulate operations.
Layer: 3 inputs → 2 outputs, ReLU activation.
\[W = \begin{bmatrix} 0.5 & -0.3 & 0.8 \\ 0.1 & 0.7 & -0.2 \end{bmatrix}, \quad b = \begin{bmatrix} 0.1 \\ -0.1 \end{bmatrix}, \quad a_{\text{in}} = \begin{bmatrix} 1.0 \\ 0.5 \\ -1.0 \end{bmatrix}\]
Forward:
| Step | Computation | Result |
|---|---|---|
| \(z = W a_{\text{in}} + b\) | \([0.5 - 0.15 - 0.8 + 0.1,\; 0.1 + 0.35 + 0.2 - 0.1]\) | \([-0.35,\; 0.55]^T\) |
| \(a_{\text{out}} = \text{ReLU}(z)\) | \([\max(0, -0.35),\; \max(0, 0.55)]\) | \([0.0,\; 0.55]^T\) |
Backward with \(\frac{\partial \mathcal{L}}{\partial a_{\text{out}}} = [0.2,\; -0.4]^T\):
| Step | Computation | Result |
|---|---|---|
| \(\delta = \nabla a_{\text{out}} \odot \text{ReLU}'(z)\) | \([0.2 \cdot 0,\; -0.4 \cdot 1]\) | \([0,\; -0.4]^T\) |
| \(\nabla W = \delta \, a_{\text{in}}^T\) | row 1: all zeros; row 2: \(-0.4 \times [1, 0.5, -1]\) | \(\begin{bmatrix}0 & 0 & 0\\-0.4 & -0.2 & 0.4\end{bmatrix}\) |
| \(\nabla b = \delta\) | — | \([0,\; -0.4]^T\) |
| \(\nabla a_{\text{in}} = W^T \delta\) | \(W^T [0, -0.4]^T\) | \([-0.04,\; -0.28,\; 0.08]^T\) |
float consumes 256 KB. Size layers to fit the target’s
stack budget.| Variant | Key Difference |
|---|---|
| Convolutional layer | Weight sharing across spatial positions; \(O(k^2 \cdot c)\) parameters per filter instead of \(O(n \cdot m)\) |
| Recurrent layer | Shares weights across time steps; adds a hidden state feedback connection |
| Batch normalization layer | Normalizes activations to zero mean and unit variance; accelerates training |
| Dropout layer | Randomly zeros activations during training; regularization effect |
| Sparse layer | Only a subset of connections exist; reduces parameter count and computation |
graph TD
Layer["Dense Layer"]
Act["Activation Functions"]
Model["Model"]
Opt["Optimizer"]
LR["Linear Regression"]
Act --> Layer
Layer --> Model
Model --> Opt
Layer -.->|"no activation, MSE loss"| LR
| Component | Relationship |
|---|---|
| Activation Functions | Applied element-wise after the affine transformation |
| Model | Chains multiple dense layers into a network |
| Optimizer (numerical-toolbox-cpp) | Updates \(W\) and \(b\) using the computed gradients |
| Linear Regression (numerical-toolbox-cpp) | A dense layer with identity activation and MSE loss is equivalent to linear regression |
An activation function \(f\) is a non-linear, element-wise transformation applied after the affine map in each neural network layer:
\[a = f(z) = f(W x + b)\]
Without activation functions, stacking layers would collapse into a single affine transformation — the network could only represent linear mappings regardless of depth. Activation functions are what give neural networks their expressive power.
The choice of activation function controls gradient flow during back-propagation, output range, and computational cost — all critical on resource-constrained embedded targets.
Every activation function exposes two operations:
| Operation | Definition | Purpose |
|---|---|---|
| Forward | \(a = f(z)\) | Transform the pre-activation |
| Backward | \(f'(z)\) | Provide the local derivative for back-propagation |
The chain rule connects them during training:
\[\frac{\partial \mathcal{L}}{\partial z} = \frac{\partial \mathcal{L}}{\partial a} \cdot f'(z)\]
\[f(z) = \max(0, z), \qquad f'(z) = \begin{cases} 1 & z > 0 \\ 0 & z \le 0 \end{cases}\]
\[f(z) = \begin{cases} z & z > 0 \\ \alpha z & z \le 0 \end{cases}, \qquad f'(z) = \begin{cases} 1 & z > 0 \\ \alpha & z \le 0 \end{cases}\]
where \(\alpha\) is a small positive constant (typically \(0.01\)). Prevents dead neurons by allowing a small gradient for \(z < 0\).
\[f(z) = \frac{1}{1 + e^{-z}}, \qquad f'(z) = f(z)(1 - f(z))\]
\[f(z) = \tanh(z) = \frac{e^z - e^{-z}}{e^z + e^{-z}}, \qquad f'(z) = 1 - f(z)^2\]
For a vector \(\mathbf{z} \in \mathbb{R}^k\):
\[f(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{k} e^{z_j}}\]
| Activation | Forward (per element) | Backward (per element) | Notes |
|---|---|---|---|
| ReLU | \(O(1)\) — comparison | \(O(1)\) — comparison | Fastest |
| Leaky ReLU | \(O(1)\) — comparison + multiply | \(O(1)\) | Negligible overhead vs ReLU |
| Sigmoid | \(O(1)\) — exp + divide | \(O(1)\) — reuse forward result | Requires exp() |
| Tanh | \(O(1)\) — exp (twice) | \(O(1)\) — reuse forward result | Requires exp() |
| Softmax | \(O(k)\) — vector exp + sum | \(O(k^2)\) — full Jacobian | Significantly more expensive |
Scenario: Forward and backward pass through a 3-neuron hidden layer with ReLU, given pre-activations \(z = [-0.5, \; 1.2, \; 0.0]\).
Forward:
| Neuron | \(z\) | \(\text{ReLU}(z)\) |
|---|---|---|
| 1 | \(-0.5\) | \(0.0\) |
| 2 | \(1.2\) | \(1.2\) |
| 3 | \(0.0\) | \(0.0\) |
Backward with incoming gradient \(\frac{\partial \mathcal{L}}{\partial a} = [0.3, \; -0.7, \; 0.1]\):
| Neuron | \(f'(z)\) | \(\frac{\partial \mathcal{L}}{\partial z}\) |
|---|---|---|
| 1 | \(0\) (dead) | \(0.3 \times 0 = 0\) |
| 2 | \(1\) | \(-0.7 \times 1 = -0.7\) |
| 3 | \(0\) (at boundary) | \(0.1 \times 0 = 0\) |
Neuron 1 is dead — its gradient is zero and its weights will not update. If this persists across all training samples, the neuron is permanently inactive.
| Variant | Key Difference |
|---|---|
| PReLU (Parametric ReLU) | \(\alpha\) is a learnable parameter per channel |
| ELU (Exponential LU) | \(\alpha(e^z - 1)\) for \(z < 0\); smooth and zero-centered |
| GELU (Gaussian Error LU) | \(z \cdot \Phi(z)\); used in Transformers |
| Swish / SiLU | \(z \cdot \sigma(z)\); smooth, non-monotonic |
| Hard Sigmoid / Hard Tanh | Piece-wise linear approximations; no transcendentals |
exp() calls on MCUs without FPU.graph TD
Act["Activation Functions"]
Layer["Dense Layer"]
NN["Neural Network"]
Loss["Loss Functions"]
Act --> Layer
Layer --> NN
NN --> Loss
| Component | Relationship |
|---|---|
| Dense Layer | Applies the activation function after the affine transformation |
| Neural Network | Activations enable the non-linear function approximation that makes deep networks useful |
| Loss Functions | The output activation must match the loss: Sigmoid + BCE, Softmax + CCE |
A loss function \(\mathcal{L}(\hat{y}, y)\) quantifies how far a model’s prediction \(\hat{y}\) is from the true target \(y\). Training a neural network means finding parameters \(\theta\) that minimize the expected loss over the training data:
\[\theta^* = \arg\min_\theta \; \mathbb{E}[\mathcal{L}(f_\theta(x), y)]\]
The loss function defines the entire learning objective — different losses lead to different optimal models even on the same data. It must also provide a gradient \(\nabla_{\hat{y}} \mathcal{L}\) for back-propagation.
\[\mathcal{L}_{\text{MSE}} = \frac{1}{m} \sum_{i=1}^{m} (\hat{y}_i - y_i)^2\]
\[\frac{\partial \mathcal{L}}{\partial \hat{y}_i} = \frac{2}{m}(\hat{y}_i - y_i)\]
\[\mathcal{L}_{\text{MAE}} = \frac{1}{m} \sum_{i=1}^{m} |\hat{y}_i - y_i|\]
\[\frac{\partial \mathcal{L}}{\partial \hat{y}_i} = \frac{1}{m} \mathrm{sign}(\hat{y}_i - y_i)\]
\[\mathcal{L}_{\text{BCE}} = -\frac{1}{m}\sum_{i=1}^{m} \left[ y_i \log \hat{y}_i + (1 - y_i) \log(1 - \hat{y}_i) \right]\]
\[\frac{\partial \mathcal{L}}{\partial \hat{y}_i} = -\frac{1}{m}\left(\frac{y_i}{\hat{y}_i} - \frac{1 - y_i}{1 - \hat{y}_i}\right)\]
\[\mathcal{L}_{\text{CCE}} = -\sum_{i=1}^{k} y_i \log \hat{y}_i\]
\[\frac{\partial \mathcal{L}}{\partial \hat{y}_i} = -\frac{y_i}{\hat{y}_i}\]
| Loss | Forward | Backward | Notes |
|---|---|---|---|
| MSE | \(O(m)\) | \(O(m)\) | Cheapest; no transcendentals |
| MAE | \(O(m)\) | \(O(m)\) | Requires sign() |
| BCE | \(O(m)\) | \(O(m)\) | Requires log() |
| CCE | \(O(k)\) | \(O(k)\) | Requires log() |
All losses are \(O(m)\) where \(m\) is the output dimension. The computational cost is negligible compared to the dense layer matrix products.
Scenario: 3-class classification. Target \(y = [0, 1, 0]\) (class 2). Softmax output \(\hat{y} = [0.1, 0.7, 0.2]\).
CCE Forward:
\[\mathcal{L} = -(0 \cdot \log 0.1 + 1 \cdot \log 0.7 + 0 \cdot \log 0.2) = -\log(0.7) \approx 0.357\]
CCE Backward:
| \(i\) | \(y_i\) | \(\hat{y}_i\) | \(\partial \mathcal{L}/\partial \hat{y}_i = -y_i / \hat{y}_i\) |
|---|---|---|---|
| 1 | 0 | 0.1 | \(0\) |
| 2 | 1 | 0.7 | \(-1.429\) |
| 3 | 0 | 0.2 | \(0\) |
The gradient is non-zero only for the true class, and its magnitude \(1/\hat{y}_2\) grows as the prediction worsens — providing a strong corrective signal.
For comparison — MSE on the same example:
\[\mathcal{L}_{\text{MSE}} = \frac{1}{3}[(0.1)^2 + (0.7-1)^2 + (0.2)^2] = \frac{1}{3}[0.01 + 0.09 + 0.04] = 0.047\]
MSE gives a much weaker signal and does not account for the probabilistic nature of the output.
log() function
needed for cross-entropy is expensive and ill-conditioned near zero in
fixed-point. Evaluate in floating-point.| Variant | Key Difference |
|---|---|
| Huber loss | Quadratic for small errors, linear for large; robust regression |
| Focal loss | Down-weights well-classified examples; addresses class imbalance |
| KL divergence | Measures distance between two distributions; used in variational inference |
| Hinge loss | Margin-based; used in SVMs and some neural classifiers |
| Contrastive loss | Learns similarity metrics; used in Siamese networks |
graph TD
Loss["Loss Functions"]
Act["Activation Functions"]
Opt["Optimizer"]
Reg["Regularization"]
Model["Model"]
LR["Linear Regression"]
Act -->|"output activation must match loss"| Loss
Loss --> Opt
Reg -->|"added to loss"| Loss
Loss --> Model
Loss -.->|"MSE + normal equation"| LR
| Component | Relationship |
|---|---|
| Activation Functions | Output activation must match: Sigmoid ↔︎ BCE, Softmax ↔︎ CCE, identity ↔︎ MSE |
| Optimizer (numerical-toolbox-cpp) | Uses \(\nabla \mathcal{L}\) to update parameters |
| Regularization (numerical-toolbox-cpp) | Adds a penalty term to the loss: \(\mathcal{L}_{\text{total}} = \mathcal{L} + \lambda \Omega(\theta)\) |
| Linear Regression (numerical-toolbox-cpp) | Solved analytically when the loss is MSE and the model is linear |
A Model composes a sequence of dense layers into a single trainable function \(f: \mathbb{R}^n \to \mathbb{R}^m\). It is the orchestrator that:
In this library, the Model is fully statically typed — layer dimensions, parameter counts, and memory footprints are all known at compile time, enabling zero-overhead abstraction on embedded targets.
For \(L\) layers with transformations \(f_1, f_2, \ldots, f_L\):
\[\hat{y} = (f_L \circ f_{L-1} \circ \cdots \circ f_1)(x) = f_L(f_{L-1}(\ldots f_1(x) \ldots))\]
Each \(f_\ell\) is a dense layer: \(f_\ell(a) = \sigma_\ell(W_\ell a + b_\ell)\).
All weights and biases are concatenated into a single vector:
\[\theta = [\text{vec}(W_1), b_1, \text{vec}(W_2), b_2, \ldots, \text{vec}(W_L), b_L] \in \mathbb{R}^P\]
where \(P = \sum_{\ell=1}^L m_\ell(n_\ell + 1)\).
graph LR
X["x ∈ ℝⁿ"] --> L1["Layer 1"] --> L2["Layer 2"] --> Ldots["⋯"] --> LL["Layer L"] --> Y["ŷ ∈ ℝᵐ"]
\[\frac{\partial \mathcal{L}}{\partial \theta_\ell} = \frac{\partial \mathcal{L}}{\partial a_L} \cdot \frac{\partial a_L}{\partial a_{L-1}} \cdots \frac{\partial a_{\ell+1}}{\partial a_\ell} \cdot \frac{\partial a_\ell}{\partial \theta_\ell}\]
Each layer stores its input \(a_{\ell-1}\) during the forward pass so it can compute \(\nabla W_\ell\) and \(\nabla b_\ell\) during the backward pass.
graph TD
FP["Forward pass: ŷ = Model(x)"]
LC["Loss: ℒ(ŷ, y)"]
BP["Backward pass: ∇θ ℒ"]
UP["Update: θ ← θ − η ∇θ ℒ"]
FP --> LC --> BP --> UP --> FP
| Operation | Time | Space |
|---|---|---|
| Forward pass | \(O(P)\) | \(O(\sum n_\ell)\) cached activations |
| Backward pass | \(O(P)\) | \(O(P)\) gradients |
GetParameters() |
\(O(P)\) | \(O(P)\) flat vector |
SetParameters() |
\(O(P)\) | — |
All operations scale linearly with the total parameter count \(P\).
Model: 2 → 3 → 1 (two layers).
Compile-time verification chain:
| Check | Condition | Status |
|---|---|---|
| Layer 1 input size = Model input size | \(2 = 2\) | ✓ |
| Layer 1 output size = Layer 2 input size | \(3 = 3\) | ✓ |
| Layer 2 output size = Model output size | \(1 = 1\) | ✓ |
All types derive from Layer |
type trait check | ✓ |
Parameter layout (\(P = 3(2 + 1) + 1(3 + 1) = 9 + 4 = 13\)):
| Index | Parameter |
|---|---|
| 0–5 | \(W_1\) (3×2 = 6 elements) |
| 6–8 | \(b_1\) (3 elements) |
| 9–11 | \(W_2\) (1×3 = 3 elements) |
| 12 | \(b_2\) (1 element) |
Forward pass with \(x = [1.0, 0.5]^T\):
Backward pass with loss gradient \(\delta_{\text{out}} = [0.12]\):
Optimizer receives the full \(\nabla \theta \in \mathbb{R}^{13}\) and updates \(\theta\).
static_assert
fires during compilation.static_assert(sizeof...(Layers) > 0).GetParameters()
and SetParameters() must use the same concatenation order.
The implementation iterates layers via std::index_sequence
to guarantee consistency.Model::TotalParameters. A mismatch is also caught at
compile time.| Variant | Key Difference |
|---|---|
| Sequential model (dynamic) | Layers stored in a container; dimension checked at runtime instead of compile time |
| Functional API | Supports branching and merging (DAG topology instead of linear chain) |
| Residual model | Adds skip connections: \(a_{\ell+2} = f_{\ell+1}(a_\ell) + a_\ell\) |
| Recurrent model | Unrolls the same layer across time steps |
SetParameters() and only
Forward() is called at runtime.graph TD
Model["Model"]
Layer["Dense Layer"]
Loss["Loss Functions"]
Opt["Optimizer"]
Reg["Regularization"]
NN["Neural Network"]
Layer --> Model
Model --> Opt
Model --> Loss
Reg --> Loss
Model --> NN
| Component | Relationship |
|---|---|
| Dense Layer | The Model is a sequence of layers stored in a
std::tuple |
| Loss Functions | Measures prediction error; the Model delegates loss computation to a Loss object |
| Optimizer (numerical-toolbox-cpp) | Receives the flat parameter/gradient vectors from the Model and returns updated parameters |
| Regularization (numerical-toolbox-cpp) | Added to the loss before optimization |