An educational but robust deep learning framework implemented from scratch using NumPy.
Project description
ToyNet
An educational but robust deep learning framework implemented from scratch using NumPy.
Data loading is handled with Pandas.
ToyNet provides a clean, extensible architecture for building and training neural networks without external ML dependencies. Perfect for understanding deep learning mathematical fundamentals or experimenting with custom architectures on small to medium datasets.
Table of Contents
- Features
- Installation
- Quick Start
- Architecture Overview
- Comprehensive Example
- Mathematical Foundations
- Development
- License
Features
Core Capabilities
- Pure NumPy implementation - No external ML libraries, transparent mathematical operations
- Educational focus - Clear, readable code designed for learning and understanding
- Modular architecture - Easily extensible with custom components
- Type safety - Full mypy compatibility with comprehensive type hints
- Comprehensive tests - Unit, integration, and end-to-end tests with high coverage
Data Handling
- Data loaders - Support for CSV files and in-memory arrays
- Preprocessing - Programmable feature scaling, train/validation splits in data loaders
- Batch processing - Efficient mini-batch training with configurable sizes
Neural Network Components
- Layers: Customizable with activation functions, weight initialization methods
- Activation and loss functions: Classic activations and losses for various tasks with the protocols to create custom ones
- Optimizers: Classic GD variants or Adam with adaptive learning rates
Training Features
- Training policies - Early stopping, learning rate scheduling, model checkpointing, protocol for custom policies
- Model persistence - Save/load trained models in NumPy format
- Logging - Comprehensive training progress tracking
Installation
From PyPI (Recommended)
pip install toynet-ml
Quick Start
Simple XOR Problem
import numpy as np
from toynet import MultiLayerPerceptron, Dense, BasicDataLoader
from toynet.functions import ReLU, Sigmoid, BinaryCrossEntropy
from toynet.optimizers import Adam
# Create XOR dataset
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]).reshape(4, 1, 2)
y = np.array([[0], [1], [1], [0]]).reshape(4, 1, 1)
# Build network
network = MultiLayerPerceptron(
layers=[
Dense(2, 8, ReLU),
Dense(8, 1, Sigmoid)
],
loss_function=BinaryCrossEntropy,
optimizer=Adam(learning_rate=0.01)
)
# Train
data_loader = BasicDataLoader(X, y, batch_size=2)
network.train(data_loader, epochs=1000)
# Make batch predictions
predictions = network(X)
predictions_rounded = np.round(predictions, 2)
print(f"Input: \n{X.reshape(4, 2)}")
print(f"Predictions: {predictions_rounded.flatten()}")
Simple Regression Problem: Predict y = 2x + 1
import numpy as np
from toynet import MultiLayerPerceptron, Dense, BasicDataLoader
from toynet.functions import ReLU, Identity, MeanSquaredError
from toynet.optimizers import Adam
# Create regression dataset
X = np.array([[-4], [-3], [-2], [-1], [0], [1], [2], [3], [4], [5], [6]]).reshape(11, 1, 1)
y = np.array([[-7], [-5], [-3], [-1], [1], [3], [5], [7], [9], [11], [13]]).reshape(11, 1, 1)
# Build network
network = MultiLayerPerceptron(
layers=[
Dense(1, 8, ReLU),
Dense(8, 8, ReLU),
Dense(8, 1, Identity)
],
loss_function=MeanSquaredError,
optimizer=Adam(learning_rate=0.01)
)
# Train
data_loader = BasicDataLoader(X, y, batch_size=4)
network.train(data_loader, epochs=1000)
# Make unseen data prediction
prediction = network(np.array([9]).reshape(1, 1)) # 2x + 1 = 19
print(f"Predictions: {prediction.flatten()}")
Architecture Overview
ToyNet follows a modular, object-oriented design:
MultiLayerPerceptron
├── Layers (Dense)
│ ├── Input/Output dimensions
│ ├── Activation Functions (ReLU, Sigmoid, etc.)
│ └── Weight Initializers (He (default), Xavier)
├── Loss Function (CrossEntropy, MSE)
└── Optimizer (GD variants, Adam)
Training
├── Data Loader (Basic, CSV)
├── Fixed epochs
└── Training Policies (EarlyStopping, LR Scheduling etc.)
Comprehensive Example
End to end training on Kaggle Digit Recognizer CSV dataset
import numpy as np
from toynet import Adam, CSVDataloader, Dense, MultiLayerPerceptron
from toynet.functions import (
CategoricalCrossEntropy,
ReLU,
Softmax,
)
from toynet.policies import ReduceLROnPlateau, SaveBestModel, ValidationLossEarlyStop
if __name__ == "__main__":
data_loader = CSVDataloader(
"train.csv",
batch_size=128,
label_cols=["label"],
validation_split=0.2,
transform=lambda X, y: (X / 255.0, np.eye(10)[y.astype(int)]),
)
nnet = MultiLayerPerceptron(
[
Dense(784, 256, ReLU),
Dense(256, 128, ReLU),
Dense(128, 64, ReLU),
Dense(64, 10, Softmax),
],
loss_function=CategoricalCrossEntropy,
optimizer=Adam(
learning_rate=0.01,
),
)
nnet.train(
data_loader,
epochs=250,
policies=[
ValidationLossEarlyStop("mnist.npz", patience=6),
ReduceLROnPlateau(factor=0.1, patience=4, min_lr=1e-6),
SaveBestModel("mnist_best_checkpoint.npz", save_grace_period=20),
],
)
Benchmarks:
- Training time: ~40 minutes on modern CPU
- Best Kaggle test accuracy achieved: 96.6%
For production workloads, use PyTorch or TensorFlow which offer GPU acceleration and distributed training.
Mathematical Foundations
ToyNet implements core neural network mathematics from scratch:
Forward Propagation
h = σ(Wx + b)
Where:
W: Weight matrixx: Input vectorb: Bias vectorσ: Activation function
Backpropagation
Automatic gradient computation using the chain rule:
∂L/∂W = ∂L/∂h × ∂h/∂z × ∂z/∂W
Gradients are computed and stored in layer objects during backpropagation.
Weight Updates
- GD variants:
W ← W - η∇W - Adam: Adaptive learning with momentum and RMSprop
Development
Running tests and code checks
After cloning the repository and setting up a virtual environment:
# Install development dependencies
pip install -e ".[dev]"
# Run all tests with coverage
pytest --cov=toynet --cov-report=html
# Type checking
mypy --install-types --config-file pyproject.toml ./src
# Code formatting
ruff format
ruff check --fix
Project Structure
toynet/
├── src/toynet/ # Main package
│ ├── data_loaders/ # Data loading utilities
│ ├── functions/ # Activation and loss functions
│ ├── initializers/ # Weight initialization
│ ├── layers/ # Layer implementations
│ ├── networks/ # Neural network architectures
│ ├── optimizers/ # Gradient descent algorithms
│ ├── policies/ # Training policies
│ └── config.py # Configuration settings
│
├── tests/ # Test suite
│ ├── uts/ # Unit tests
│ ├── integration/ # Integration tests
└───└── e2e/ # End-to-end tests
License
This project is licensed under the MIT License - see the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file toynet_ml-1.0.0.tar.gz.
File metadata
- Download URL: toynet_ml-1.0.0.tar.gz
- Upload date:
- Size: 16.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6bc58ddbdf46b60fd3903495c03a293a9f68c86117281a93ce8388abd5854b85
|
|
| MD5 |
1e7a41b517ecdd27cdc7e1c3c9242ab1
|
|
| BLAKE2b-256 |
a71e17ceafe1ee5844ccbc7da3fa07aacb295877b6861c731fee5df7df5bd61b
|
File details
Details for the file toynet_ml-1.0.0-py3-none-any.whl.
File metadata
- Download URL: toynet_ml-1.0.0-py3-none-any.whl
- Upload date:
- Size: 20.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
03e20e4e5bb5c881e2b6c35073265f858ae67f32ab1f24e236629da18caf4162
|
|
| MD5 |
7771a91a38cbb93f28408c3220989a51
|
|
| BLAKE2b-256 |
4fa260a810711386407d84dcbd7111e720d4efc082c214b845f26788b3119c06
|