A lightweight, powerful Python framework for training AI models — inspired by numpy, scikit-learn, PyTorch and TensorFlow.
Project description
EmberML
A lightweight, powerful Python framework for training AI models — built from scratch.
EmberML combines the essentials of numpy, scikit-learn, PyTorch and TensorFlow into one small, readable codebase. The core has exactly one hard dependency (numpy); everything else — GPU support, PyTorch/TensorFlow/scikit-learn/OpenCV interop — is an optional extra you opt into.
Author: Levi Enama
Honest positioning
EmberML's own autograd engine is pure numpy. It is not a replacement for PyTorch or TensorFlow on real production workloads — it doesn't have compiled CUDA kernels, doesn't do distributed multi-node training, and won't match their raw throughput on large models. What it gives you instead:
- A training engine you can read end-to-end in an afternoon, with every op unit-tested and several (
Conv2d,MaxPool2d, checkpointing) verified against numerical gradients - A single, consistent API across deep learning and classical ML and data loading and metrics
- Real, working bridges to PyTorch/TensorFlow/scikit-learn/OpenCV for when you need their production-grade speed or ecosystem, without leaving EmberML's workflow
Features
Core (numpy only)
- Full reverse-mode autograd on n-dimensional tensors
nn:Linear,Conv2d,MaxPool2d,Flatten,Dropout,BatchNorm1d,SimpleRNN,Sequentialoptim:SGD,Adam,AdamW,RMSprop+lr_scheduler:StepLR,ExponentialLR,ReduceLROnPlateauml:LinearRegression,LogisticRegression,KMeans,KNNClassifier,GaussianNB,PCA,DecisionTreeClassifier,RandomForestClassifiermetrics: precision, recall, F1, confusion matrix, MSE, R²Dataset/DataLoader(generic, works with lazy/on-disk data too) /train_test_split- Model persistence:
.save()/.load()for networks,save_model()/load_model()for classical ML EarlyStoppingcallback
Native acceleration (optional C++/C/Rust, auto-detected — see emberml/_native/)
Conv2d/MaxPool2dtransparently use a compiled C++/OpenMP extension for the im2col/col2im/max-pool steps on CPU float32 tensors — the actual measured bottleneck in the pure-Python path (np.add.at-basedcol2im), not the matmul itself (numpy's BLAS already wins there). Falls back to the original pure-numpy code automatically on GPU tensors, other dtypes, or if no C++ compiler was available at install time — results are bit-for-bit checked equal either way (tests/test_native.py).emberml.security: HMAC-SHA256 signing for saved models (save_model_secure()/load_model_secure()), backed by a small, dependency-free C implementation of SHA-256/HMAC. Addresses the fact that plainpickle.load()(whatsave_model()/load_model()use) runs arbitrary code from the file — verification happens before unpickling, so a wrong key or a tampered file is rejected outright.emberml.safeformat: a pickle-free binary container (.emsf) for{name: numpy.ndarray}dicts — no unpickling step exists at all, so there's no code-execution surface to defend, unlike signed pickle. Implemented in Rust (PyO3) for safe parsing of untrusted files (bounds checking, no manual buffer arithmetic), with a byte-for-byte cross-compatible pure-Python fallback.security.save_tensors_secure()/load_tensors_secure()combine it with the same HMAC signing as above — the strongest option when what you're saving is purely tensors (nn.Moduleweights, embeddings).Module.save(path, format="safe")uses it directly.- Check
emberml.HAVE_NATIVE_OPS/emberml.HAVE_NATIVE_CRYPTO/emberml._native.HAVE_NATIVE_SAFEFORMATat runtime to see which compiled extensions are active.
Scaling up (still numpy/stdlib only)
- GPU:
Tensor(..., device="cuda")/Module.to("cuda")via CuPy — a drop-in numpy-compatible GPU array library. Requirespip install emberml[gpu]and an NVIDIA GPU; raises a clear error rather than silently running on CPU if unavailable. - Mixed precision:
emberml.amp.autocast()+GradScaler(dynamic loss scaling) - Gradient checkpointing:
emberml.checkpoint.checkpoint(fn, *tensors)— trade compute for memory on deep networks - CPU data parallelism:
emberml.parallel.DataParallelCPU— shard a batch across processes on one machine (not multi-GPU/multi-node)
emberml.integrations (optional bridges, not imported by default)
torch_bridge— hand off to real PyTorch when you need production GPU speedtf_bridge— hand off to real TensorFlowsklearn_bridge— useemberml.mlmodels inside scikit-learnPipeline/GridSearchCV, or reach for a real scikit-learn model by namecv— OpenCV-backedImageDataset, image loading, flip/rotation augmentation
Installation
git clone https://github.com/<your-username>/emberml.git
cd emberml
pip install -e . # core only (numpy) — native extensions build automatically if a C/C++ compiler is present
pip install -e .[torch] # + PyTorch bridge
pip install -e .[tf] # + TensorFlow bridge
pip install -e .[sklearn] # + scikit-learn bridge
pip install -e .[cv] # + OpenCV bridge
pip install -e .[gpu] # + CuPy (needs an NVIDIA GPU)
pip install -e .[all] # everything
No C/C++ compiler or Rust toolchain on the machine (or a build hiccup)?
Installation still succeeds — pip prints a one-line warning per missing
toolchain and emberml runs on its pure-Python/numpy fallbacks. Verify
what actually got built:
import emberml
print(emberml.HAVE_NATIVE_OPS, emberml.HAVE_NATIVE_CRYPTO, emberml._native.HAVE_NATIVE_SAFEFORMAT)
Signing a model checkpoint
from emberml import security
key = security.generate_key() # keep this secret; os.urandom(32) under the hood
security.save_model_secure(model, "model.emlpkl", key)
# ... later, possibly on another machine / after downloading the file ...
model = security.load_model_secure("model.emlpkl", key) # raises SecurityError on wrong key or tampering
Pickle-free tensor checkpoints (recommended for nn.Module weights)
# strongest option for pure-tensor checkpoints: no pickle anywhere, plus HMAC authenticity
from emberml import security
key = security.generate_key()
security.save_tensors_secure({"w1": w1, "b1": b1}, "weights.bin", key)
tensors = security.load_tensors_secure("weights.bin", key) # SecurityError on wrong key/tampering
# or, unsigned, straight from a Module:
model.save("checkpoint", format="safe") # writes checkpoint.emsf, no pickle involved
model.load("checkpoint", format="safe")
Quick start
Train a CNN, GPU if available
import numpy as np
from emberml import Tensor, nn, optim
device = "cuda" # falls back to "cpu" if you don't have CuPy + a GPU
X = Tensor(np.random.randn(32, 1, 28, 28).astype(np.float32), device="cpu")
y = Tensor(np.random.randint(0, 2, (32, 1)).astype(np.float32), device="cpu")
model = nn.Sequential(
nn.Conv2d(1, 8, kernel_size=3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.Flatten(), nn.Linear(8 * 14 * 14, 32), nn.ReLU(), nn.Dropout(0.3),
nn.Linear(32, 1), nn.Sigmoid(),
)
# model.to("cuda"); X = X.to("cuda"); y = y.to("cuda") # uncomment on a GPU box
optimizer = optim.Adam(model.parameters(), lr=0.001)
for epoch in range(10):
optimizer.zero_grad()
loss = nn.bce_loss(model(X), y)
loss.backward()
optimizer.step()
model.save("mnist_like_model")
Mixed precision training
from emberml.amp import autocast, GradScaler
scaler = GradScaler()
with autocast():
pred = model(X)
loss = nn.mse_loss(pred, y)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
When you need real PyTorch speed
from emberml.integrations import torch_bridge
torch_state = torch_bridge.emberml_module_to_torch_state(model)
# now train_state in real torch.Tensors on a real GPU with real torch.optim
Classic ML inside a scikit-learn Pipeline
from emberml import ml
from emberml.integrations.sklearn_bridge import EmberMLClassifier
from sklearn.model_selection import cross_val_score
clf = EmberMLClassifier(ml.RandomForestClassifier, n_estimators=50)
scores = cross_val_score(clf, X_train, y_train, cv=5)
Real image data via OpenCV
from emberml.integrations.cv import ImageDataset
from emberml import DataLoader
ds = ImageDataset(image_paths, labels, size=(64, 64), augment=True)
loader = DataLoader(ds, batch_size=32, shuffle=True)
Command-line interface
python -m emberml info # library info
python -m emberml demo # run a live training demo
python -m emberml benchmark --iters 500 # benchmark forward+backward speed
python -m emberml --help # list all commands
Architecture
emberml/
├── tensor.py # Core: Tensor + autograd, device (CPU/CUDA) + dtype aware
├── functional.py # conv2d / max_pool2d (im2col/col2im, gradient-checked, device-aware)
├── amp.py # autocast + GradScaler (mixed precision)
├── checkpoint.py # gradient checkpointing
├── parallel.py # CPU multiprocessing data parallelism
├── nn/ # Linear, Conv2d, MaxPool2d, Flatten, Dropout,
│ # BatchNorm1d, SimpleRNN, Sequential, losses
├── optim.py # SGD, Adam, AdamW, RMSprop
├── lr_scheduler.py # StepLR, ExponentialLR, ReduceLROnPlateau
├── callbacks.py # EarlyStopping
├── ml/ # LinearRegression, LogisticRegression, KMeans,
│ # KNNClassifier, GaussianNB, PCA, DecisionTree,
│ # RandomForest
├── data.py # Dataset, DataLoader (generic), train_test_split
├── metrics.py # precision/recall/F1/confusion_matrix/MSE/R²
├── utils.py # seed, accuracy, one_hot, normalize, save/load
├── security.py # HMAC-SHA256 model signing (save_model_secure/load_model_secure)
├── safeformat.py # pickle-free tensor container dispatcher (.emsf)
├── _safeformat_py.py # pure-Python reference impl of the .emsf format
├── cli.py # info / demo / benchmark
├── _native/ # OPTIONAL — compiled C++/C/Rust extensions, auto-detected
│ ├── ops.cpp # im2col/col2im/max_pool2d/activations (pybind11 + OpenMP)
│ ├── sha256.c, sha256.h, _crypto.c # SHA-256/HMAC (plain C, no dependencies)
│ ├── rust_safeformat/ # Cargo crate: .emsf reader/writer (PyO3, memory-safe parsing)
│ └── __init__.py # try/except imports; HAVE_NATIVE_OPS / _CRYPTO / _SAFEFORMAT
└── integrations/ # OPTIONAL — never imported by default
├── torch_bridge.py
├── tf_bridge.py
├── sklearn_bridge.py
└── cv.py
tests/ # 48 pytest tests (gradient checks, native-vs-reference checks, integration bridges)
examples/train_cnn_classifier.py # full end-to-end training example
setup.py # builds ext_modules (C/C++) + cargo build (Rust); metadata stays in pyproject.toml
.github/workflows/ci.yml # CI: core job (numpy only, + Rust toolchain) + integrations job (all extras)
Testing
pip install -e .[dev]
pytest tests/ -v # core tests, including native-extension checks (auto-skipped if not built)
pip install -e .[all,dev]
pytest tests/ -v # + integration bridge tests
Roadmap
- LSTM / GRU cells
- Real multi-GPU / multi-node distributed training (would hand off to
torch.distributedrather than reinvent it) - ONNX-style model export
License
MIT — see LICENSE.
Author
Levi Enama
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 emberml-0.5.0.tar.gz.
File metadata
- Download URL: emberml-0.5.0.tar.gz
- Upload date:
- Size: 64.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ef931ceac1a6b6b9eacc6d978b3508f011dcc72a0452b6bb0e22765f61508e26
|
|
| MD5 |
d2a2428fcb2fd39d653f15ce927a41b1
|
|
| BLAKE2b-256 |
71275879227b2f2190dcaaf21b2654acb36288884fecea83a0d5fa6013109161
|
File details
Details for the file emberml-0.5.0-cp310-cp310-win_amd64.whl.
File metadata
- Download URL: emberml-0.5.0-cp310-cp310-win_amd64.whl
- Upload date:
- Size: 58.8 kB
- Tags: CPython 3.10, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
924c5aae07f1861ea178a418eb4177af58b15686eecf4414ecb844fc68d862bf
|
|
| MD5 |
53b1f8f9b74c2bd89459c7771238137e
|
|
| BLAKE2b-256 |
f1e2a9033ab2a231622b6c76d1dc0ecc56a192468964bec381ef96223b47a96d
|