masaMLP
Extensible tabular deep learning — TabularResNet, DANet, and TabularLNN behind sklearn-compatible estimators with first-class sample_weight, custom objectives, custom metrics, and early stopping on any metric. The sibling library of repleafgbm (same author, same API philosophy), for the neural side of tabular ML.
Status: alpha (0.2.x). Built with heavy use of Claude Code (coding and architecture design).
Why masaMLP
Excellent tabular DL libraries exist — pytabkit
ships state-of-the-art models like RealMLP and TabM, and
rtdl provides reference modules.
What they don't make easy is extension: sample_weight in fit, custom
training losses, custom evaluation metrics, and early stopping driven by
them. masaMLP is built around exactly those hooks:
fit(X, y, sample_weight=..., eval_set=...)— LightGBM-style, sklearn compatible. Weights flow through a single reduction(loss * w).sum() / w.sum()that every objective shares.- Custom objectives are per-sample torch losses — a plain function (or
nn.Modulewith trainable parameters). Because the trainer owns the weighted reduction, your loss gets correctsample_weightandclass_weighthandling for free. - Custom metrics are plain NumPy callables via
make_metric, and any of them (minimize or maximize) can drive early stopping with best-epoch weight restoration. - Multiclass, multioutput regression, class_weight, label smoothing
supported natively; built-in preprocessing (quantile scaling, missing
values, categorical embeddings) so DataFrames go straight into
fit. - CPU / CUDA / MPS / multi-GPU behind
device="auto": device-resident tensors with no DataLoader overhead, automatic full-batch mode for small data, per-model bf16 AMP on CUDA, opt-intorch.compilewith eager fallback — and when several GPUs are detected,n_ensmembers train concurrently, one worker per GPU.
masaMLP deliberately does not try to re-benchmark the field — see docs/attribution.md for the research and libraries it builds on.
Models
| name | source | notes |
|---|---|---|
resnet |
Gorishniy et al. 2021 (arXiv:2106.11959) | default; strong baseline |
tabm |
Gorishniy et al. 2024 (arXiv:2410.24210) | parameter-efficient deep ensemble: byte-compatible variant="mini", or headline full BatchEnsemble on every backbone linear with variant="full"; supports quantile PLE-vB (num_embedding="ple") and independent member batches |
realmlp |
Holzmüller et al. 2024 (arXiv:2407.04491) | RealMLP-TD-S architecture (scaling layer, NTP linear layers, SELU/Mish); pair with masamlp.realmlp_params(task) for the full training recipe |
realm |
Holzmüller et al. 2024 + Gorishniy et al. 2024 | RealMLP backbone under TabM-style full BatchEnsemble (new in 0.9.2): k members share one weight matrix per layer and differ through rank-1 r/s adapters, per-member biases and per-member heads — diversity is learned jointly instead of bought with k independent fits. k, member_init, adapter_lr_factor; preset masamlp.realm_td_params(task, k=...). See docs/realm.md |
ft_transformer |
Gorishniy et al. 2021 (arXiv:2106.11959) | feature tokens + [CLS] + PreNorm/ReGLU transformer, per the rtdl reference |
tab_transformer |
Huang et al. 2020 (arXiv:2012.06678) | transformer over categorical tokens; numerics bypass (or embed via num_embedding) |
danet |
Chen et al. AAAI 2022 (arXiv:2112.02962) | Abstract Layers with learnable sparse feature groups (in-house entmax15) |
tabr |
Gorishniy et al. 2023 (arXiv:2307.14338) | retrieval-augmented: nearest training rows are aggregated into each prediction |
modernnca |
Ye et al. 2024 (arXiv:2407.03257) | soft-nearest-neighbor aggregation with stochastic candidate sampling; pairs well with num_embedding="plr-lite" |
gandalf |
Joseph & Raj 2022 (arXiv:2207.08548) | GFLU stages: learnable sparse feature masks (t-softmax) with GRU-style gating; exposes feature_importances() |
grn |
GRN blocks from TFT, Lim et al. 2021 (arXiv:1912.09363) | stack of Gated Residual Networks over embedded features (masaMLP's own composition) |
lnn |
CfC cells, Hasani et al. 2022 | experimental liquid-network adaptation for static tabular data — see docs/lnn.md |
Third-party architectures plug in with register_model and get the whole
estimator surface (weights, objectives, metrics, early stopping) for free.
Every architecture is fully configurable through model_params — depth,
width, dropout, and the model-specific knobs (e.g. TabR's context_size).
The complete list per model, with defaults and sizing notes, is in
docs/parameters.md:
clf = MasaClassifier(model="ft_transformer",
model_params={"n_blocks": 4, "d_block": 256})
# realmlp is the free-form MLP: hidden_sizes IS the architecture
# (length = depth, entries = per-layer width)
reg = MasaRegressor(model="realmlp",
model_params={"hidden_sizes": (512, 256, 128)})
Layer-by-layer width control (512 → 256 → 128) is a realmlp feature —
its hidden_sizes is the whole stack. The other architectures keep a
constant width per their papers (residual streams require it); size those
with d/d_token × n_blocks/n_layers.
Key parameters
Constructor parameters shared by both estimators (the full reference, including everything below plus preprocessing, ensembling, and hardware options, is docs/parameters.md):
| Parameter | Default | Meaning |
|---|---|---|
model |
"resnet" |
Architecture (see Models above). |
model_params |
None |
Architecture knobs, e.g. {"n_blocks": 5, "d": 384} — per-model tables in docs/parameters.md. |
objective |
None |
Training loss: task default, a built-in name ("huber", "quantile", ...), or a custom per-sample torch loss. |
eval_metric |
None |
Metric(s) on eval_set: built-in name, make_metric(...), or a NumPy callable; the first one drives early stopping. |
early_stopping_rounds |
None |
Patience in epochs; restores the best epoch's weights. |
n_epochs |
256 |
Maximum epochs. |
batch_size |
"auto" |
Full-batch ≤ 4096 rows, else minibatches of 1024. |
learning_rate |
1e-3 |
Optimizer learning rate. |
n_ens |
1 |
Seed-ensemble members (averaged predictions; multi-GPU aware). Per-member predictions: predict_members / predict_proba_members. |
class_weight |
None |
(classifier) "balanced" or a {label: weight} dict. |
device |
"auto" |
cuda > mps > cpu. |
random_state |
42 |
Seed; same seed ⇒ same model. |
RealMLP insights are composable options
The tricks from the RealMLP paper are estimator-level options usable with
any model (lnn included), not baked into one architecture:
numeric_scaler="rssc"— robust scale + smooth clip preprocessingcat_encoding="onehot"— RealMLP-style one-hot (binary → ±1, missing → 0)num_embedding="ple" | "pbld" | "plr" | "plr-lite" | "pl" | "periodic"— PLE-vB ("ple", the TabM† embedding) plus the Fourier/periodic embedding zoo (arXiv:2203.05556 + PBLD); token models (ft_transformer,tab_transformer) use the PLR family as feature tokenizers, but not PLEnum_embedding_cols=[...]/linear_skip_cols=[...](new in 0.9.1) — input routing: embed only these numeric columns and let the rest enter the first layer linearly, and/or send these numeric columns straight to the output through a zero-initialized linear skip (raw = trunk(x) + x_skip @ W_skip + b_skip, own param group atlinear_skip_lr_factor, no weight decay;realmlp). For numeric blocks that mix raw measurements with target-encoded log-odds columnsmodel_params={"num_scaling": True}— learnable per-feature input scalelr_scheduler="coslog4",optimizer_betas=(0.9, 0.95)— the training scheduleclip_predictions=True(regressor) — clip to the observed target rangen_ens=k— seed ensembling as in pytabkit's RealMLP: k members trained with seedsrandom_state + i, predictions averaged on the probability / value scale; works with every model including the retrieval ones.ens_mode="vectorized"trains all members in one vmapped forward/backward (torch.func) for BatchNorm-free models — pytabkit's speed trick- inner ensembling —
tabm(always),realm(always, new in 0.9.2) andft_transformer(k>1, new in 0.8.0) runkweight-shared members inside one model, composing with the outern_ens; then_ens·kmembers are exposed bypredict_members/predict_proba_members.tabmandft_transformeruse the TabM-mini adapter;tabmadditionally offersvariant="full", whilerealmuses full BatchEnsemble over the RealMLP trunk weight_decay_schedule="flat_cos"— RealMLP-TD's scheduled weight decay (param groups can opt out, e.g. biases)ema_decay=0.999— exponential moving average (Polyak averaging) of the weights; evaluation, early stopping, and the final model all use the averaged parameterscandidate_budget=N— bound the retrieval corpus oftabr/modernncawith a seeded, class-stratified subsample (keeps memory/compute in check on large data; no-op for other models)masamlp.realmlp_td_params(task)— the full RealMLP-TD recipe: parametric activations, flat_cos-scheduled dropout and weight decay, PBLD embeddings with their own lr factor, and hybrid categorical encoding (one-hot ≤ 9 categories, embeddings above)masamlp.realm_td_params(task, k=8)— the same recipe on therealmarchitecture: identical training knobs,kBatchEnsemble members instead of one model
from masamlp import MasaClassifier, realmlp_params
clf = MasaClassifier(**realmlp_params("classification")) # the TD-S recipe
clf = MasaClassifier(**{**realmlp_params("classification"),
"num_embedding": "pbld"}) # toward RealMLP-TD
Install
pip install masamlp # torch, numpy, pandas, scikit-learn
Quickstart
import numpy as np
from masamlp import MasaClassifier, make_metric
def f1(y_true, y_proba):
pred = y_proba >= 0.5
tp = np.sum(pred & (y_true == 1))
return 2 * tp / max(pred.sum() + (y_true == 1).sum(), 1)
clf = MasaClassifier(
model="resnet",
eval_metric=make_metric(f1, name="f1", minimize=False),
early_stopping_rounds=15,
class_weight="balanced",
)
clf.fit(X_train, y_train, sample_weight=w_train, eval_set=[(X_val, y_val)])
proba = clf.predict_proba(X_test)
print(clf.best_iteration_, clf.best_score_, clf.evals_result_["valid_0"]["f1"][:3])
Custom objective (regression, asymmetric loss):
import torch
from masamlp import MasaRegressor
def asymmetric_mse(y_true, raw_pred): # -> per-sample (n,) tensor
err = raw_pred - y_true # raw_pred: (n, out_dim)
return torch.where(err < 0, 4.0 * err**2, err**2).mean(dim=1)
reg = MasaRegressor(model="danet", objective=asymmetric_mse)
reg.fit(X, y, sample_weight=w) # weights just work
Save/load is a plain directory (manifest.json + tensors, loaded with
weights_only=True — no pickle execution):
reg.save_model("model_dir")
reg2 = MasaRegressor.load_model("model_dir")
Devices
device="auto" resolves tpu > cuda > mps > cpu. CUDA gets bf16 AMP by
default (per-model policies apply) and optional compile=True; MPS and CPU
train in float32. With multiple GPUs and n_ens > 1, ensemble members are
sharded across all GPUs and trained concurrently; opt out with
device="cuda:0".
TPU (experimental, 0.4.0/0.5.0): device="tpu" (or "xla") trains on
Cloud/Kaggle/Colab TPUs via torch_xla — bf16 by default; all ten 0.5.0
models verified on Kaggle v5e-8 and Colab v5e-1 (tabm, new in 0.6.0, has
XLA CI coverage but no TPU measurement yet). Kaggle grants TPU quota
separately from GPU quota, so this is extra free accelerator time for
competition workloads. 0.5.0 adds opt-in bf16 prediction (amp_predict)
and large-corpus TabR eval fusion (predict −44% at 345k rows on TPU).
Details, install pairing, tuning guidance, and measured numbers:
docs/devices.md.
Development
pip install -e ".[dev]"
bash scripts/check.sh # ruff + pytest + examples/quickstart.py
Development rules live in CLAUDE.md; roadmap in docs/roadmap.md.
License
MIT. Architecture attributions: docs/attribution.md.
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 masamlp-0.12.0.tar.gz.
File metadata
- Download URL: masamlp-0.12.0.tar.gz
- Upload date:
- Size: 711.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d296b49823c03d7ebd24d043010949a2d307cdcd189f73ad488d84719e8ce208
|
|
| MD5 |
e2854f71fcf260fcd193abb7a6755dbb
|
|
| BLAKE2b-256 |
796ed35c4aaf1428adc44e806612340f4574ad5cc67038bcb09bc026b9b75d66
|
Provenance
The following attestation bundles were made for masamlp-0.12.0.tar.gz:
Publisher:
publish.yml on Matapanino/masamlp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
masamlp-0.12.0.tar.gz -
Subject digest:
d296b49823c03d7ebd24d043010949a2d307cdcd189f73ad488d84719e8ce208 - Sigstore transparency entry: 2732614784
- Sigstore integration time:
-
Permalink:
Matapanino/masamlp@a4dde75a0d623cb2cb6aefcd350931af558234a1 -
Branch / Tag:
refs/tags/v0.12.0 - Owner: https://github.com/Matapanino
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a4dde75a0d623cb2cb6aefcd350931af558234a1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file masamlp-0.12.0-py3-none-any.whl.
File metadata
- Download URL: masamlp-0.12.0-py3-none-any.whl
- Upload date:
- Size: 122.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04a96e09aa0895c22ce46d10d46f14252c5604efa8c60af76cf05424c4eb5984
|
|
| MD5 |
06f4d71a8e9ceec36a80b438a1e173e3
|
|
| BLAKE2b-256 |
1301f55621d3cba4855e90f1ae974aba05c613f45ad9711093259e86589ff8c8
|
Provenance
The following attestation bundles were made for masamlp-0.12.0-py3-none-any.whl:
Publisher:
publish.yml on Matapanino/masamlp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
masamlp-0.12.0-py3-none-any.whl -
Subject digest:
04a96e09aa0895c22ce46d10d46f14252c5604efa8c60af76cf05424c4eb5984 - Sigstore transparency entry: 2732614837
- Sigstore integration time:
-
Permalink:
Matapanino/masamlp@a4dde75a0d623cb2cb6aefcd350931af558234a1 -
Branch / Tag:
refs/tags/v0.12.0 - Owner: https://github.com/Matapanino
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a4dde75a0d623cb2cb6aefcd350931af558234a1 -
Trigger Event:
push
-
Statement type: