mononet#
Constrained monotonic neural networks with first-class support for PyTorch, JAX (Flax NNX), and Keras 3.
Reference implementation of:
Runje, D., Shankaranarayana, S. M. (2023). Constrained Monotonic Neural Networks. ICML 2023. arXiv:2205.11775
Install#
pip install "mononet[torch]" # or [jax], [keras], [all]
See Installation for the full extras reference, GPU extras, and the CPU-torch (uv vs pip) caveat.
Quickstart#
Your first monotonic model — a small regressor that is non-decreasing in every
input. mononet ships layers; stack them with your framework’s native
Sequential.
# SPDX-License-Identifier: Apache-2.0
"""Quickstart: a monotone regressor in PyTorch.
Non-decreasing in every one of its 4 inputs. ``mononet`` ships layers, not
composed models — stack them with a native ``torch.nn.Sequential``.
"""
from __future__ import annotations
import torch
from torch import nn
from mononet.torch import MonoLinear, MonoResidual
model = nn.Sequential(
MonoLinear(4, 32, activation="elu"),
MonoResidual(32, 32, activation="elu"),
MonoLinear(32, 1),
)
y = model(torch.rand(8, 4))
print(y.shape) # torch.Size([8, 1]) — monotone in all 4 inputs
# SPDX-License-Identifier: Apache-2.0
"""Quickstart: a monotone regressor in JAX / Flax NNX.
Non-decreasing in every one of its 4 inputs. Dense layers take an explicit
``rngs`` for weight initialization.
"""
from __future__ import annotations
import jax
from flax import nnx
from mononet.jax import MonoLinear, MonoResidual
rngs = nnx.Rngs(0)
model = nnx.Sequential(
MonoLinear(4, 32, activation="elu", rngs=rngs),
MonoResidual(32, 32, activation="elu", rngs=rngs),
MonoLinear(32, 1, rngs=rngs),
)
y = model(jax.random.uniform(jax.random.key(0), (8, 4)))
print(y.shape) # (8, 1) — monotone in all 4 inputs
# SPDX-License-Identifier: Apache-2.0
"""Quickstart: a monotone regressor in Keras 3.
Non-decreasing in every one of its 4 inputs. Runs on whichever backend Keras is
configured to use (``KERAS_BACKEND``); ``MonoDense`` infers the input width.
"""
from __future__ import annotations
import keras
from mononet.keras import MonoDense, MonoResidual
model = keras.Sequential(
[
MonoDense(32, activation="elu"),
MonoResidual(32, activation="elu"),
MonoDense(1),
]
)
y = model(keras.ops.zeros((8, 4)))
print(tuple(y.shape)) # (8, 1) — monotone in all 4 inputs
The same layers exist in all three backends — see the guide for the full mixed-feature example.
Where to next#
Build something — the guides: the full mixed-feature example and per-backend specifics.
Understand how it stays monotone — concepts.
See it work / reproduce results — benchmarks.
API details — the reference.
Citation#
If you use mononet in academic work, please cite the reference paper:
@inproceedings{runje2023constrained,
title = {Constrained Monotonic Neural Networks},
author = {Runje, Davor and Shankaranarayana, Sharath M.},
booktitle = {Proceedings of the 40th International Conference on Machine Learning},
series = {Proceedings of Machine Learning Research},
volume = {202},
year = {2023},
publisher = {PMLR},
url = {https://proceedings.mlr.press/v202/runje23a.html},
eprint = {2205.11775},
archivePrefix = {arXiv}
}
Note: confirm the exact BibTeX entry against the PMLR proceedings page before the first PyPI release — venue, volume, and URL fields are sensitive to typos.