Nums AI has released Causilo, a pretrained tabular foundation model for classification and regression. Causilo comes with a scikit-learn interface, Apache-2.0 code and pretrained weights on Hugging Face. On TabArena, it has the highest Elo among single models for both classification and regression.
Is it deployable? Yes, for research and evaluation today, on CUDA or CPU. Commercial, production and hosted API use need a separate license from Nums AI.
What Causilo Does
Causilo is an in-context learning model. Calling fit does not update the pretrained weights. It stores the training rows as context and predicts query rows in one forward pass. According to its TabArena submission, Nums AI pretrained Causilo only on synthetic data, with no TabArena datasets.
Inputs can be NumPy arrays or pandas DataFrames, including categorical features and missing values. Classification supports up to 10 classes. Regression returns mean predictions by default. Version 1.0.1 adds median and quantile outputs, based on 999 native quantiles.
Architecture: Refinement, Compression, In-Context Learning
Nums AI splits the network into 3 phases: refinement, compression and in-context learning. The released code and configs show how each phase works.
Features are grouped in sets of 3. Each value is embedded with 16 learned sine and cosine frequencies. Missing values get their own learned vector.
2 column stages summarize each feature group. In each, 128 latent slots read only the training rows and pass that summary to every row. Between the 2 column stages, a row stage lets feature groups interact through 4 latent tokens. It uses cross-attention instead of full self-attention, which Nums AI says keeps cost linear in feature count.
A pooling block then compresses each row into a fixed 512-dimensional vector. Labels are added to the training rows. A 12-layer prediction block lets query rows attend to those labeled rows. Query rows cannot change the training context or each other.
By default, 8 ensemble members share the same weights. Each one cycles through none, rank2gaussian, robust or power normalization, with seeded feature and class permutations.
TabArena Results
Nums AI used the official TabArena pipeline: 51 datasets and 816 Full splits, with 8 estimators and seed 42. A TabArena maintainer re-ran the full evaluation and got the same overall Elo of 1794.
| Task | Causilo Elo | Next best single model | Causilo improvability |
|---|---|---|---|
| Overall | 1792.9 | TabFM, 1764.4 | 0.0684 |
| Classification | 1771.8 | EXAONE Tabular, 1758.8 | 0.0875 |
| Regression | 2032.6 | TabFM, 1992.8 | 0.0125 |
The field includes Google Research’s TabFM, LG AI Research’s EXAONE Tabular and Prior Labs’ TabPFN-3 (1636.2 overall).
A few points help when reading these numbers:
- The #1 positions exclude system entries. With systems included, the maintainer re-run placed Causilo 3rd of 88 overall.
- On improvability, TabFM still leads overall and on classification. Causilo leads on regression.
- The Elo confidence intervals at the top overlap, so the lead over TabFM and EXAONE Tabular is narrow.
- Nums AI also lists Xiaomi-TabLDM and Amazon’s Mitra-v2 behind Causilo. Neither model appears in the benchmark files in Causilo’s repo.
ScoringBench Results
ScoringBench scores regression models with proper scoring rules such as CRPS, alongside RMSE and R². Nums AI submitted Causilo 1.0.1 on 101 datasets, 5 folds each, capped at 3,000 samples. Nums AI reports that Causilo ranks 1st by CRPS, R² and RMSE. The ScoringBench maintainer independently checked the results before committing them.
Speed and Memory
Nums AI also reran 3 models on 1 H100 80 GB GPU, with 8 CPU cores per job.
| Model | Fit (s per 1k rows) | Predict (s per 1k rows) | GPU memory (GiB) |
|---|---|---|---|
| Causilo | 2.504 | 0.251 | 8.15 |
| TabICLv2 | 3.449 | 0.303 | 8.37 |
| TabPFN-3 | 4.18 | 0.686 | 0.88 |
In this test, Causilo is fastest on both fit and predict. TabPFN-3 uses far less GPU memory. Setting use_kv_cache=True moves context work into fit, using more memory to speed up repeated predictions.
Getting Started
Causilo needs Python 3.10 to 3.12 and PyTorch 2.13 or newer. The first fit downloads the checkpoint automatically.
# pip install causilo
from causilo import CausiloClassifier, CausiloRegressor
clf = CausiloClassifier(n_estimators=8, random_state=42)
clf.fit(X_train, y_train)
proba = clf.predict_proba(X_test)
reg = CausiloRegressor()
reg.fit(X_train, y_train)
bands = reg.predict(X_test, output_type="quantiles", quantiles=[0.05, 0.5, 0.95])
You can also try the Hugging Face demo Space.
<section class="slide att" data-title="Who reads whom">
<h3>Query rows read the training rows, never each other</h3>
<p class="lede">In the prediction block, only labeled training rows supply attention keys and values. Tap a query row to trace its paths.</p>
<div class="ctrls">
<div class="range"><label for="tRows">Training rows</label><input type="range" id="tRows" min="3" max="9" value="6"><output id="tRowsOut">6</output></div>
<div class="seg" id="blockSeg"><button aria-pressed="false" data-v="1">Show blocked paths</button><button aria-pressed="true" data-v="0">Hide</button></div>
</div>
<svg id="attSvg" viewBox="0 0 700 360" role="img" aria-label="Attention paths from training rows to a query row"></svg>
<div class="reads">
<div class="read"><span>Paths into selected query, per layer</span><strong id="attPaths">6</strong></div>
<div class="read"><span>Prediction layers</span><strong>12</strong></div>
<div class="read"><span>Paths from other queries</span><strong>0</strong></div>
</div>
<p class="note"><strong>Why it matters:</strong> a prediction for one row cannot change because other test rows sit in the same batch. This also lets Causilo cache the training context once with <code>use_kv_cache=True</code>.</p>
</section>
<section class="slide" data-title="Wide tables">
<h3>Row mixing grows linearly with feature count</h3>
<p class="lede">Features are grouped in 3s. Inside each row, groups talk through 4 latent tokens instead of attending to every other group.</p>
<div class="ctrls">
<div class="range"><label for="feat">Features</label><input type="range" id="feat" min="3" max="600" step="3" value="60"><output id="featOut">60</output></div>
</div>
<div class="bars" id="scaleBars"></div>
<div class="reads">
<div class="read"><span>Feature groups</span><strong id="gOut">20</strong></div>
<div class="read"><span>Full self-attention pairs</span><strong id="fullOut">400</strong></div>
<div class="read"><span>Latent cross-attention pairs</span><strong id="latOut">192</strong></div>
<div class="read"><span>Ratio</span><strong id="ratioOut">2.1x</strong></div>
</div>
<p class="note"><strong>Illustrative:</strong> pair counts are derived from the code’s attention shapes for one row layer (groups plus 4 latents reading 4 latents, then 4 latents reading groups plus latents). They show growth, not measured speed.</p>
</section>
<section class="slide" data-title="Ensemble views">
<h3>1 model, several views of your table</h3>
<p class="lede">Each estimator reuses the same weights on a different view. Normalization cycles through 4 methods, and feature and class orders are permuted with a fixed seed.</p>
<div class="ctrls">
<div class="range"><label for="nEst">n_estimators</label><input type="range" id="nEst" min="1" max="16" value="8"><output id="nEstOut">8</output></div>
</div>
<div class="chips" id="chips"></div>
<div class="reads" id="normReads"></div>
<p class="note"><strong>Source:</strong> data/ensemble.py. Member 1 keeps the original feature order; later members use seeded affine permutations. Default is 8 estimators, seed 42. Order strips are illustrative.</p>
</section>
<section class="slide" data-title="TabArena">
<h3>Where Causilo lands on TabArena Full</h3>
<p class="lede">816 splits across 51 datasets. Switch tasks, metrics and whether multi-hour system entries are included.</p>
<div class="ctrls">
<div class="seg" id="taTask"><button aria-pressed="true" data-v="overall">Overall</button><button aria-pressed="false" data-v="cls">Classification</button><button aria-pressed="false" data-v="reg">Regression</button></div>
<div class="seg" id="taMetric"><button aria-pressed="true" data-v="elo">Elo</button><button aria-pressed="false" data-v="imp">Improvability</button></div>
<div class="seg" id="taSys"><button aria-pressed="true" data-v="0">Single models</button><button aria-pressed="false" data-v="1">Include systems</button></div>
</div>
<div class="bars" id="taBars"></div>
<div class="reads">
<div class="read"><span>Causilo rank on this view</span><strong id="taRank">#1</strong></div>
<div class="read"><span>Causilo score</span><strong id="taScore">1792.9</strong></div>
<div class="read"><span>Better is</span><strong id="taDir">Higher</strong></div>
</div>
<p class="note" id="taNote"></p>
</section>
<section class="slide" data-title="Speed and memory">
<h3>Fit and predict time on 1 H100</h3>
<p class="lede">Nums AI reran 3 models on the same H100 80 GB server with 8 physical CPU cores per job. Lower is better on every metric.</p>
<div class="ctrls">
<div class="seg" id="rsTask"><button aria-pressed="true" data-v="0">Overall</button><button aria-pressed="false" data-v="1">Classification</button><button aria-pressed="false" data-v="2">Regression</button></div>
<div class="seg" id="rsMetric"><button aria-pressed="true" data-v="0">Fit</button><button aria-pressed="false" data-v="1">Predict</button><button aria-pressed="false" data-v="2">CPU memory</button><button aria-pressed="false" data-v="3">GPU memory</button></div>
</div>
<div class="bars" id="rsBars"></div>
<p class="note" id="rsNote"></p>
</section>
<section class="slide curve" data-title="Intervals">
<h3>Regression gives you intervals, not only a mean</h3>
<p class="lede">Version 1.0.1 exposes 999 native quantiles. Pick a coverage level to see which quantiles to request.</p>
<div class="ctrls">
<div class="range"><label for="cov">Central coverage</label><input type="range" id="cov" min="0" max="12" step="1" value="4"><output id="covOut">90%</output></div>
</div>
<svg id="qSvg" viewBox="0 0 700 220" role="img" aria-label="Predictive distribution with shaded interval"></svg>
<code class="snip" id="qCode"></code>
<span class="flag" id="qFlag"></span>
<p class="note"><strong>Illustrative curve.</strong> Native levels run from 0.001 to 0.999 with linear interpolation. Beyond them, the package extrapolates exponential tails from the 2 outermost quantiles (docs/inference.md).</p>
</section>
<div class="nav">
<button class="pill" id="prev">Previous</button>
<span class="count" id="pos"></span>
<button class="pill solid" id="next">Next</button>
</div>
</main>
<footer class="foot">
<span>Data: <a href="https://github.com/nums-ai/causilo" target="_blank" rel="noopener">nums-ai/causilo</a> benchmark files and <a href="https://huggingface.co/nums-ai/causilo" target="_blank" rel="noopener">model card</a>, checked Sep 15, 2026</span>
<span class="mtp">Built by Marktechpost</span>
</footer>
</div>
<script>
(function(){
var $ = function(id){ return document.getElementById(id); };
var reduce = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
/* ———- auto resize for WordPress iframe ———- */
function postH(){
var h = document.getElementById("cx").offsetHeight + 40;
try{ parent.postMessage({__mtpH:h, __cx:"causilo"}, "*"); }catch(e){}
}
window.addEventListener("load", postH);
window.addEventListener("resize", postH);
if (window.ResizeObserver){ new ResizeObserver(postH).observe(document.getElementById("cx")); }
/* ———- slides ———- */
var slides = [].slice.call(document.querySelectorAll(".slide"));
var steps = $("steps"), cur = 0;
slides.forEach(function(s, i){
var b = document.createElement("button");
b.className = "step"; b.setAttribute("role","tab");
b.innerHTML = "<b>" + (i+1) + "</b>" + s.getAttribute("data-title");
b.addEventListener("click", function(){ go(i); });
steps.appendChild(b);
});
var hooks = {};
function go(i){
cur = Math.max(0, Math.min(slides.length-1, i));
slides.forEach(function(s, k){ s.classList.toggle("on", k===cur); });
[].forEach.call(steps.children, function(b, k){ b.setAttribute("aria-selected", k===cur ? "true" : "false"); if(k===cur && b.scrollIntoView){ b.scrollIntoView({block:"nearest", inline:"nearest"}); } });
$("prev").disabled = cur===0; $("next").disabled = cur===slides.length-1;
$("pos").textContent = (cur+1) + " of " + slides.length;
if (cur===1) drawAtt(); if (cur===6) drawQ(); if (hooks[cur]) hooks[cur]();
setTimeout(postH, 60);
}
$("prev").onclick = function(){ go(cur-1); };
$("next").onclick = function(){ go(cur+1); };
document.addEventListener("keydown", function(e){
if (e.target && e.target.tagName === "INPUT") return;
if (e.key === "ArrowRight") go(cur+1);
if (e.key === "ArrowLeft") go(cur-1);
});
function seg(id, cb){
var el = $(id);
[].forEach.call(el.children, function(b){
b.addEventListener("click", function(){
[].forEach.call(el.children, function(x){ x.setAttribute("aria-pressed", x===b ? "true" : "false"); });
cb(b.getAttribute("data-v"));
});
});
return function(){ var p = el.querySelector(‘[aria-pressed="true"]’); return p ? p.getAttribute("data-v") : null; };
}
function fmt(n){ return n.toLocaleString("en-US"); }
/* ———- 1. pipeline ———- */
var ST = [
{g:"Refinement", n:"Embed features", d:"groups of 3", t:"Features are grouped in 3s. Each value becomes 16 learned sine and cosine frequencies, projected to width 128. Missing values get their own learned vector instead of an imputed number.", s:"Training rows also receive a label embedding at this point.", r:[["Group size","3"],["Frequencies","16"],["Width","128"]], v:"embed"},
{g:"Refinement", n:"Column context", d:"3 layers", t:"For every feature group, 128 latent slots read down the training rows and build a summary. That summary is broadcast back to every row, including the query rows.", s:"Only the training prefix feeds the latents.", r:[["Layers","3"],["Latent slots","128"],["Heads","4"]], v:"column"},
{g:"Refinement", n:"Row mixing", d:"3 layers", t:"Inside each row, feature groups exchange information through 4 latent tokens using cross-attention. There is no full self-attention across features.", s:"Nums AI says this keeps cost linear in feature count.", r:[["Layers","3"],["Row latents","4"],["Heads","8"]], v:"row"},
{g:"Refinement", n:"Column context", d:"3 layers", t:"A second column stage refreshes each group’s training summary after row mixing, so column statistics now reflect cross-feature interactions.", s:"Same structure as the first column stage.", r:[["Layers","3"],["Latent slots","128"],["Heads","4"]], v:"column"},
{g:"Compression", n:"Row pool", d:"to 512 numbers", t:"4 latents read all feature groups in a row and are flattened into 1 fixed vector. A 5 column table and a 500 column table both become 512 numbers per row.", s:"4 latents times width 128 equals 512.", r:[["Layers","3"],["Latents","4"],["Row vector","512"]], v:"pool"},
{g:"In-context learning", n:"Prediction", d:"12 layers", t:"Labels are added to the pooled training rows. Query rows then attend to those labeled rows across 12 layers, which is where in-context learning happens.", s:"Queries read the context but never write to it.", r:[["Layers","12"],["Heads","4"],["Width","512"]], v:"icl"},
{g:"In-context learning", n:"Output head", d:"logits or quantiles", t:"The classifier head emits 10 class logits, which is why classification tops out at 10 classes. Regression predictions expose 999 native quantiles for mean, median or intervals.", s:"Heads run in FP32. CUDA uses FP16 mixed precision elsewhere.", r:[["Classes","10 max"],["Quantiles","999"],["Default members","8"]], v:"head"}
];
var pipe = $("pipe"), pIdx = 0, playing = !reduce, timer = null;
ST.forEach(function(s, i){
var b = document.createElement("button");
b.className = "node";
b.innerHTML = ‘<span class="grp">’ + s.g + ‘</span><span class="nm">’ + s.n + ‘</span><span class="dp">’ + s.d + ‘</span>’;
b.addEventListener("click", function(){ setPlay(false); showStage(i); });
pipe.appendChild(b);
});
var NS = "http://www.w3.org/2000/svg";
function el(tag, attrs, parent){ var e = document.createElementNS(NS, tag); for (var k in attrs) e.setAttribute(k, attrs[k]); if (parent) parent.appendChild(e); return e; }
function drawViz(kind){
var svg = $("pipeViz"); svg.innerHTML = "";
var ink = "#12151c", soft = "#d5dae2", faint = "#98a0ac";
var cells = [];
if (kind === "embed"){
for (var r=0;r<5;r++) for (var c=0;c<9;c++){
var miss = (r===1&&c===4)||(r===3&&c===7);
var x = 30 + c*22, y = 22 + r*22;
var e = el("rect",{x:x,y:y,width:16,height:16,rx:3,fill: miss ? "#fff" : soft, stroke: miss ? faint : "none","stroke-dasharray":"3 2",class:"cell"},svg);
cells.push([e,c,miss]);
}
for (var g=0; g<3; g++) el("rect",{x:28+g*66,y:16,width:62,height:118,rx:6,fill:"none",stroke:ink,"stroke-width":1.2,opacity:0,class:"cell grpbox"},svg);
el("text",{x:250,y:80,"font-size":12,fill:faint},svg).textContent = "3 per group";
setTimeout(function(){
[].forEach.call(svg.querySelectorAll(".grpbox"), function(b){ b.setAttribute("opacity",1); });
cells.forEach(function(p){ if(!p[2]) p[0].setAttribute("fill", ["#12151c","#5a616e","#98a0ac"][p[1]%3]); else p[0].setAttribute("stroke", ink); });
}, 80);
} else if (kind === "column"){
for (var r2=0;r2<6;r2++){
var q = r2>=4;
el("rect",{x:40,y:14+r2*21,width:120,height:15,rx:3,fill: q ? "#fff" : soft, stroke: q ? faint : "none"},svg);
}
el("rect",{x:40,y:10,width:24,height:128,rx:4,fill:"none",stroke:ink,"stroke-width":1.4},svg);
for (var l=0;l<4;l++){
var cc = el("circle",{cx:240,cy:30+l*30,r:7,fill:ink,opacity:.15,class:"cell"},svg);
(function(n,d){ setTimeout(function(){ n.setAttribute("opacity",1); }, 120+d*120); })(cc,l);
for (var t=0;t<4;t++) el("path",{d:"M64 "+(21+t*21)+" C150 "+(21+t*21)+" 160 "+(30+l*30)+" 233 "+(30+l*30),stroke:ink,"stroke-width":.6,fill:"none",opacity:.25},svg);
}
el("text",{x:180,y:146,"font-size":11,fill:faint},svg).textContent = "training rows write, queries read";
} else if (kind === "row"){
var gx=[40,78,116,154,192,230,268];
gx.forEach(function(x){ el("rect",{x:x,y:100,width:28,height:22,rx:4,fill:soft},svg); });
for (var k=0;k<4;k++){
var cx2 = 98 + k*42;
var lat = el("circle",{cx:cx2,cy:40,r:9,fill:ink,class:"cell",opacity:.2},svg);
(function(n,d){ setTimeout(function(){ n.setAttribute("opacity",1); }, 100+d*110); })(lat,k);
gx.forEach(function(x){ el("line",{x1:cx2,y1:49,x2:x+14,y2:100,stroke:ink,"stroke-width":.6,opacity:.28},svg); });
}
el("text",{x:40,y:142,"font-size":11,fill:faint},svg).textContent = "groups connect only through 4 latents";
} else if (kind === "pool"){
for (var i2=0;i2<10;i2++){
var bx = el("rect",{x:20+i2*16,y:40+(i2%3)*24,width:12,height:12,rx:2,fill:soft,class:"cell"},svg);
(function(n,d){ setTimeout(function(){ n.setAttribute("x", 214 + (d%4)*20); n.setAttribute("y", 64); n.setAttribute("fill","#12151c"); n.setAttribute("width",14); n.setAttribute("height",22); }, 150+d*50); })(bx,i2);
}
el("text",{x:200,y:118,"font-size":12,fill:faint},svg).textContent = "4 x 128 = 512";
} else if (kind === "icl"){
for (var r3=0;r3<5;r3++){
el("rect",{x:30,y:18+r3*22,width:110,height:15,rx:3,fill:soft},svg);
el("rect",{x:144,y:18+r3*22,width:16,height:15,rx:3,fill:ink},svg);
}
for (var q2=0;q2<2;q2++) el("rect",{x:220,y:40+q2*40,width:80,height:15,rx:3,fill:"#fff",stroke:ink},svg);
for (var r4=0;r4<5;r4++){
var p = el("path",{d:"M160 "+(25+r4*22)+" C190 "+(25+r4*22)+" 190 47 220 47",stroke:ink,"stroke-width":1,fill:"none","stroke-dasharray":"120","stroke-dashoffset":"120"},svg);
(function(n,d){ setTimeout(function(){ n.style.transition="stroke-dashoffset .7s ease"; n.setAttribute("stroke-dashoffset","0"); }, 80+d*90); })(p,r4);
}
el("text",{x:30,y:140,"font-size":11,fill:faint},svg).textContent = "labels ride on training rows";
} else {
var vals=[.12,.46,.08,.22,.05,.03,.02,.01,.005,.005];
vals.forEach(function(v,i3){
var h = 8 + v*210;
var bar = el("rect",{x:36+i3*26,y:130,width:18,height:0,rx:2,fill: i3===1 ? ink : soft,class:"cell"},svg);
setTimeout(function(){ bar.setAttribute("y",130-h); bar.setAttribute("height",h); }, 80+i3*40);
});
el("text",{x:36,y:146,"font-size":11,fill:faint},svg).textContent = "10 class logits (illustrative values)";
}
}
function showStage(i){
pIdx = i;
[].forEach.call(pipe.children, function(b,k){ b.classList.toggle("on", k===i); });
$("pipeBar").style.width = ((i+1)/ST.length*100) + "%";
$("pipeCount").textContent = "Stage " + (i+1) + " of " + ST.length + ": " + ST[i].g;
$("pipeText").innerHTML = ST[i].t + "<small>" + ST[i].s + "</small>";
$("pipeReads").innerHTML = ST[i].r.map(function(x){ return ‘<div class="read"><span>’+x[0]+'</span><strong>’+x[1]+'</strong></div>’; }).join("");
drawViz(ST[i].v);
}
function setPlay(on){
playing = on; $("play").textContent = on ? "Pause" : "Play";
clearInterval(timer);
if (on) timer = setInterval(function(){ if (cur===0) showStage((pIdx+1)%ST.length); }, 2600);
}
$("play").onclick = function(){ setPlay(!playing); };
showStage(0); setPlay(playing);
/* ———- 2. attention ———- */
var sel = 0, showBlocked = false;
var getBlk = seg("blockSeg", function(v){ showBlocked = v==="1"; drawAtt(); });
function drawAtt(){
var T = +$("tRows").value, Q = 3, svg = $("attSvg"), narrow = svg.getBoundingClientRect().width < 520;
var NC = narrow ? 3 : 5, CW = 38, W = narrow ? 470 : 700, FS = narrow ? 20 : 14, QX = narrow ? 290 : 450;
$("tRowsOut").textContent = T; $("attPaths").textContent = T;
svg.innerHTML = "";
var rowH = narrow ? 40 : 34, topT = narrow ? 50 : 40, H = topT + T*rowH + 16;
svg.setAttribute("viewBox","0 0 " + W + " " + H);
el("text",{x:16,y:FS+8,"font-size":FS,fill:"#5a616e"},svg).textContent = narrow ? "Training" : "Training rows (labeled)";
el("text",{x:QX,y:FS+8,"font-size":FS,fill:"#5a616e"},svg).textContent = narrow ? "Queries (tap)" : "Query rows (tap one)";
var tY = [];
for (var i=0;i<T;i++){
var y = topT + i*rowH;
tY.push(y+12);
var g = el("g",{class:"row"},svg);
for (var c=0;c<NC;c++) el("rect",{x:16+c*CW,y:y,width:32,height:26,rx:4,fill:"#eef1f6"},g);
var LX = 16+NC*CW;
el("rect",{x:LX,y:y,width:32,height:26,rx:4,fill:"#12151c"},g);
el("text",{x:LX+16,y:y+18,"font-size":narrow?16:12,fill:"#f5f7fa","text-anchor":"middle"},g).textContent = ["A","B","A","C","B","A","C","B","A"][i];
}
var span = T*rowH, qY = [];
for (var j=0;j<Q;j++){
var yq = topT + (span/(Q+1))*(j+1) – 12;
qY.push(yq+12);
var gq = el("g",{class:"row q",tabindex:0,role:"button","aria-label":"Query row "+(j+1)},svg);
for (var c2=0;c2<NC;c2++) el("rect",{x:QX+c2*CW,y:yq,width:32,height:26,rx:4,fill: j===sel ? "#12151c" : "#fff",stroke:"#12151c","stroke-width":1},gq);
el("text",{x:QX+NC*CW+10,y:yq+18,"font-size":narrow?18:13,fill:"#12151c","text-anchor":"middle"},gq).textContent = "?";
(function(k){ gq.addEventListener("click", function(){ sel=k; drawAtt(); }); gq.addEventListener("keydown", function(e){ if(e.key==="Enter"||e.key===" "){ e.preventDefault(); sel=k; drawAtt(); } }); })(j);
}
tY.forEach(function(y, k){
var sx = 16+NC*CW+34, mx = (sx+QX)/2;
var p = el("path",{class:"ln",d:"M"+sx+" "+y+" C"+mx+" "+y+" "+mx+" "+qY[sel]+" "+(QX-2)+" "+qY[sel]},svg);
p.style.animationDelay = (reduce ? 0 : k*0.06) + "s";
});
if (showBlocked){
qY.forEach(function(y, k){
if (k===sel) return;
var ex = QX+NC*CW+22, x = W-4, midY = (y + qY[sel])/2;
el("path",{class:"bl",d:"M"+ex+" "+y+" C"+(x)+" "+y+" "+(x)+" "+qY[sel]+" "+ex+" "+qY[sel]},svg);
var gx = el("g",{},svg);
el("circle",{cx:x-12,cy:midY,r:9,fill:"#fff",stroke:"#98a0ac"},gx);
el("path",{d:"M"+(x-16)+" "+(midY-4)+" l8 8 M"+(x-8)+" "+(midY-4)+" l-8 8",stroke:"#5a616e","stroke-width":1.4},gx);
});
}
postH();
}
$("tRows").addEventListener("input", drawAtt);
window.addEventListener("resize", function(){ clearTimeout(window.__att); window.__att = setTimeout(drawAtt, 150); });
drawAtt();
/* ———- 3. scaling ———- */
function drawScale(){
var F = +$("feat").value, G = Math.ceil(F/3);
var full = G*G, lat = 8*(G+4);
var fullMax = Math.max(full, lat);
$("featOut").textContent = F; $("gOut").textContent = fmt(G);
$("fullOut").textContent = fmt(full); $("latOut").textContent = fmt(lat);
$("ratioOut").textContent = (full/lat >= 10 ? Math.round(full/lat) : (full/lat).toFixed(1)) + "x";
var rows = [["Full self-attention", full, false],["Causilo latents", lat, true]];
$("scaleBars").innerHTML = rows.map(function(r){
return ‘<div class="bar’+(r[2]?" me":"")+’"><span class="lb">’+r[0]+'</span><div class="tk"><div class="fl" data-w="’+Math.max(0.6, r[1]/fullMax*100)+’"></div></div><span class="vl">’+fmt(r[1])+'</span></div>’;
}).join("");
requestAnimationFrame(function(){ [].forEach.call($("scaleBars").querySelectorAll(".fl"), function(f){ f.style.width = f.getAttribute("data-w") + "%"; }); });
}
$("feat").addEventListener("input", drawScale);
drawScale();
/* ———- 4. ensemble ———- */
var METHODS = ["none","rank2gaussian","robust","power"];
function drawEns(){
var n = +$("nEst").value; $("nEstOut").textContent = n;
var counts = {none:0, rank2gaussian:0, robust:0, power:0};
var html = "";
for (var i=0;i<n;i++){
var m = n===1 ? "none" : METHODS[i%4]; counts[m]++;
var order = "";
for (var k=0;k<8;k++){
var on = i===0 ? (k<4) : (((k*(2*((i%3)+1)+1)) + i) % 8) < 4;
order += ‘<i class="’+(on?"k":"")+’"></i>’;
}
html += ‘<div class="chip" style="animation-delay:’+(reduce?0:i*0.03)+’s"><span>Member ‘+(i+1)+(i===0?" (original order)":" (permuted)")+'</span><strong>’+m+'</strong><em>’+order+'</em></div>’;
}
$("chips").innerHTML = html;
$("normReads").innerHTML = METHODS.map(function(m){ return ‘<div class="read"><span>’+m+'</span><strong>’+counts[m]+'</strong></div>’; }).join("");
}
$("nEst").addEventListener("input", drawEns);
drawEns();
/* ———- 5. TabArena ———- */
var TA = {
"0": {
overall:{rankE:1, rankI:2, rows:[["Causilo",1792.9,89.3,55.7,.0684],["TabFM (Google Research)",1764.4,110.1,101.5,.0397],["EXAONE Tabular (LG)",1755.5,78.5,53.1,.0743],["TabPFN-3",1636.2,71.3,52.3,.0962],["TabPFN-2.6",1588.2,65.9,44.6,.1096]]},
cls:{rankE:1, rankI:2, rows:[["Causilo",1771.8,103.1,72.5,.0875],["EXAONE Tabular (LG)",1758.8,86.7,61.2,.0887],["TabFM (Google Research)",1745.5,128.0,114.7,.0460],["TabPFN-3",1631.7,82.4,66.9,.1193],["TabPFN-2.6",1583.0,62.2,57.9,.1317]]},
reg:{rankE:1, rankI:1, rows:[["Causilo",2032.6,225.7,131.7,.0125],["TabFM (Google Research)",1992.8,161.4,104.6,.0212],["EXAONE Tabular (LG)",1882.1,151.0,103.0,.0322],["TabPFN-3",1783.0,232.2,128.1,.0289],["Nori-30M",1751.7,117.6,80.5,.0390]]}
},
"1": {
overall:{rankE:3, rankI:4, rows:[["TabFM+ (4h ensemble)",1815.6,104.7,80.2,.0484],["AutoGluon 1.6 (4h)",1794.1,104.3,59.6,.0732],["Causilo",1794.0,90.7,57.5,.0762],["TabFM (Google Research)",1771.7,102.4,96.1,.0517],["EXAONE Tabular (LG)",1752.7,73.2,54.1,.0823]]},
cls:{rankE:2, rankI:4, rows:[["TabFM+ (4h ensemble)",1791.5,116.5,85.5,.0605],["Causilo",1771.4,96.5,73.7,.0970],["AutoGluon 1.6 (4h)",1765.7,86.9,55.9,.0924],["EXAONE Tabular (LG)",1757.2,79.7,59.5,.0985],["TabFM (Google Research)",1755.6,120.8,112.6,.0611]]},
reg:{rankE:3, rankI:2, rows:[["TabFM+ (4h ensemble)",2076.8,195.9,144.5,.0128],["AutoGluon 1.6 (4h)",2075.7,212.7,151.6,.0170],["Causilo",2042.1,242.7,137.5,.0154],["AutoGluon 1.6 extreme (4h)",2016.0,175.3,113.3,.0218],["TabFM (Google Research)",1988.1,168.9,97.2,.0240]]}
}
};
var taState = {task:"overall", metric:"elo", sys:"0"};
seg("taTask", function(v){ taState.task=v; drawTA(); });
seg("taMetric", function(v){ taState.metric=v; drawTA(); });
seg("taSys", function(v){ taState.sys=v; drawTA(); });
function drawTA(){
var d = TA[taState.sys][taState.task], elo = taState.metric==="elo";
var rows = d.rows.slice().sort(function(a,b){ return elo ? b[1]-a[1] : a[4]-b[4]; });
var lo, hi;
if (elo){ lo = Math.min.apply(null, rows.map(function(r){return r[1]-r[3];})) – 40; hi = Math.max.apply(null, rows.map(function(r){return r[1]+r[2];})) + 10; }
else { lo = 0; hi = Math.max.apply(null, rows.map(function(r){return r[4];})) * 1.08; }
var pct = function(v){ return Math.max(1,(v-lo)/(hi-lo)*100); };
$("taBars").innerHTML = rows.map(function(r){
var me = r[0]==="Causilo";
var val = elo ? r[1].toFixed(1) : r[4].toFixed(4);
var ci = elo ? ‘<div class="ci" data-l="’+pct(r[1]-r[3])+’" data-w="’+(pct(r[1]+r[2])-pct(r[1]-r[3]))+’" style="left:0;width:0"></div>’ : "";
return ‘<div class="bar’+(me?" me":"")+’"><span class="lb" title="’+r[0]+’">’+r[0]+'</span><div class="tk"><div class="fl" data-w="’+pct(elo?r[1]:r[4])+’"></div>’+ci+'</div><span class="vl">’+val+'</span></div>’;
}).join("");
requestAnimationFrame(function(){
[].forEach.call($("taBars").querySelectorAll(".fl"), function(f){ f.style.width = f.getAttribute("data-w")+"%"; });
[].forEach.call($("taBars").querySelectorAll(".ci"), function(c){ c.style.left = c.getAttribute("data-l")+"%"; c.style.width = c.getAttribute("data-w")+"%"; });
});
var me = d.rows.filter(function(r){return r[0]==="Causilo";})[0];
$("taRank").textContent = "#" + (elo ? d.rankE : d.rankI);
$("taScore").textContent = elo ? me[1].toFixed(1) : me[4].toFixed(4);
$("taDir").textContent = elo ? "Higher" : "Lower";
var n = elo
? "<strong>Elo</strong> with bootstrap confidence whiskers. Overlapping whiskers mean the top of the board is close. Bar axis starts above zero."
: "<strong>Improvability</strong> is the average gap to the best method per dataset. Lower is better. TabFM leads here overall and on classification.";
n += taState.sys==="1" ? " System entries are multi-hour ensembles or AutoML portfolios, not single models." : " System methods excluded, as in Causilo’s README.";
n += " Top 5 rows shown; rank is the official position in the full table.";
$("taNote").innerHTML = n;
postH();
}
drawTA();
/* ———- 6. resources ———- */
var RS = [
[["Causilo",2.504,0.251,1.94,8.15],["TabICLv2",3.449,0.303,2.00,8.37],["TabPFN-3",4.18,0.686,2.87,0.88]],
[["Causilo",2.568,0.272,1.95,8.36],["TabICLv2",3.51,0.335,2.00,8.96],["TabPFN-3",4.185,0.703,2.90,0.81]],
[["Causilo",1.682,0.212,1.92,7.54],["TabICLv2",1.909,0.216,1.99,6.64],["TabPFN-3",3.19,0.498,2.81,1.07]]
];
var rs = {task:0, m:0}, UNITS = [" s"," s"," GiB"," GiB"], LBL = ["Median fit seconds per 1,000 rows","Median predict seconds per 1,000 rows","Mean peak CPU memory during fit","Mean peak GPU memory during fit"];
seg("rsTask", function(v){ rs.task=+v; drawRS(); });
seg("rsMetric", function(v){ rs.m=+v; drawRS(); });
function drawRS(){
var rows = RS[rs.task], k = rs.m + 1;
var mx = Math.max.apply(null, rows.map(function(r){return r[k];})) * 1.05;
$("rsBars").innerHTML = rows.map(function(r){
return ‘<div class="bar’+(r[0]==="Causilo"?" me":"")+’"><span class="lb">’+r[0]+'</span><div class="tk"><div class="fl" data-w="’+(r[k]/mx*100)+’"></div></div><span class="vl">’+r[k]+UNITS[rs.m]+'</span></div>’;
}).join("");
requestAnimationFrame(function(){ [].forEach.call($("rsBars").querySelectorAll(".fl"), function(f){ f.style.width = f.getAttribute("data-w")+"%"; }); });
var best = rows.slice().sort(function(a,b){return a[k]-b[k];})[0][0];
$("rsNote").innerHTML = "<strong>" + LBL[rs.m] + ".</strong> Lowest on this view: " + best + ". These are Nums AI’s local reruns, not TabArena’s official timings.";
}
drawRS();
/* ———- 7. quantiles ———- */
var COV = [50,60,70,80,90,95,98,99,99.5,99.8,99.9,99.95,99.98];
function covFromSlider(v){ return COV[v]/100; }
function pdf(x){ return Math.exp(-0.5*x*x); }
function invNorm(p){ // Acklam approximation
var a=[-39.69683028665376,220.9460984245205,-275.9285104469687,138.3577518672690,-30.66479806614716,2.506628277459239],
b=[-54.47609879822406,161.5858368580409,-155.6989798598866,66.80131188771972,-13.28068155288572],
c=[-0.007784894002430293,-0.3223964580411365,-2.400758277161838,-2.549732539343734,4.374664141464968,2.938163982698783],
d=[0.007784695709041462,0.3224671290700398,2.445134137142996,3.754408661907416], q, r;
if (p<0.02425){ q=Math.sqrt(-2*Math.log(p)); return (((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5])/((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1); }
if (p>1-0.02425){ q=Math.sqrt(-2*Math.log(1-p)); return -(((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5])/((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1); }
q=p-0.5; r=q*q; return (((((a[0]*r+a[1])*r+a[2])*r+a[3])*r+a[4])*r+a[5])*q/(((((b[0]*r+b[1])*r+b[2])*r+b[3])*r+b[4])*r+1);
}
function trim(n){ return String(parseFloat(n.toFixed(5))); }
function drawQ(){
var cov = covFromSlider(+$("cov").value), lo = Math.round((1-cov)/2*1e5)/1e5, hi = Math.round((1-lo)*1e5)/1e5;
var qn = $("qSvg").getBoundingClientRect().width < 520, qf = qn ? 26 : 12, qb = qn ? 28 : 13;
$("covOut").textContent = COV[+$("cov").value] + "%";
var svg = $("qSvg"); svg.innerHTML = "";
var X = function(z){ return 350 + z*80; }, Y = function(z){ return 180 – pdf(z)*150; };
var zl = invNorm(lo), zh = invNorm(hi), d = "M" + X(zl) + " 180", z;
for (z = zl; z <= zh; z += 0.05) d += " L" + X(z).toFixed(1) + " " + Y(z).toFixed(1);
d += " L" + X(zh) + " " + Y(zh) + " L" + X(zh) + " 180 Z";
var area = el("path",{d:d,fill:"#12151c",opacity:.12},svg);
var line = "M" + X(-4.3) + " " + Y(-4.3);
for (z = -4.3; z <= 4.3; z += 0.05) line += " L" + X(z).toFixed(1) + " " + Y(z).toFixed(1);
el("path",{d:line,fill:"none",stroke:"#12151c","stroke-width":2},svg);
el("line",{x1:20,y1:180,x2:680,y2:180,stroke:"rgba(18,21,28,.2)"},svg);
var nat = [invNorm(0.001), invNorm(0.999)];
nat.forEach(function(zz){ el("line",{x1:X(zz),y1:30,x2:X(zz),y2:180,stroke:"#98a0ac","stroke-dasharray":"3 4"},svg); });
el("text",{x:X(nat[1])+6,y:44,"font-size":qf,fill:"#98a0ac"},svg).textContent = "0.999";
el("text",{x:X(nat[0])-6,y:44,"font-size":qf,fill:"#98a0ac","text-anchor":"end"},svg).textContent = "0.001";
[[zl,trim(lo)],[zh,trim(hi)]].forEach(function(p, i){
el("line",{x1:X(p[0]),y1:Y(p[0])-4,x2:X(p[0]),y2:196,stroke:"#12151c","stroke-width":1.5},svg);
el("text",{x:X(p[0]),y:214,"font-size":qb,fill:"#12151c","text-anchor":"middle","font-weight":600},svg).textContent = "q=" + p[1];
});
el("line",{x1:X(0),y1:30,x2:X(0),y2:180,stroke:"#12151c","stroke-dasharray":"2 3",opacity:.5},svg);
el("text",{x:X(0),y:22,"font-size":qf,fill:"#5a616e","text-anchor":"middle"},svg).textContent = "median 0.5";
if (!reduce){ area.style.transition = "opacity .4s"; }
$("qCode").textContent = ‘regressor.predict(n X_test, output_type="quantiles",n quantiles=[‘ + trim(lo) + ‘, 0.5, ‘ + trim(hi) + ‘]n)’;
var outside = lo < 0.001;
$("qFlag").className = "flag" + (outside ? " warn" : "");
$("qFlag").textContent = outside ? "Outside native levels: exponential tail extrapolation applies" : "Inside native levels: linear interpolation between quantiles";
}
$("cov").addEventListener("input", drawQ);
window.addEventListener("resize", function(){ clearTimeout(window.__q); window.__q = setTimeout(drawQ, 150); });
drawQ();
go(0);
})();
</script>
</body>
</html>
” style=”width:100%;border:0;height:600px;display:block;overflow:hidden” loading=”lazy” title=”Causilo, explained: interactive explainer”>
Key Takeaways
- Causilo has the top TabArena Elo among single models, overall and per task.
- With system ensembles included, a maintainer re-run places it 3rd of 88.
- Row mixing goes through 4 latent tokens, keeping cost linear in feature count.
- The code is Apache-2.0; the weights are research-only without a commercial license.
- Version 1.0.1 adds quantile outputs, so regression intervals work out of the box.
Check out the Repo on GitHub and Model on HF. All credit goes to the researcher of this project. Also, feel free to follow us on Twitter and don’t forget to join our 150k+ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.
Need to partner with us for promoting your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar etc.? Connect with us
The post Nums AI Releases Causilo: A Tabular Foundation Model That Tops TabArena Among Single Models appeared first on MarkTechPost.