Nori-Causal

Nori-Causal is a ~30M-parameter (30,342,598) model that reads a single observational table and returns, for every ordered pair of columns, the probability of a direct causal edge between them. It is zero-shot: one forward pass per table, with no per-dataset fitting. It is trained entirely on synthetic data (simulated structural causal models).

In synthefy-nori it powers the causal view of NoriInterpreter: next to each feature's importance for predicting the target, it reports P(feature β†’ target) and P(target β†’ feature), so an important feature that is more likely an effect (a proxy) of the target than a cause is visible.

Architecture

Each cell is embedded with the Nori input layer (RBF numeric embedding, two values per token, a regression target encoder). Six blocks alternate attention across rows and across columns; the rows are then pooled (mean and standard deviation per column), fifteen blocks of attention run across the columns, and a bilinear edge head scores every ordered pair. One column can sit in the target slot, which the model reads as the variable of interest; with no target, every column is an ordinary node. Tables longer than 2,048 rows are evenly subsampled.

Up to 25 features, the table is read in one target-aware pass. Wider tables are read as random 30-column subsets with the target in the target slot of every subset that contains it, plus extra subsets until every feature has been read with the target at least 3 times; each pair's score is averaged over the subsets that contain it.

Usage

pip install "synthefy-nori[interpretability]>=X.Y.Z"

Through the interpreter (regression targets):

from sklearn.datasets import load_diabetes
from synthefy_nori.interpretability.glassbox import NoriInterpreter

data = load_diabetes()
interp = NoriInterpreter(causal=True).fit(data.data, data.target, feature_names=list(data.feature_names))
interp.causal_ranking_       # per feature: p_cause, p_effect, target_coverage, importance
interp.causal_adjacency_     # (d+1, d+1) edge probabilities; the target is the last node

On its own, with or without a target:

from synthefy_nori.causal import NoriCausal

causal = NoriCausal().fit(X, y)   # downloads these weights from the Hub on first use; y is optional
causal.adjacency_                 # [i, j] = P(node i -> node j)

It uses a GPU when one is available and falls back to CPU. To run from a local copy of this checkpoint, pass NoriCausal(checkpoint="path/to/noricausal_31m.pt") (or NoriInterpreter(causal_checkpoint=...)), or set SYNTHEFY_NORICAUSAL_31M_CHECKPOINT.

Intended use & limitations

  • Intended for ranking candidate causes and effects of a target in a tabular dataset, and for screening features whose importance may come from being a consequence of the target.
  • Probabilities, not a graph. The output is edge probabilities; no cutoff is applied by default. A cutoff calibrated on synthetic graphs over- or under-shoots on real tables, so a decided graph is not part of this release.
  • Regression targets only in NoriInterpreter: class labels are not numeric values, and the training targets were almost always continuous.
  • Observational data, no guarantees. Edge direction is inferred from distributional patterns learned on synthetic SCMs; hidden confounders, near-duplicate (collinear) columns and deterministic relationships can mislead it. Treat the scores as evidence to check, not as causal conclusions.
  • Trained entirely on synthetic data; no benchmark data is used in training.

License

Apache-2.0. See LICENSE and NOTICE.

Downloads last month
27
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support