Skip to main content

An educational but robust deep learning framework implemented from scratch using NumPy.

Project description

ToyNet

Python 3.12+ MIT License Type Checked Ruff

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

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 matrix
  • x: Input vector
  • b: 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

toynet_ml-1.0.0.tar.gz (16.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

toynet_ml-1.0.0-py3-none-any.whl (20.2 kB view details)

Uploaded Python 3

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

Hashes for toynet_ml-1.0.0.tar.gz
Algorithm Hash digest
SHA256 6bc58ddbdf46b60fd3903495c03a293a9f68c86117281a93ce8388abd5854b85
MD5 1e7a41b517ecdd27cdc7e1c3c9242ab1
BLAKE2b-256 a71e17ceafe1ee5844ccbc7da3fa07aacb295877b6861c731fee5df7df5bd61b

See more details on using hashes here.

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

Hashes for toynet_ml-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 03e20e4e5bb5c881e2b6c35073265f858ae67f32ab1f24e236629da18caf4162
MD5 7771a91a38cbb93f28408c3220989a51
BLAKE2b-256 4fa260a810711386407d84dcbd7111e720d4efc082c214b845f26788b3119c06

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page