pytensor_ml#
A(nother) deep learning library, built on top of PyTensor.
Networks are ordinary PyTensor graphs. You build one out of layers, and everything PyTensor already does — symbolic differentiation, graph rewrites, and compilation to Numba, C, JAX, PyTorch, or MLX — applies to it unchanged. Training is a compiled function that takes a batch and returns a loss; there is no separate runtime or tape.
That goes all the way down: layers are graph constructors, parameters are shared variables, and a training step is a compiled function whose updates are the optimizer. Because a model is only a graph, it composes with any other PyTensor graph — a PyMC model included — as there is nothing else to interoperate with.
pytensor_ml ships the usual layer library (dense, convolutional, recurrent, attention, normalization), composable optimizers with learning-rate schedules and step guards, and safetensors-backed serialization that round-trips both weights and architecture.
Note
pytensor_ml is pre-alpha. The API is still moving, and there is no release-to-release compatibility guarantee yet.
Quick install#
pip install pytensor-ml
See the installation guide for backend extras.
Quick example#
import numpy as np
from pytensor import config
from sklearn.datasets import load_digits
from pytensor_ml.activations import ReLU
from pytensor_ml.layers import Input, Linear, Sequential
from pytensor_ml.loss import CrossEntropy
from pytensor_ml.model import Model
from pytensor_ml.optim import adam, chain, clip_by_global_norm, cosine_schedule
from pytensor_ml.util import DataLoader
X, y = load_digits(return_X_y=True)
X = (X / 16.0).astype(config.floatX)
y_onehot = np.eye(10, dtype=config.floatX)[y]
X_in = Input("X_in", shape=(None, 64))
network = Sequential(
Linear("fc1", n_in=64, n_out=128),
ReLU(),
Linear("logits", n_in=128, n_out=10),
)
model = Model(network(X_in)).initialize(seed=0)
rule = chain(clip_by_global_norm(1.0), adam(learning_rate=cosine_schedule(1e-3, total_steps=500)))
loss_fn = CrossEntropy(expect_onehot_labels=True, expect_logits=True, reduction="mean")
step = model.compile_train(rule, loss_fn)
loader = DataLoader(X, y_onehot, batch_size=64, random_state=0)
for _ in range(500):
loss_value = step(*loader())
predictions = model.predict(X).argmax(axis=-1)
See the example gallery for full end-to-end walkthroughs.