Skip to main content

A robust N-D autograd library with comprehensive ops, NN layers, and optimizers

Project description

JunGrad

A robust N-D autograd library with comprehensive operations, neural network layers, and optimizers.

Features

  • N-D Tensor with numpy backend and automatic differentiation
  • Comprehensive Operations:
    • Elementwise ops (add, sub, mul, div, exp, log, pow, etc.)
    • Reductions (sum, mean, max, min, var, std)
    • Linear algebra (matmul, transpose, reshape, concat, stack)
    • Indexing (gather, scatter_add, slice, take)
  • Neural Network Modules:
    • Linear, Conv1d, Embedding, LayerNorm, Dropout
    • Sequential, Stack containers
    • Parameter and state_dict management
  • Optimizers:
    • SGD (with momentum and Nesterov)
    • Adam, AdamW (decoupled weight decay)
    • RMSProp
    • Gradient clipping utilities
  • Learning Rate Schedulers:
    • StepLR, ExponentialLR
    • CosineLR (with warmup)
    • OneCycleLR
  • Loss Functions:
    • cross_entropy (with label smoothing support)
    • mse_loss
    • bce_with_logits (numerically stable)
  • Functional API:
    • Activations: relu, tanh, sigmoid, gelu
    • Stable: softmax, log_softmax, logsumexp
  • Utilities:
    • Gradient checking via finite differences
    • Profiler for timing operations
    • Graphviz export for computation graphs
    • Hooks system

Installation

# From PyPI (once published)
pip install jungrad

# Optional extras
pip install "JunGrad[viz]"        # Graphviz rendering support
pip install "JunGrad[tutorial]"   # Dependencies for the quickstart notebook
pip install "JunGrad[sparse]"     # SciPy-backed sparse utilities

# Development installation (editable)
pip install -e .

# Development with extras
pip install -e ".[dev,sparse,viz,tutorial]"

Quick Start

Basic Tensor Operations

from jungrad import tensor, randn

# Create tensors
a = tensor([1.0, 2.0, 3.0], requires_grad=True)
b = tensor([4.0, 5.0, 6.0], requires_grad=True)

# Operations
c = a + b
d = a * b
e = a ** 2

# Backward pass
e.backward()
print(f"a.grad = {a.grad}")
print(f"b.grad = {b.grad}")

Neural Network

from jungrad import randn, no_grad
from jungrad.nn import Linear, Sequential, ReLU, Dropout
from jungrad.optim import Adam
from jungrad.losses import cross_entropy
from jungrad.sched import CosineLR
from jungrad.optim import clip_grad_norm_

# Create model with dropout
model = Sequential(
    Linear(10, 64),
    ReLU(),
    Dropout(0.3),
    Linear(64, 32),
    ReLU(),
    Dropout(0.3),
    Linear(32, 5),  # 5 classes
)

# Training data
x = randn(32, 10)
y = [0, 1, 2, 3, 4] * 6 + [0, 1]  # class labels

# Forward pass
logits = model(x)
loss = cross_entropy(logits, y)

# Backward and optimize
optimizer = Adam(model.parameters(), lr=0.001)
loss.backward()
clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
optimizer.zero_grad()

# Evaluation mode
model.eval()
with no_grad():
    pred = model(x)

Complete Training Example

from jungrad import randn, tensor, no_grad
from jungrad.nn import Linear, Sequential, ReLU, Dropout
from jungrad.nn.init import kaiming_normal_
from jungrad.losses import cross_entropy
from jungrad.optim import Adam, clip_grad_norm_
from jungrad.sched import CosineLR
import numpy as np

# Model
model = Sequential(
    Linear(10, 64), ReLU(), Dropout(0.3),
    Linear(64, 32), ReLU(), Dropout(0.3),
    Linear(32, 5),
)

# Initialize weights
for module in model.modules():
    if isinstance(module, Linear):
        kaiming_normal_(module.weight)

# Setup training
optimizer = Adam(model.parameters(), lr=0.001)
scheduler = CosineLR(optimizer, T_max=50)

# Training loop
for epoch in range(50):
    x = randn(32, 10)
    y = np.random.randint(0, 5, size=32)

    model.train()
    logits = model(x)
    loss = cross_entropy(logits, y)

    optimizer.zero_grad()
    loss.backward()
    clip_grad_norm_(model.parameters(), max_norm=1.0)
    optimizer.step()
    scheduler.step()

    # Validation
    if epoch % 10 == 0:
        model.eval()
        with no_grad():
            val_logits = model(randn(16, 10))
            print(f"Epoch {epoch}, Loss: {loss.item():.4f}")

Gradient Checking

from jungrad import randn
from jungrad.ops import matmul
from jungrad.testing import gradcheck

# Verify gradients are correct
a = randn(3, 4, requires_grad=True)
b = randn(4, 5, requires_grad=True)

passed = gradcheck(lambda x, y: matmul(x, y), (a, b), eps=1e-5)
print(f"Gradients verified: {passed}")

Tutorial

See quickstart.ipynb for a comprehensive interactive tutorial covering:

  • Creating and manipulating N-D tensors
  • Automatic differentiation and gradient computation
  • Building neural networks with Sequential layers
  • Training models with optimizers (SGD, Adam, AdamW, RMSProp)
  • Advanced layers (Conv1d, LayerNorm, Embedding, Dropout)
  • Activation functions and functional API
  • Learning rate schedulers (StepLR, CosineLR, OneCycleLR)
  • Gradient clipping for stable training
  • Performance optimization with no_grad()
  • Computation graph visualization with Graphviz
  • Performance profiling
  • Gradient checking for verification
  • End-to-end classification demo with real-world data (20 Newsgroups dataset)

Documentation

Tensor API

from jungrad import Tensor, tensor, zeros, ones, randn

