A Deep Learning Framework Built From Scratch
Zero external ML dependencies · Dynamic computation graphs · Reverse-mode automatic differentiation
Quickstart • Features • Architecture • API • Tests • License
PureGrad is a lightweight, educational deep learning framework implemented entirely from scratch in pure Python + NumPy. No PyTorch. No TensorFlow. No Autograd libraries. Every piece of the engine — from the computation graph to backpropagation to gradient descent — is built from first principles.
It can train real neural networks on non-linear datasets and achieve convergence.
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ PUREGRAD — Custom Deep Learning Framework ┃
┃ Zero Dependencies · Pure Autograd ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
▸ Training MLP on Moons dataset...
Epoch 100 │ Loss: 0.043053
Epoch 200 │ Loss: 0.032260
Epoch 300 │ Loss: 0.026878
Epoch 400 │ Loss: 0.022956
Epoch 500 │ Loss: 0.019878
✅ CONVERGED — Final Loss: 0.0199
📊 Training Accuracy: 99.7%
- Python 3.10+
- NumPy (the only dependency)
git clone https://github.com/kaivalya-cyber/puregrad.git
cd puregrad
# Create a virtual environment
python3 -m venv .venv
source .venv/bin/activate
pip install numpy
# Run the training demo
python train.pyfrom puregrad import Tensor, MLP, MSELoss, SGD
from puregrad.data import make_moons
# Generate dataset
X_np, y_np = make_moons(n_samples=300, noise=0.1)
X_train, y_train = Tensor(X_np), Tensor(y_np)
# Build model
model = MLP(input_dim=2, hidden_dims=[16, 16], output_dim=1, activation="tanh")
optimizer = SGD(model.parameters(), lr=0.05)
# Train
for epoch in range(500):
model.zero_grad()
predictions = model(X_train)
loss = MSELoss(predictions, y_train)
loss.backward()
optimizer.step()
print(f"Final loss: {loss.data.flat[0]:.4f}")- Dynamic Computation Graph — Automatically constructs a DAG of operations during the forward pass
- Reverse-Mode Autodiff — Single
.backward()call propagates gradients through the entire graph via the chain rule - Topological Sort — DFS-based ordering guarantees correct gradient evaluation sequence
- Gradient Accumulation — Gradients accumulate (
+=), never overwrite — supports safe variable reuse across multiple paths
| Category | Operations |
|---|---|
| Arithmetic | +, -, *, /, ** (all with broadcasting) |
| Matrix | @ / matmul, transpose, reshape |
| Reductions | sum(axis), mean(axis) |
| Activations | relu, tanh, sigmoid |
| Math | log, exp |
Linear(in, out)— Fully-connected layer with He initializationReLU,Tanh,Sigmoid— Activation layersMLP(input_dim, hidden_dims, output_dim)— Multi-layer perceptron with configurable architecture
- Loss Functions —
MSELoss,CrossEntropyLoss(binary, with built-in sigmoid) - Optimizer —
SGDwith optional momentum - Datasets — Built-in
make_moonsandmake_circlesgenerators
draw_graph(tensor)— Print the full computation graph topologygradient_check(f, inputs)— Numerical gradient verification via centered finite differences
puregrad/
├── tensor.py Core Tensor class + autograd engine
├── layers.py Module │ Linear │ ReLU │ Tanh │ Sigmoid
├── nn.py MLP composite model
├── loss.py MSELoss │ CrossEntropyLoss
├── optim.py SGD optimizer
├── data.py Synthetic dataset generators
├── utils.py Diagnostics (graph viz, gradient check)
└── tests/
├── test_tensor.py 9 tests — autograd verification
├── test_layers.py 7 tests — layer/MLP verification
└── test_training.py 3 tests — end-to-end convergence
Every operation on a Tensor creates a new node in a dynamically constructed DAG:
Input(X) ──┐
├── [@] matmul ──> [+] add bias ──> [tanh] ──> [@] ──> [+] ──> [sum] = Loss
Weights(W) ─┘ Bias(B)
- Forward Pass — Operations register new Tensor nodes with parent pointers (
_prev) and bind a backward closure (_backward) computing the local vector-Jacobian product - Backward Pass — From the loss node, DFS topological sort yields the evaluation order. Walking in reverse, each node's
_backward()pushes gradients to its parents via+=
For a linear layer Y = X @ W + B:
dL/dX = dL/dY @ Wᵀ
dL/dW = Xᵀ @ dL/dY
dL/dB = Σ_rows(dL/dY)
t = Tensor(data) # Create from array/scalar
t.backward() # Backpropagate from this node
t.grad # Access accumulated gradient
t.shape # Shape of underlying data
t.T # Transpose
t.relu() / t.tanh() # Activations
t.sum(axis) / t.mean(axis) # Reductions
t @ other # Matrix multiplylinear = Linear(in_features=4, out_features=8)
model = MLP(input_dim=2, hidden_dims=[32, 32], output_dim=1, activation="tanh")
model(x) # Forward pass (calls model.forward(x))
model.parameters() # List of all trainable Tensors
model.zero_grad() # Reset all gradients to zeroloss = MSELoss(predictions, targets) # Mean Squared Error
loss = CrossEntropyLoss(logits, targets) # Binary Cross-Entropy
optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9)
optimizer.step() # Apply gradient updates
optimizer.zero_grad() # Reset gradientsfrom puregrad.utils import draw_graph, gradient_check
draw_graph(loss) # Print computation graph
gradient_check(f, [a, b], eps=1e-5, tol=1e-4) # Numerical verificationRun the full test suite:
# Phase 1 & 2: Tensor engine (scalar autograd, broadcasting, matmul, activations)
python -m puregrad.tests.test_tensor
# Phase 3: Layers & MLP (shapes, gradient flow, zero_grad)
python -m puregrad.tests.test_layers
# Phase 4: Training pipeline (MSE loss, SGD step, convergence)
python -m puregrad.tests.test_training| Suite | Tests | Status |
|---|---|---|
| Tensor Engine | 9/9 | Passed |
| Layers & MLP | 7/7 | Passed |
| Training | 3/3 | Passed |
| Total | 19/19 | All Passed |
Key verifications:
- Scalar autograd:
f(a,b) = a*b + b²matches hand-calculated derivatives - Matrix gradients match TRD analytical formulas
- Numerical gradient check via finite differences: relative error < 1e-10
- MLP converges on Moons dataset: loss 0.0199 < 0.05 target, 99.7% accuracy
"If you wish to make an apple pie from scratch, you must first invent the universe." — Carl Sagan
PureGrad exists to make the invisible machinery of deep learning visible. Every gradient, every graph edge, every backward closure is hand-written and inspectable. No black boxes.
Constraints by design:
- No PyTorch, TensorFlow, JAX, or autograd libraries
- NumPy permitted only for raw array storage and element-wise math
- All calculus, graph logic, and backpropagation is proprietary
This project is licensed under the MIT License.
Built with math and determination 🧠