Multi-Layer Perceptron (MLP) with GPU Backpropagation #
Complete implementation of 2-layer MLP for MNIST with GPU-accelerated forward and backward passes.
Architecture #
Input(784) → Dense(128) + ReLU → Dense(10) + Softmax → Output(10)
GPU Implementation #
Forward Pass:
- Layer 1: MatVec(784→128) + Bias + ReLU (fused kernel)
- Layer 2: MatVec(128→10) + Bias (fused kernel)
- Softmax(10)
Backward Pass:
- Softmax gradient: dL/dlogits = probs - one_hot(label)
- Layer 2 gradient: dW2 = h1^T @ dlogits, dB2 = dlogits, dH1 = W2^T @ dlogits
- ReLU gradient: dH1pre = dH1 * (h1 > 0)
- Layer 1 gradient: dW1 = input^T @ dH1pre, dB1 = dH1pre
SGD Update (GPU):
- W = W - lr * dW (element-wise on GPU)
- B = B - lr * dB (element-wise on GPU)
Type Definitions #
MLP parameters (weights and biases for 2 layers)
- w1 : Core.TensorData
- b1 : Core.TensorData
- w2 : Core.TensorData
- b2 : Core.TensorData
Instances For
Equations
MLP input (single sample + label for training)
- x : Core.TensorData
- label : Nat
- params : MLPParams
Instances For
Equations
Instances For
Equations
Equations
Instances For
MLP gradients (for backprop)
- dW1 : Core.TensorData
- dB1 : Core.TensorData
- dW2 : Core.TensorData
- dB2 : Core.TensorData
Instances For
Equations
Instances For
CPU Reference Implementation #
Add bias vector to result
Equations
- Hesper.NN.MLP.cpuAddBias vec bias = Array.zipWith (fun (x1 x2 : Float) => x1 + x2) vec bias
Instances For
CPU forward pass
Equations
- One or more equations did not get rendered due to their size.
Instances For
CPU backward pass (returns gradients)
Equations
- One or more equations did not get rendered due to their size.
Instances For
GPU Kernels (using existing WGSL helpers) #
Generate Layer 1 kernel (MatVec + Bias + ReLU)
Equations
Instances For
Generate Layer 2 kernel (MatVec + Bias)
Equations
Instances For
Generate Softmax kernel
Instances For
GPU Backward Pass Kernels (using WGSL DSL) #
Softmax gradient kernel: dLogits[i] = probs[i] - (i == label ? 1 : 0)
Equations
- One or more equations did not get rendered due to their size.
Instances For
Layer 2 backward kernel: computes dW2, dB2, dH1
Equations
- One or more equations did not get rendered due to their size.
Instances For
ReLU backward kernel: dH1pre[i] = dH1[i] * (h1[i] > 0)
Equations
- One or more equations did not get rendered due to their size.
Instances For
Layer 1 backward kernel: computes dW1, dB1
Equations
- One or more equations did not get rendered due to their size.
Instances For
SGD Update on GPU #
SGD kernel: param[i] -= lr * grad[i]
Equations
- One or more equations did not get rendered due to their size.
Instances For
Generate GPU kernel for Adam optimizer update.
Adam (Adaptive Moment Estimation) combines momentum and RMSprop.
Algorithm:
m[i] = beta1 * m[i] + (1 - beta1) * grad[i] # Update first moment
v[i] = beta2 * v[i] + (1 - beta2) * grad[i]^2 # Update second moment
m_hat = m[i] / (1 - beta1^step) # Bias correction
v_hat = v[i] / (1 - beta2^step) # Bias correction
params[i] -= lr * m_hat / (sqrt(v_hat) + epsilon) # Update parameters
Parameters:
- size: Number of parameters
- lr: Learning rate (typical: 0.001)
- beta1: Momentum decay rate (typical: 0.9)
- beta2: Variance decay rate (typical: 0.999)
- epsilon: Numerical stability constant (typical: 1e-8)
- step: Current step number (for bias correction)
Buffers:
- @binding(0): params (read-write) - parameters to update
- @binding(1): grads (read-only) - gradients
- @binding(2): m (read-write) - first moment estimates
- @binding(3): v (read-write) - second moment estimates
Example:
let kernel := genAdamKernel 1000 0.001 0.9 0.999 1e-8 10
Equations
- One or more equations did not get rendered due to their size.
Instances For
SGD Update on CPU #
CPU SGD parameter update
Equations
- One or more equations did not get rendered due to their size.
Instances For
VerifiedOpFusion Instance #
Note: Full VerifiedOpFusion instance would require:
- Kernel type signatures matching the pattern
- WGSL expression builders
- Proper workgroup dimensions
For now, we provide the CPU spec which can be called directly from the training loop. GPU kernels can be invoked via Compute API.
Equations
- One or more equations did not get rendered due to their size.
Training Helpers #
Single training step: forward + backward + update
Equations
- Hesper.NN.MLP.trainStep input lr = (Hesper.NN.MLP.cpuMLPForward input, Hesper.NN.MLP.cpuSGDUpdate input.params (Hesper.NN.MLP.cpuMLPBackward input (Hesper.NN.MLP.cpuMLPForward input)) lr)