# Creation
x = tensor([1.0, 2.0, 3.0], requires_grad=True)
x = zeros((3, 4))
x = ones((2, 2))
x = randn(5, 5)

# Methods
x.detach()           # Detach from graph
x.retain_grad()      # Retain gradient for non-leaf
x.item()             # Get scalar value
x.numpy()            # Get numpy array
x.backward()         # Compute gradients
x.zero_grad()        # Zero gradients

Autograd

from jungrad import no_grad, enable_grad

# Context managers
with no_grad():
    # Operations without gradients
    y = x * 2

with enable_grad():
    # Enable gradients
    z = x + y

Operations

from jungrad.ops import add, mul, matmul, sum, mean

# Elementwise
c = add(a, b)
c = mul(a, b)

# Matrix multiplication
out = matmul(x, w)

# Reductions
s = sum(x, axis=0, keepdims=True)
m = mean(x, axis=-1)

Neural Network Layers

from jungrad.nn import Linear, Conv1d, Embedding, LayerNorm, Dropout

# Linear layer
linear = Linear(in_features=10, out_features=5, bias=True)

# Conv1d
conv = Conv1d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)

# Embedding
embed = Embedding(num_embeddings=1000, embedding_dim=128)

# LayerNorm
ln = LayerNorm(normalized_shape=128, eps=1e-5, affine=True)

# Dropout
dropout = Dropout(p=0.5)

Optimizers

from jungrad.optim import SGD, Adam, AdamW, RMSProp, clip_grad_norm_

# SGD
optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9, nesterov=True)

# Adam
optimizer = Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))

# AdamW (decoupled weight decay)
optimizer = AdamW(model.parameters(), lr=0.001, weight_decay=0.01)

# Gradient clipping
clip_grad_norm_(model.parameters(), max_norm=1.0)

Loss Functions

from jungrad.losses import cross_entropy, mse_loss, bce_with_logits

# MSE loss
loss = mse_loss(pred, target)

# Cross-entropy (supports index and one-hot targets)
loss = cross_entropy(logits, target_indices)
loss = cross_entropy(logits, target_onehot, label_smoothing=0.1)

# BCE with logits
loss = bce_with_logits(logits, target)

Development

Running Tests

Run all tests:

pytest tests/
# or
python -m pytest tests/

Run with verbose output:

pytest tests/ -v

Run a specific test file:

pytest tests/test_tensor.py

Run a specific test:

pytest tests/test_autograd.py::test_backward_simple

Run tests matching a pattern:

pytest tests/ -k "backward"

With coverage report:

pytest tests/ --cov=jungrad --cov-report=term-missing

See TESTING.md for detailed testing documentation.

Code Quality

# Format
black jungrad/

# Lint
ruff check jungrad/

# Type check
mypy jungrad/

Architecture

  • tensor.py: N-D Tensor class with autograd support
  • autograd.py: Backward engine with topological sort
  • ops.py: Low-level primitive operations (200+ operations)
  • functional.py: High-level differentiable functions (activations, softmax)
  • losses.py: Loss functions (MSE, cross-entropy, BCE)
  • nn/: Neural network modules (Module, Parameter, layers, initialization, utils)
  • optim/: Optimizers (SGD, Adam, AdamW, RMSProp) and gradient clipping
  • sched/: Learning rate schedulers (StepLR, CosineLR, OneCycleLR, ExponentialLR)
  • testing/: Gradient checking utilities
  • graphviz.py: Computation graph visualization
  • profiler.py: Performance profiling tools
  • hooks.py: Forward and backward hooks for debugging

Design Philosophy

  • N-D from the start: Not scalar-only like micrograd - works with tensors of any shape
  • Separate engine: Clean separation between tensor and autograd engine
  • Broadcast-aware: Proper handling of broadcasting in forward and backward passes
  • Numerically stable: Uses logsumexp for softmax, stable sigmoid, stable BCE with logits
  • Type-safe: Full type hints throughout the codebase
  • PyTorch-inspired API: Familiar interface for users coming from PyTorch
  • Educational: Clear, well-documented code suitable for learning autograd internals

Real-World Example

The quickstart.ipynb tutorial includes a complete end-to-end classification demo using the 20 Newsgroups dataset, demonstrating:

  • Loading real-world text data
  • TF-IDF feature extraction
  • Multi-layer neural network with dropout
  • Training with learning rate scheduling
  • Gradient clipping for stability
  • Comprehensive evaluation metrics
  • Training curve visualization

This showcases how JunGrad can be used for practical machine learning tasks beyond synthetic examples.

License

MIT License

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

jungrad-0.1.0.tar.gz (208.5 kB view details)

Uploaded Source

Built Distribution

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

jungrad-0.1.0-py3-none-any.whl (40.5 kB view details)

Uploaded Python 3

File details

Details for the file jungrad-0.1.0.tar.gz.

File metadata

  • Download URL: jungrad-0.1.0.tar.gz
  • Upload date:
  • Size: 208.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.16

File hashes

Hashes for jungrad-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8fd31411b9edf649b8356ebf3499b5a6c4c2855d050dd9de4040542d3588a91e
MD5 417fb83e17d99e0951d3395b2b9a154a
BLAKE2b-256 4a23ebed5ccbd8edcc81a519fc9cb150e10fa48b9edd4a363b8fe44cc19da6d7

See more details on using hashes here.

File details

Details for the file jungrad-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: jungrad-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 40.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.16

File hashes

Hashes for jungrad-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1d6d91a772315c096c68ec6b6a3d46a895a6034e99924522313d138db888bd6c
MD5 0702e0c6f8a1b5fb79998690f94145e1
BLAKE2b-256 eecae154fb5b4d98737cad64edeae5caa65137fdd9aa5e2e59e40031bbf8d0b4

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