<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohamed Bal</title>
    <description>The latest articles on DEV Community by Mohamed Bal (@mohamed_bal).</description>
    <link>https://dev.to/mohamed_bal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4011272%2F618b30ac-4729-447b-a220-33a42e9a1c46.jpeg</url>
      <title>DEV Community: Mohamed Bal</title>
      <link>https://dev.to/mohamed_bal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mohamed_bal"/>
    <language>en</language>
    <item>
      <title>Your SAE Passed the Cosine Similarity Bar. That Doesn't Mean It</title>
      <dc:creator>Mohamed Bal</dc:creator>
      <pubDate>Wed, 15 Jul 2026 16:50:09 +0000</pubDate>
      <link>https://dev.to/mohamed_bal/your-sae-passed-the-cosine-similarity-bar-that-doesnt-mean-it-4eo3</link>
      <guid>https://dev.to/mohamed_bal/your-sae-passed-the-cosine-similarity-bar-that-doesnt-mean-it-4eo3</guid>
      <description>&lt;p&gt;I ran a causal audit on sparse autoencoder features and found that up to 77% of "recovered" features never actually activate when their concept is present — even at cosine similarity ≈ 1.000.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;I spent the last few months building and running a causal audit on Sparse Autoencoders (SAEs) — the tool the mechanistic interpretability field uses to decompose neural network activations into human-interpretable features. The result is now on arXiv:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://arxiv.org/abs/2607.12166" rel="noopener noreferrer"&gt;From Geometric Recovery to Causal Validation: A Reproducible Audit of Sparse Autoencoder Features&lt;/a&gt;&lt;/strong&gt; (cs.LG)&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/mohamed-bal/sae-causal-audit" rel="noopener noreferrer"&gt;&lt;code&gt;sae-causal-audit&lt;/code&gt;&lt;/a&gt; · &lt;a href="https://github.com/mohamed-bal/superposition-to-monosemanticity" rel="noopener noreferrer"&gt;&lt;code&gt;superposition-to-monosemanticity&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The headline finding: &lt;strong&gt;up to 77% of SAE features that pass the field's standard recovery metric (cosine similarity ≥ 0.90) never actually fire when their feature is present&lt;/strong&gt; — including matches at cosine ≈ 1.000, in an otherwise well-trained SAE. Correlational recovery and causal behavior are not the same claim, and the metric everyone uses can't tell them apart.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem, in one sentence
&lt;/h2&gt;

&lt;p&gt;SAEs are evaluated almost entirely by &lt;strong&gt;decoder geometry&lt;/strong&gt;: does the learned decoder atom point in roughly the same direction as the ground-truth (or probed) feature? That's a correlational claim. Whether the &lt;strong&gt;encoder&lt;/strong&gt; ever actually selects that atom when the feature is genuinely present is a completely different, causal claim — and cosine similarity, by construction, cannot distinguish the two.&lt;/p&gt;

&lt;p&gt;An SAE under pressure to reconstruct well can place a decoder atom at the geometrically perfect location for a feature, while the paired encoder weight almost never wins the TopK (or ReLU) selection competition for that feature — because something else usually wins first. The atom is "recovered." It's also silent.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually did
&lt;/h2&gt;

&lt;p&gt;Rather than argue this abstractly, I built a fully controlled toy setting where ground truth is known exactly, and ran the whole pipeline from scratch:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reproduced the superposition phase diagram&lt;/strong&gt; from Elhage et al. (2022) — and caught a convergence artifact along the way: at high sparsity, under-training was silently masquerading as superposition. Fixing the step budget resolved it and surfaced a third, under-described geometric regime (&lt;em&gt;diffuse sharing&lt;/em&gt;) at extreme overcompleteness.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reproduced the TopK-vs-L1 comparison&lt;/strong&gt; from Gao et al. (2024), including a direct activation-refinement test that &lt;em&gt;measures&lt;/em&gt; L1 shrinkage rather than just asserting it (91.2% of the L1 SAE's reconstruction gap closes when you refine magnitudes on a frozen support; TopK's magnitude barely moves at all).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Built a causal validation battery&lt;/strong&gt; — ablation and sign-correct steering, propagated through the model's actual output stage, not a proxy — and ran it against every feature that passed the standard cosine bar.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last step is where it gets uncomfortable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The central result
&lt;/h2&gt;

&lt;p&gt;Two TopK SAEs, opposite ends of the Pareto front:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Correlationally recovered (of 22)&lt;/th&gt;
&lt;th&gt;Causally inert (fired_frac = 0)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Good SAE&lt;/strong&gt; (k=4, precision 1.00)&lt;/td&gt;
&lt;td&gt;22/22&lt;/td&gt;
&lt;td&gt;2 (9%) — both at cosine &amp;gt; 0.9999&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Degraded SAE&lt;/strong&gt; (k=13, precision 0.11)&lt;/td&gt;
&lt;td&gt;18/22&lt;/td&gt;
&lt;td&gt;up to 17 (77%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;"Causally inert" means: across 500 samples where the ground-truth feature is genuinely present, the matched decoder atom's encoder entry &lt;strong&gt;never fires once&lt;/strong&gt;. Not weak. Not noisy. Exactly zero. Ablating an atom that never activates cannot possibly change anything — the specificity ratio isn't small, it's undefined-and-reported-as-zero, for a structurally different reason than "weak effect."&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the &lt;em&gt;good&lt;/em&gt; SAE still has inert features
&lt;/h2&gt;

&lt;p&gt;This is the part I didn't expect going in. The two inert features in the well-trained SAE aren't noise — they're the exact same geometric event, twice. Feature 8 matches atom 78 at cosine 0.9997, anti-aligned, fired_frac = 0.00. But that same atom 78 is &lt;em&gt;also&lt;/em&gt; the best match for feature 1 — positively aligned, firing 100% of the time, ablation specificity 535.&lt;/p&gt;

&lt;p&gt;One atom, two "recovered" features. The toy model's weights explain it completely: &lt;code&gt;cos(W1, W8) = -0.9998&lt;/code&gt; — an antipodal pair, the exact &lt;code&gt;Wi ≈ -Wj&lt;/code&gt; configuration the superposition literature predicts. The SAE learned one atom per shared axis, which is the &lt;em&gt;correct&lt;/em&gt; thing to do for reconstruction. But TopK-then-ReLU only passes positive pre-activations, so the atom fires for one side of the axis and never the other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Antipodal inertness is not a training failure — it's superposition geometry faithfully compressed.&lt;/strong&gt; A better SAE pushes the anti-aligned cosine closer to 1.000, which makes the inert match look &lt;em&gt;more&lt;/em&gt; convincing by the correlational metric, not less. No amount of SAE quality removes this on its own; only interface-level awareness of match sign does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read-inert ≠ write-inert
&lt;/h2&gt;

&lt;p&gt;Here's the part that I think matters most practically. The antipodal features are &lt;strong&gt;ablation-inert&lt;/strong&gt; (you can't remove what never activates) — but they are absolutely &lt;strong&gt;not steering-inert&lt;/strong&gt;. Forcing the same atom on with the correct sign raises the paired feature's output at steering specificity 143–310, some of the highest specificities in the entire audit, attached to atoms whose ablation effect is &lt;em&gt;exactly zero&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So "causally inert" isn't one property — it decomposes into two separable, dissociable claims:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read-inert&lt;/strong&gt;: the encoder never selects the atom → monitoring built on it is blind&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write-inert&lt;/strong&gt;: interventions along the atom don't move the feature → steering built on it is impotent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All five antipodal pairs across both SAEs dissociate these completely. A feature can be simultaneously unmonitorable &lt;em&gt;and&lt;/em&gt; highly steerable, through the same atom. If you're using an SAE feature as a monitoring signal, that's a distinction with real safety implications — read-validation and write-validation are not interchangeable, and passing one tells you nothing about the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  The instrument, not just the finding
&lt;/h2&gt;

&lt;p&gt;A result that only exists inside one-off experiment scripts is a claim, not a tool. So I packaged the methodology as &lt;strong&gt;&lt;code&gt;sae-causal-audit&lt;/code&gt;&lt;/strong&gt;: a model-agnostic instrument built around two runtime-checkable structural protocols (no inheritance, no adapter needed) —&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@runtime_checkable&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SparseAutoencoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;W_dec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sae_lens.SAE&lt;/code&gt; satisfies this out of the box. The division of labor restates the finding structurally: matching uses &lt;code&gt;W_dec&lt;/code&gt; (correlational, what the field's metric measures); every causal metric routes through &lt;code&gt;encode&lt;/code&gt;/&lt;code&gt;decode&lt;/code&gt; (what decoder geometry can't certify).&lt;/p&gt;

&lt;p&gt;The package includes a &lt;strong&gt;hash-verified deterministic reproduction pipeline&lt;/strong&gt;. Getting that byte-exact promise to actually hold surfaced three layers of cross-environment nondeterminism — a serialization leak (wall-clock timing hashed into results), a multi-threaded Adam optimizer silently reordering floating-point accumulation, and the discovery that "the same torch version" on Windows vs. Linux is not the same compiled program. Byte-exact cross-platform reproducibility isn't hard to achieve — it's &lt;strong&gt;unavailable by construction&lt;/strong&gt; for this class of workload. The repo now makes two separate guarantees with disjoint scopes: byte-exact within one pinned CI environment, semantic (rtol = 1e-4) everywhere else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it show up on a real model?
&lt;/h2&gt;

&lt;p&gt;Toy models are what make exact ground truth and causal certification possible — they're also exactly what makes every number a calibration point for the easy case, not a benchmark. So I ran the harness against a published production SAE (&lt;code&gt;gpt2-small-res-jb&lt;/code&gt;, one hook layer) against 83 hand-authored concepts spanning unrelated domains.&lt;/p&gt;

&lt;p&gt;Of 83 matched pairs, 7 cleared a (lowered, probe-proxy-adjusted) recovery bar; 1 (14%) was causally inert. Small-scale, but qualitatively consistent with the toy regime. More interesting: a handful of decoder atoms — not one, several — recur as the nearest correlational match for &lt;strong&gt;dozens of semantically unrelated concepts&lt;/strong&gt; (astronomy, cryptography, law, all matching the same atom at cosine 0.30–0.70). This replicated across three independently constructed, growing concept batches, and a controlled negative case ruled out prompt-templating as the artifact. It's the same dictionary-under-splitting signal the toy antipodal-pair mechanism was built to make legible — now showing up at production scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical guidance, if you're building on SAEs
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Never gate an automated action directly on raw SAE feature activation&lt;/strong&gt; — in one realistic configuration, 77% of correlationally matched features were acting-on-noise candidates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate causally for the direction you actually use.&lt;/strong&gt; Monitoring needs read-validation. Steering needs write-validation. This work measured five cases where one direction passes at specificity 143–310 while the other sits at exactly zero.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-run causal validation whenever the SAE is retrained.&lt;/strong&gt; A feature's causal relationship to a concept is a property of one trained checkpoint, not a portable abstraction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version-pin SAE checkpoints&lt;/strong&gt; to the exact model and data distribution they were validated against.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/mohamed-bal/sae-causal-audit
&lt;span class="nb"&gt;cd &lt;/span&gt;sae-causal-audit
make reproduce      &lt;span class="c"&gt;# regenerates every number in the paper, ~3 min on CPU&lt;/span&gt;
make verify          &lt;span class="c"&gt;# checks results within tolerance, any machine&lt;/span&gt;
make verify-hashes   &lt;span class="c"&gt;# byte-exact check, pinned CI environment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The protocol interface accepts any SAE that can encode, decode, and expose its dictionary — including &lt;code&gt;sae_lens.SAE&lt;/code&gt; directly.&lt;/p&gt;




&lt;p&gt;This is my first arXiv submission as an independent researcher, and I want to say a genuine thank-you to &lt;strong&gt;Adam Karvonen&lt;/strong&gt; (lead author of &lt;a href="https://arxiv.org/abs/2503.09532" rel="noopener noreferrer"&gt;SAEBench&lt;/a&gt;) for the cs.LG endorsement that made this possible. SAEBench's benchmark-scale diagnosis — that proxy metrics don't reliably predict practical performance — is a big part of what motivated pushing the same question down to the level of individual features with a causal instrument.&lt;/p&gt;

&lt;p&gt;Happy to answer questions, get pushback, or hear about places this breaks. That's the point of putting the instrument out there rather than just the number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paper&lt;/strong&gt;: &lt;a href="https://arxiv.org/abs/2607.12166" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2607.12166&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Code&lt;/strong&gt;: &lt;a href="https://github.com/mohamed-bal/sae-causal-audit" rel="noopener noreferrer"&gt;https://github.com/mohamed-bal/sae-causal-audit&lt;/a&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>A Perfect 1.000 Cosine Match That Never Fires: The Hidden Trap in SAE Evaluation</title>
      <dc:creator>Mohamed Bal</dc:creator>
      <pubDate>Fri, 10 Jul 2026 12:48:51 +0000</pubDate>
      <link>https://dev.to/mohamed_bal/a-cosine-similarity-of-1000-and-the-feature-still-never-fires-turning-a-causal-inertness-finding-5dhp</link>
      <guid>https://dev.to/mohamed_bal/a-cosine-similarity-of-1000-and-the-feature-still-never-fires-turning-a-causal-inertness-finding-5dhp</guid>
      <description>&lt;p&gt;description: "The 77% causal-inertness finding is now a tested, hash-verified, model-agnostic audit tool — and building it surfaced two more real bugs (a serialization leak and a three-layer reproducibility failure), a new failure-mode decomposition rooted in antipodal geometry, and features matched at cosine ≈ 1.000 that never fire once — in the good SAE."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Show me the code:&lt;/strong&gt; the tool described here — &lt;code&gt;sae-causal-audit&lt;/code&gt;, with its full test suite (37 tests including property-based tests), deterministic reproduction pipeline, hash-based scientific-regression gate, and a harness for auditing published production SAEs — has its own repository: &lt;a href="https://github.com/mohamed-bal/sae-causal-audit" rel="noopener noreferrer"&gt;mohamed-bal/sae-causal-audit&lt;/a&gt;. The finding that motivated it was first published alongside the original toy-model reproduction: &lt;a href="https://github.com/mohamed-bal/superposition-to-monosemanticity" rel="noopener noreferrer"&gt;mohamed-bal/superposition-to-monosemanticity&lt;/a&gt;. Every number in this piece is written by code to a &lt;code&gt;results/*.json&lt;/code&gt; file whose SHA-256 hash is committed and verified in CI, and every figure is regenerated by re-running the corresponding script. Nothing here is hand-typed from memory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  One clarification before anything else
&lt;/h2&gt;

&lt;p&gt;This piece does not claim that sparse autoencoders are broken, and it does not claim that the tool presented here certifies them. What it does is narrower and, I'd argue, more useful: it takes the causal-validation methodology from &lt;a href="https://github.com/mohamed-bal/superposition-to-monosemanticity" rel="noopener noreferrer"&gt;the previous piece&lt;/a&gt; — the one that measured, in a fully-controlled setting, that up to 77% of features passing a standard correlational recovery bar were causally inert — and turns it into an instrument anyone can point at their own SAE. An instrument, unlike a finding, has to survive contact with inputs its author never anticipated. That constraint forced design decisions, surfaced a third real bug (reported below in full, in the same tradition as the first two), and — unexpectedly — produced a refinement of the original finding itself: "causally inert" turns out to decompose into two distinct failure modes, one of which is directly traceable to the antipodal-pair geometry of superposition.&lt;/p&gt;

&lt;p&gt;The state of the underlying question is unchanged from the previous piece: no interpretability method today gives a certified, complete account of a model's internal computation, and correlational feature-recovery metrics — the cosine-similarity matches used throughout the field's evaluation practice — measure decoder geometry, not encoder behavior. Those are two different empirical claims. This piece is about the machinery for telling them apart at whatever scale you work at, and about what that machinery revealed when it was turned, once again, on the setting where the right answers are known.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the last piece stopped, precisely
&lt;/h2&gt;

&lt;p&gt;A one-paragraph recap, because everything below builds on it. The previous piece trained the Elhage et al. (2022) toy model — 32 sparse features compressed into an 8-dimensional bottleneck at sparsity 0.95 — then trained sparse autoencoders (L1 and TopK) on its hidden activations and asked whether the SAE's dictionary atoms recover the ground-truth features. By the standard correlational metric (unsigned cosine similarity ≥ 0.90 between a ground-truth direction and its best-matching decoder atom), recovery looked excellent for the right hyperparameters. Then came the intervention: for every matched pair, ablate the atom's code on inputs where the feature is genuinely present, and measure whether the &lt;em&gt;targeted&lt;/em&gt; output drops more than everything else moves. For a deliberately imperfect SAE (TopK, $k=13$), &lt;strong&gt;17 of 22 correlationally-matched features showed an ablation effect of exactly zero&lt;/strong&gt; — not small, &lt;em&gt;zero&lt;/em&gt; — because the matched atom never fired at all when its feature was presented. One of those seventeen had a cosine similarity of 0.92. The mechanism: cosine matching compares against &lt;strong&gt;decoder&lt;/strong&gt; atoms ($W_{dec}$, the reconstruction vectors), while whether an atom &lt;em&gt;fires&lt;/em&gt; is governed by the &lt;strong&gt;encoder&lt;/strong&gt; and the TopK/ReLU selection — a competition the geometrically-correct atom can simply keep losing.&lt;/p&gt;

&lt;p&gt;That was the finding. The honest criticism of the previous piece — the one I'd make of it myself — is that its most decision-relevant output was locked inside its own experiment scripts. If you trained an SAE tomorrow and wanted &lt;em&gt;your&lt;/em&gt; inert rate, you'd have to read my code, separate the methodology from the experiment, and re-implement the former against your model. That's not a tool; that's homework. A result you can't hand to someone is a claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit, precisely
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;sae-causal-audit&lt;/code&gt; runs three measurements per matched (feature, atom) pair, in increasing order of causal strength. All three propagate through the SAE's actual &lt;code&gt;encode&lt;/code&gt;/&lt;code&gt;decode&lt;/code&gt; path and through a caller-supplied behavioral readout — never through decoder geometry alone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu1zxyrb6ics2ffhfx2ep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu1zxyrb6ics2ffhfx2ep.png" alt="Audit pipeline diagram: a SparseAutoencoder and a FeatureProbe feed two parallel paths — matching against W_dec (decoder geometry, correlational) and a causal battery of fired_frac, ablation, and steering (encoder behavior, causal) — which combine into an AuditReport serialized as hash-verified JSON and Markdown" width="799" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The diagram names the split that matters: matching runs on the decoder ($W_{dec}$) because that's what correlational recovery metrics are supposed to measure, while every causal number below comes from the encoder's actual behavior through &lt;code&gt;encode&lt;/code&gt;/&lt;code&gt;decode&lt;/code&gt; — the two paths only merge back together in the final report.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Fired fraction.&lt;/strong&gt; The cheap screen that, on its own, explained every one of the seventeen inert cases in the original experiment:&lt;/p&gt;

&lt;p&gt;$$\text{fired_frac}&lt;em&gt;{i,j} = \frac{1}{N}\sum&lt;/em&gt;{n=1}^{N} \mathbb{1}\left[\,|f_j(h_n)| &amp;gt; \varepsilon\,\right], \quad h_n \sim \text{feature } i \text{ present}$$&lt;/p&gt;

&lt;p&gt;If the encoder never activates atom $j$ across hundreds of samples where feature $i$ is genuinely present, no downstream claim about atom $j$ "representing" feature $i$ can be causal, whatever the cosine says. This is a screen, not a verdict — it costs one batched &lt;code&gt;encode&lt;/code&gt;, which matters when the full ablation battery is expensive at production scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Ablation specificity.&lt;/strong&gt; Present inputs where feature $i$ is active, encode, zero atom $j$'s code entry, decode, push both reconstructions through the downstream readout, and compare the targeted drop against mean collateral movement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sae&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;activations_on&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;f_ablated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;f_ablated&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="n"&gt;atom_idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;

&lt;span class="n"&gt;y_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;downstream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sae&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;y_abl&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;downstream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sae&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f_ablated&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;targeted_drop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_base&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="n"&gt;feature_idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y_abl&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="n"&gt;feature_idx&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;off_target&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_base&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y_abl&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;()[:,&lt;/span&gt; &lt;span class="n"&gt;other_features&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;specificity&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;targeted_drop&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;off_target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A causally faithful match hits its target hard and everything else barely at all. A ratio near 1 means the "intervention" is indistinguishable from generic collateral damage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Sign-correct steering.&lt;/strong&gt; The reverse direction: inputs where feature $i$ is &lt;em&gt;off&lt;/em&gt;, atom $j$ forced to a fixed value — multiplied by the &lt;em&gt;sign&lt;/em&gt; of the match, which the API requires as an explicit argument. Why that requirement exists is a story from the previous piece that shaped this package's interface, told properly below.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "any SAE" means: structural typing, and why the causal path routes around the decoder
&lt;/h2&gt;

&lt;p&gt;The audit accepts anything satisfying a three-member protocol — no inheritance, no registration, no adapter class to write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@runtime_checkable&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SparseAutoencoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;W_dec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;                                  &lt;span class="c1"&gt;# (d_sae, d_in), rows are atoms
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sae_lens.SAE&lt;/code&gt; — the interface behind most published open-weight SAE suites — satisfies this out of the box. The division of labor inside the audit is deliberate and is itself a restatement of the original finding: &lt;strong&gt;matching uses &lt;code&gt;W_dec&lt;/code&gt;&lt;/strong&gt; (that's the correlational step, and it &lt;em&gt;should&lt;/em&gt; use decoder geometry, because that's what the field's recovery metrics measure and what the audit is auditing), but &lt;strong&gt;every causal metric routes through &lt;code&gt;encode&lt;/code&gt; and &lt;code&gt;decode&lt;/code&gt;&lt;/strong&gt;, so encoder-side selection — the thing decoder geometry cannot certify — is what actually gets measured.&lt;/p&gt;

&lt;p&gt;The ground-truth side is a second small protocol, and it's the seam that lets one pipeline serve two regimes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FeatureProbe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;activations_with_feature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;feature_idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n_samples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;activations_without_feature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;feature_idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n_samples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the toy regime, "with feature $i$" means synthetic isolation inputs — ground truth, exact. In the real-model regime, it means positive/negative prompt datasets for a labeled concept, with activations captured at the SAE's hook point. Same audit, honestly different epistemics — the real regime's weaker ground truth is a stated substitution, not a hidden one, and the whole reason the toy calibration exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interface design as bug prevention: making the sign bug unrepresentable
&lt;/h2&gt;

&lt;p&gt;The previous piece reported two real bugs its own discipline caught: a convergence artifact in the phase diagram (caught by multi-seed sanity checks against a theoretically-required answer) and a sign-convention bug in steering (caught by the test suite). Packaging the methodology forced a harder question than catching bugs: can the &lt;em&gt;interface&lt;/em&gt; make a bug class impossible to write?&lt;/p&gt;

&lt;p&gt;For the sign bug, yes. The original failure: cosine matching takes absolute values — correctly, because a feature and its exact negation are equally good &lt;em&gt;correlational&lt;/em&gt; matches — and the first steering implementation silently assumed every match was positively aligned. On an atom whose true alignment was $-0.82$, steering "on" toward $+1$ pushed the reconstruction into a region the output ReLU clips, and the measured effect came back as exactly $0.0$. In the package, the matcher returns &lt;em&gt;both&lt;/em&gt; facts as separate fields instead of collapsing them into one lossy number:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;slots&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MatchResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;feature_idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;atom_idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;cosine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;   &lt;span class="c1"&gt;# unsigned, in [0, 1] — recovery semantics
&lt;/span&gt;    &lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;     &lt;span class="c1"&gt;# ±1.0 — intervention semantics
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and &lt;code&gt;steering_effect(...)&lt;/code&gt; &lt;strong&gt;requires&lt;/strong&gt; the sign as an argument. There is no default to silently assume. The original failure scenario is additionally encoded as a permanent regression test: an anti-aligned atom steered with the wrong sign must read back exactly $0.0$ through a ReLU downstream, and with the correct sign must read back positive. The same test that once caught the bug now guards the API that prevents it.&lt;/p&gt;

&lt;p&gt;Two more semantics rules are load-bearing enough to state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zeros carry their cause.&lt;/strong&gt; A specificity of $0.0$ can mean "weak effect" or "the atom's code was already zero, so ablating it changed nothing" — opposite implications hiding behind one number. Every causal result therefore reports &lt;code&gt;fired_frac&lt;/code&gt; alongside the ratio, and the &lt;code&gt;causally_inert&lt;/code&gt; flag is &lt;em&gt;defined&lt;/em&gt; as &lt;code&gt;fired_frac == 0.0&lt;/code&gt;, never inferred from the ratio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infinity is legal where it means something and rejected where it doesn't.&lt;/strong&gt; A perfectly surgical intervention — nonzero targeted effect, exactly zero collateral — is legitimately infinite specificity. The serializer encodes it safely (strict JSON has no &lt;code&gt;Infinity&lt;/code&gt; literal; the Python extension breaks downstream parsers), median-based statistics accept it, and mean-based statistics &lt;em&gt;refuse&lt;/em&gt; it loudly, because a mean over infinity is not a number anyone should publish.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A third bug, in the same tradition
&lt;/h2&gt;

&lt;p&gt;The package makes a specific, checkable promise: &lt;strong&gt;two runs that produce identical science produce byte-identical result files.&lt;/strong&gt; That's what lets CI regenerate every result from scratch and compare SHA-256 hashes — regression detection on the &lt;em&gt;results&lt;/em&gt;, not just the code. A refactor that silently moves a scientific number fails CI exactly like a broken unit test.&lt;/p&gt;

&lt;p&gt;The first attempt to prove that promise failed. Two back-to-back from-scratch reproductions — same seeds, single-threaded, &lt;code&gt;torch.use_deterministic_algorithms(True)&lt;/code&gt; — produced different hashes. The scientific numbers were identical; the files were not. The culprit was embarrassing in hindsight: the report dataclass carries a &lt;code&gt;runtime_seconds&lt;/code&gt; field, wall-clock timing was being serialized into the hashed JSON, and no two runs take the same number of microseconds. The fix is a documented &lt;code&gt;VOLATILE_FIELDS&lt;/code&gt; exclusion set in the serializer — timing stays available in memory and in the human-readable render, and never enters the hashed artifact.&lt;/p&gt;

&lt;p&gt;That is the third real bug this project has caught and reported across two pieces, and the pattern is the point. The convergence artifact was caught by multi-seed checks against a known answer; the sign bug by the test suite; this one by &lt;em&gt;actually executing the reproducibility claim instead of asserting it&lt;/em&gt;. The verification loop that caught it is now the CI gate itself, and the gate is tested the only way a gate can honestly be tested: reproduce twice and require identical hashes, then deliberately corrupt one number in one result file and require the gate to fail. It does — the corrupted file is named, with the expected and observed hashes side by side.&lt;/p&gt;

&lt;h2&gt;
  
  
  A fourth bug, right on schedule
&lt;/h2&gt;

&lt;p&gt;The limitations list below makes a falsifiable prediction — that a fourth bug exists — and between drafting that sentence and publishing this piece, the prediction cashed out. It lived in the reproducibility machinery itself, it was three distinct mechanisms deep, and digging it out ended with this repository making a more honest promise than the one it started with.&lt;/p&gt;

&lt;p&gt;The gate just described had passed the only test I had given it: two from-scratch reproductions on one machine, identical hashes, and a deliberately corrupted number caught loudly. Then the same gate ran on GitHub Actions and produced &lt;em&gt;different hashes on different runs of the same commit&lt;/em&gt; — same seeds, same code, same pinned dependencies. Peeling that back went three layers down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer one: the optimizer was multi-threaded behind my back.&lt;/strong&gt; &lt;code&gt;torch.set_num_threads(1)&lt;/code&gt; pins intra-op parallelism, but PyTorch's Adam defaults to &lt;code&gt;foreach=True&lt;/code&gt; — a fused multi-tensor path whose floating-point accumulation order is not the naive loop's — and inter-op parallelism (&lt;code&gt;torch.set_num_interop_threads&lt;/code&gt;) had never been pinned at all. Float addition is not associative; a different reduction order is a different result in the last bit. Setting &lt;code&gt;foreach=False&lt;/code&gt;, pinning interop threads to one, and adding a wall of defensive environment variables (&lt;code&gt;MKL_CBWR&lt;/code&gt;, every BLAS thread count, &lt;code&gt;PYTHONHASHSEED&lt;/code&gt;) restored single-environment determinism.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer two: the bad SAE is a noise amplifier — and that is a finding, not an inconvenience.&lt;/strong&gt; A last-bit difference should change a hash and nothing else. In the $k=13$ SAE it changed &lt;em&gt;integer counts&lt;/em&gt;: one feature's best-match cosine sits close enough to the 0.90 bar, and one atom's pre-activation close enough to the TopK cut, that last-bit noise flips them across. The good SAE's census never moved; the deliberately degraded one is perched on a selection boundary where its discrete statistics are chaotic in the float noise. The same TopK competition that produces causally inert matches also produces numerical instability — one mechanism, two symptoms, at two completely different levels of the stack. The repository now encodes this as an explicit $\pm 1$ tolerance band on that SAE's counts, and only that SAE's.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer three: "the same torch version" is not the same program.&lt;/strong&gt; With CI-side determinism proven, the hashes still refused to match the committed baseline — because the baseline had been generated on my Windows machine, and CI runs Linux. The &lt;code&gt;torch==2.13.0+cpu&lt;/code&gt; wheel for Windows and the one for Linux are different binaries: MSVC versus GCC 13.3, linked against MKL 2026.1 versus 2024.2, NNPACK off versus on. Different compiled code produces different last-bit rounding — deterministically, permanently. No environment variable bridges it. Byte-exact reproducibility across platforms is not hard; it is &lt;em&gt;unavailable, by construction&lt;/em&gt;. On this workload the visible symptom was layer two wearing different clothes: the bad SAE's census read one feature higher on Windows than on Linux while every continuous metric agreed to four decimal places.&lt;/p&gt;

&lt;p&gt;So the promise was restructured rather than widened. The repository now makes two, with disjoint scopes. &lt;strong&gt;Byte-exact&lt;/strong&gt; — SHA-256-identical result files — is guaranteed &lt;em&gt;within the pinned CI environment&lt;/em&gt; (&lt;code&gt;ubuntu-24.04&lt;/code&gt;, &lt;code&gt;torch==2.13.0+cpu&lt;/code&gt;) and verified there on every push by &lt;code&gt;make verify-hashes&lt;/code&gt;; the gate has since produced identical hashes across three independent runs of a single commit. &lt;strong&gt;Semantic&lt;/strong&gt; — every number equal within $\text{rtol}=10^{-4}$, the boundary-sensitive counts within $\pm 1$ — is guaranteed on &lt;em&gt;any&lt;/em&gt; platform by &lt;code&gt;make verify&lt;/code&gt;. The byte-exact baseline is generated by the CI environment itself, through a manually dispatched job that uploads it as an artifact — never regenerated locally, never copied out of an error log — because a baseline produced on the wrong machine &lt;em&gt;was&lt;/em&gt; the entire third layer. And the tolerance tier is tested the way the hash tier was: corrupt a count by two (outside the $\pm 1$ band) and the gate must fail; nudge a continuous metric by one percent and the gate must fail. Both do.&lt;/p&gt;

&lt;p&gt;One sentence of generalization, because most repositories' "fully reproducible" badge silently means &lt;em&gt;on my machine, probably&lt;/em&gt;: &lt;strong&gt;reproducibility is not one claim but a stack of claims with different scopes, and an honest repository states which rung it guarantees where.&lt;/strong&gt; This one guarantees the top rung on exactly one pinned environment, the semantic rung everywhere, and tells you which one you are getting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The test suite as instrument calibration
&lt;/h2&gt;

&lt;p&gt;An audit tool's numbers are only as trustworthy as the setting where its answers can be checked. The suite (37 tests) works in three layers, each borrowed from the previous piece's discipline and pushed one step further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hand-derivable unit cases.&lt;/strong&gt; Identity SAEs and two-atom constructions where every expected value is computable on paper: a perfectly surgical ablation must return exactly $\infty$; a structurally dead atom must return exactly $0.0$ &lt;em&gt;with&lt;/em&gt; &lt;code&gt;fired_frac = 0.0&lt;/code&gt;; a downstream that mixes the target equally into one other dimension must return specificity exactly $1.0$. The same standard the previous piece applied to &lt;code&gt;feature_dimensionality&lt;/code&gt;, where a hand-checkable antipodal pair had to come out at exactly $D_i = 0.5$.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Property-based tests&lt;/strong&gt; (Hypothesis) over randomized inputs: for &lt;em&gt;any&lt;/em&gt; directions and &lt;em&gt;any&lt;/em&gt; dictionary, cosine stays in $[0,1]$, the reported sign agrees with the true signed cosine of the chosen pair, dead atoms never win a match through a $0/0$, and bootstrap intervals are always ordered and bracketed by the sample range.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An end-to-end integration layer&lt;/strong&gt; that trains the actual toy setting — the real optimizer, the real TopK competition — and asserts the audit recovers the known qualitative answers: a good SAE's recovered features are overwhelmingly causally specific; census arithmetic is internally consistent; serialization round-trips deterministically; a shape mismatch anywhere fails loudly rather than producing numbers computed on misaligned tensors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Results: the setting re-audited under the instrument
&lt;/h2&gt;

&lt;p&gt;The deterministic pipeline (&lt;code&gt;make reproduce&lt;/code&gt;: single-threaded, &lt;code&gt;foreach=False&lt;/code&gt;, deterministic algorithms enforced, fixed seeds, ~3 minutes on CPU) retrains the original configuration — 32 features into 8 dimensions at sparsity 0.95 with decayed importance (the toy model drops the 10 lowest-importance features outright and represents the other 22, exactly as before) — and audits two TopK SAEs from opposite ends of the previous piece's Pareto front, both with 128-atom dictionaries. One environmental note worth a full sentence: the fully deterministic pipeline converges to different weights than the original multi-threaded runs, so &lt;strong&gt;the exact counts moved and the qualitative finding did not&lt;/strong&gt; — which is precisely the non-transferability the previous piece warned about when it said a number measured for one checkpoint is not a portable constant. Consider this an accidental robustness check that the claim passed. All numbers below are from the reference environment whose hashes CI verifies; where the boundary sensitivity documented above makes a count environment-dependent, that is stated at the number.&lt;/p&gt;

&lt;p&gt;The census, over the 22 well-represented features, at the same cos ≥ 0.90 recovery bar as before:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;TopK $k=4$ (good)&lt;/th&gt;
&lt;th&gt;TopK $k=13$ (bad)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Correlationally recovered, of 22&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;22 / 22&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;18 / 22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovered but &lt;strong&gt;causally inert&lt;/strong&gt; (atom never fires)&lt;/td&gt;
&lt;td&gt;2 (&lt;strong&gt;9%&lt;/strong&gt;)&lt;/td&gt;
&lt;td&gt;3 (&lt;strong&gt;17%&lt;/strong&gt;), 4 in the ±1 band&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median ablation specificity, recovered set†&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;133.8&lt;/strong&gt; [95% CI 107.0 – 167.4]&lt;/td&gt;
&lt;td&gt;68.3 [95% CI &lt;strong&gt;22.0&lt;/strong&gt; – 105.9]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median steering specificity, recovered set†&lt;/td&gt;
&lt;td&gt;37.7 [95% CI 33.1 – 41.8]&lt;/td&gt;
&lt;td&gt;16.9 [95% CI 14.2 – 21.3]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;† Medians and bootstrap intervals are computed over &lt;em&gt;every&lt;/em&gt; recovered pair across all 32 features ($n = 24$ and $n = 21$ respectively), not only the well-represented 22 used for the census rows — the bootstrap operates on the full recovered set by design.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fes7gfxmkhcoik8murgut.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fes7gfxmkhcoik8murgut.png" alt="Boxplot with individual points on a symlog scale: ablation specificity for both SAEs, inert pairs marked as amber X's sitting at exactly zero, with the specificity=1 collateral-damage line marked" width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzkb0rlrobq3z7wow0266.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzkb0rlrobq3z7wow0266.png" alt="Scatter of cosine similarity vs. ablation specificity on a symlog axis, points colored by fired_frac: high-cosine points span the full range from specificity in the hundreds down to exactly zero, with feature 8 (cos 0.9997, never fires) annotated" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Three things in that table deserve to be read slowly.&lt;/p&gt;

&lt;p&gt;First, the inert features are not marginal matches scraping past the threshold — in either SAE. The bad SAE's inert cosines are 0.986, 0.994, and 0.9995; the good SAE's two are &lt;strong&gt;0.9997 and 0.9998&lt;/strong&gt;. Read that again: the &lt;em&gt;good&lt;/em&gt; SAE — the one whose recovered set is otherwise causally excellent — contains two features whose geometric match is perfect to three decimal places and whose atoms do not fire once across 500 samples where the feature is present. The previous piece's most alarming single example was an inert match at cosine 0.92; the instrument, on a fresh training run, found matches at effectively 1.000 that never fire — and found them in &lt;em&gt;both&lt;/em&gt; SAEs, including the well-trained one. The correlational metric is not merely noisy at the margin. It can be maximally confident and causally wrong, and being a good SAE by every reconstruction and specificity measure does not prevent it. Why the good SAE, of all things, produces the most perfect inert matches has a clean geometric answer, given in the next section.&lt;/p&gt;

&lt;p&gt;Second, correlation between match quality and causal quality, over each SAE's &lt;em&gt;firing&lt;/em&gt; pairs (cosine vs. log ablation specificity): $r = 0.859$ ($n = 21$) for the good SAE, $r = 0.471$ ($n = 18$) for the bad one. The previous piece reported a single pooled figure ($r = 0.657$); splitting it per-SAE reveals the more decision-relevant shape: &lt;strong&gt;the correlational metric is least trustworthy exactly where you most need it.&lt;/strong&gt; On a healthy dictionary, cosine is a decent (never sufficient) proxy for causal quality; on a degraded one — the case an audit exists to catch — the proxy itself degrades toward uninformative. Cosine similarity is a fair-weather instrument.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa7umo9vzrllda7ay1jay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa7umo9vzrllda7ay1jay.png" alt="Stacked bar chart: recovered features split into firing vs. causally inert, for the good (1/22 inert, 5%) and bad (6/18 inert, 33%) SAEs" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Third, the bad SAE's ablation interval is wide in a way the point estimate hides. The good SAE's 95% interval spans 107–167 around a median of 134 — a relative width of about 45%. The bad SAE's spans 22–106 around 68: a relative width of &lt;strong&gt;123%&lt;/strong&gt;, with a lower bound sitting within an order of magnitude of the specificity-1 collateral-damage line. A percentile bootstrap over an 18-pair recovered set containing three exact zeros produces resampled medians that swing across most of the observed range — the uncertainty structure &lt;em&gt;is&lt;/em&gt; the finding, restated statistically. This is also the upgrade the previous piece explicitly owed, having warned that its n ≈ 20 point estimates should be read as shapes, not tight values. Every summary number now ships with a seeded, 10,000-resample interval.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F28n9ccgvzkbbgi6fj4sx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F28n9ccgvzkbbgi6fj4sx.png" alt="Overlaid histograms of 10,000 bootstrap-resampled medians for each SAE: the good SAE's distribution sits tightly around 150, the bad SAE's is wide and multimodal with mass reaching down toward zero" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the count carrying the "±1 band" annotation is itself data. On the reference Linux environment the bad SAE's recovered census reads 18 with 3 inert; on a Windows build of the &lt;em&gt;same&lt;/em&gt; torch version it reads 19 with 4, because one non-antipodal feature (cosine 0.924) sits close enough to both the recovery bar and the TopK selection boundary that different BLAS builds resolve it differently. That flip-prone feature is the competitive-inertness case discussed in the next section — the boundary sensitivity documented in the reproducibility section and the causal taxonomy below turn out to be the same phenomenon seen from two altitudes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomy of the perfect inert matches: antipodal pairs, and a refinement of the original finding
&lt;/h2&gt;

&lt;p&gt;The good SAE's two inert features repay close inspection, because they are not flukes and they are not independent — they are the same geometric event happening twice, visible end to end.&lt;/p&gt;

&lt;p&gt;Feature 8 matches atom 78 at cosine &lt;strong&gt;0.9997&lt;/strong&gt;, anti-aligned (sign $-$), with &lt;code&gt;fired_frac = 0.00&lt;/code&gt;: the atom never activates once across 500 feature-ON samples, so its ablation specificity is exactly 0. But atom 78 is simultaneously the best match for &lt;strong&gt;feature 1&lt;/strong&gt; — same atom, positively aligned, firing on 100% of feature-1 samples with an ablation specificity of 535. One atom, two "recovered" features. And the good SAE's &lt;em&gt;other&lt;/em&gt; inert feature is the identical story with different indices: feature 5 matches atom 22 at cosine 0.9998, anti-aligned, never fires — while feature 0 matches the &lt;em&gt;same&lt;/em&gt; atom 22, positively aligned, firing every time with specificity 347.&lt;/p&gt;

&lt;p&gt;Checking the toy model's weights explains everything: $\cos(W_1, W_8) = -0.9998$ and $\cos(W_0, W_5) = -0.9999$. Both are &lt;strong&gt;antipodal pairs&lt;/strong&gt; — the exact $W_i \approx -W_j$ configuration the original superposition paper predicts and the previous piece reproduced — two well-represented features sharing a single direction with opposite signs. The SAE, reasonably, learned &lt;em&gt;one&lt;/em&gt; atom per shared axis. The encoder's TopK-then-ReLU selection passes only positive pre-activations, so each atom fires for the positive side of its axis and never for the negative side. Decoder geometry for the negative-side feature is essentially perfect; encoder behavior for it is essentially nonexistent. This also answers the question the census table raised — why the &lt;em&gt;good&lt;/em&gt; SAE produces the most perfect inert matches: antipodal inertness is not a training failure, it is superposition geometry faithfully compressed. A better SAE learns the shared axis &lt;em&gt;more&lt;/em&gt; precisely, which pushes the anti-aligned cosine &lt;em&gt;closer&lt;/em&gt; to 1.000. The failure is structural, and no amount of SAE quality removes it — only interface-level awareness of match sign does.&lt;/p&gt;

&lt;p&gt;The bad SAE replicates the pattern threefold: atoms 22, 21, and 39 each serve an antipodal pair (features 0/5, 1/8, and 4/2 respectively), each with one side firing at specificity in the hundreds and the other side at exactly zero, each pair anti-parallel in the ground truth to at least $-0.999$. Across both SAEs, that is &lt;strong&gt;five antipodal pairs, and on the reference environment they account for every causally inert feature in both recovered sets.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Which sharpens the taxonomy: causal inertness itself decomposes by &lt;em&gt;cause&lt;/em&gt;. &lt;strong&gt;Structural inertness&lt;/strong&gt; — the antipodal mechanism above — appears in good and bad SAEs alike, survives improved training, and is diagnosable from geometry (a shared atom with opposite signs is visible in the match table before any intervention runs). &lt;strong&gt;Competitive inertness&lt;/strong&gt; — an atom that simply keeps losing the TopK competition despite decent geometry, the dominant mechanism behind the previous piece's 77% figure — appears only in the degraded SAE. The bad SAE's fourth inert case, the non-antipodal feature at cosine 0.924 that flips in and out of the census across BLAS builds, is this second kind — and the fact that it is &lt;em&gt;also&lt;/em&gt; the boundary-unstable feature is not a coincidence. An atom that barely loses the TopK competition is an atom whose selection is decided in the last bits of a float; competitive inertness and numerical boundary sensitivity are one mechanism expressed at two levels. The two kinds have opposite operational profiles: the structural kind is stable, predictable, and screenable from the dictionary alone; the competitive kind is unstable by nature and is precisely what the &lt;code&gt;fired_frac&lt;/code&gt; screen exists to catch empirically.&lt;/p&gt;

&lt;p&gt;And there is a twist that refines the original taxonomy along a second axis. These features are ablation-inert — you cannot remove what never activates — but they are &lt;strong&gt;not steering-inert&lt;/strong&gt;: forcing atom 78 on &lt;em&gt;with the correct negative sign&lt;/em&gt; raises feature 8's reconstructed output with a steering specificity of &lt;strong&gt;310&lt;/strong&gt;, and the same intervention on feature 5's atom scores 203; the bad SAE's three antipodal ghosts score 143–261. These are among the highest steering specificities in the entire audit, attached to atoms whose ablation effect is exactly zero. The decoder direction is causally &lt;em&gt;usable&lt;/em&gt; in the write direction even though the encoder never uses it in the read direction. "Causally inert," as the previous piece used it, therefore decomposes into two separable claims — &lt;strong&gt;read-inert&lt;/strong&gt; (the encoder never selects the atom for the feature; ablation-based monitoring built on this atom is blind) and &lt;strong&gt;write-inert&lt;/strong&gt; (interventions along the atom don't move the feature; steering built on it is impotent) — and all five antipodal pairs dissociate the two completely. A feature can be unmonitorable yet steerable through the same atom, and in this setting that is not an edge case: it is the &lt;em&gt;systematic signature&lt;/em&gt; of antipodal superposition under a positive-pass encoder. For anyone building on SAE features, the two failure modes have different operational consequences, and one intervention type cannot stand in for the other. This decomposition wasn't visible in the previous piece because, without the signed-steering machinery working correctly, the write-direction test on anti-aligned matches returned zeros for the wrong reason. Fixing the instrument revealed structure the bug had been hiding.&lt;/p&gt;

&lt;p&gt;Two smaller notes fall out of the same examples. The matcher is deliberately greedy (per-feature argmax) rather than a bipartite assignment, precisely so that atom collisions like 1-and-8-on-atom-78 surface in the results instead of being optimized away — a collision is a finding about the dictionary (here: one atom serving an antipodal pair), not matching noise; the audit's five collisions were the thread that unraveled everything above. And the &lt;code&gt;fired_frac&lt;/code&gt; screen would have flagged every one of the five for the cost of one batched &lt;code&gt;encode&lt;/code&gt;, before any intervention ran — which at production scale is the difference between a cheap census and an expensive one.&lt;/p&gt;

&lt;h2&gt;
  
  
  From toy calibration to production audit: the real-model harness
&lt;/h2&gt;

&lt;p&gt;Everything above is the controlled setting. The package ships &lt;code&gt;scripts/audit_real_sae.py&lt;/code&gt;: the identical pipeline pointed at &lt;strong&gt;published, production SAEs&lt;/strong&gt; — GPT-2 residual-stream SAEs and Gemma Scope, via SAELens and TransformerLens. The real setting forces two substitutions, and the harness makes both explicit rather than smuggling them in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ground truth → probe datasets.&lt;/strong&gt; "Feature present" is defined by positive/negative prompt sets per labeled concept, activations captured at the SAE's hook point on the final token. The concept's direction — the thing cosine matching needs — is estimated as the difference in mean activations between the two sets: a standard linear-probe direction, and explicitly the weakest link in the real regime. It is a proxy standing in for ground truth that does not exist; that is precisely why the pipeline is calibrated first in the toy regime, where the test suite can assert the right answers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Toy readout → spliced logits.&lt;/strong&gt; The downstream readout decodes the (possibly intervened) SAE code, splices the reconstruction back into the residual stream at the hook point, runs the remainder of the model, and reads mean logits over a small set of concept-diagnostic tokens. Ablation specificity then means: does zeroing this atom suppress &lt;em&gt;this concept's&lt;/em&gt; tokens more than it moves the other audited concepts' tokens?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GPT-2-small runs on a free Colab T4 (or CPU, slowly); Gemma-2-2b with Gemma Scope wants ~16 GB of GPU memory. The research question the harness exists to answer is the obvious promotion of everything above: &lt;em&gt;of the features in a published production SAE that pass a standard correlational bar for a labeled concept, what fraction never fire when the concept is actually present — and of those that fire, how does read-specificity relate to write-specificity?&lt;/em&gt; I didn't know the answers when I wrote the previous paragraph, and I specifically wasn't predicting that the toy regime's rates would transfer — the probe-direction proxy alone guarantees the numbers aren't comparable one-to-one. Here's what running it actually found.&lt;/p&gt;

&lt;h2&gt;
  
  
  A first real-model census, and something the toy setting didn't prepare me for
&lt;/h2&gt;

&lt;p&gt;I audited &lt;code&gt;gpt2-small-res-jb/blocks.8.hook_resid_pre&lt;/code&gt; — a published SAE from SAELens — against 83 hand-written concepts chosen for maximum semantic distance from one another: geography, natural sciences, sports, and a long tail of skilled trades (beekeeping, glassblowing, cartography, falconry) picked specifically because nothing about "beekeeping" should share a probe direction with "cryptography." Each concept gets 8 positive and 8 negative prompts; the correlational bar drops to cosine ≥ 0.5, down from the toy regime's 0.90, because a difference-in-means probe direction from 8 prompts is a much weaker proxy than exact ground truth.&lt;/p&gt;

&lt;p&gt;Of 83 matched pairs, 7 cleared the bar. Of those, 1 (&lt;strong&gt;14%&lt;/strong&gt;) was causally inert. Ablation specificity over the recovered set: median 1.63, 95% CI [0.05, 5.34]. Steering specificity: median 2.23, 95% CI [0.69, 3.54]. Both intervals are wide and both sit close to their lower bound — which is the same story the toy regime told: correlational recovery is a weak predictor of causal magnitude, now showing up in a production dictionary instead of a synthetic one. I'm explicitly not treating 14% as comparable to the toy regime's 77%/9% — the probe-direction proxy and the lowered bar mean the two numbers measure related but distinct things, exactly as flagged above.&lt;/p&gt;

&lt;p&gt;That's the expected kind of result. The unexpected part showed up while I was scaling the concept set up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Atom 14149 is the nearest match for 8 of the 83 concepts.&lt;/strong&gt; Not "related" concepts — astronomy, cryptography, and law are three of the eight, domains that share essentially no vocabulary. Same story at smaller scale: atom 4504 and atom 17413 each match 5 concepts, atom 17241 matches 4. This is the "matcher is deliberately greedy, and a collision is a finding" argument from the antipodal-pairs section above, playing out again — except this time on a real dictionary in a production model, not something I built to have this property.&lt;/p&gt;

&lt;p&gt;I didn't believe it the first time. My first instinct was that it had to be a prompt-template artifact — I'd started scaling the concept set by extending it with 40 templated per-country entries (same eight-sentence skeleton, country names substituted), and it's exactly the kind of thing that could fake a "collision" by making 40 concepts secretly correlated with each other. So I checked: the collision rate went &lt;em&gt;up&lt;/em&gt; and the recovery yield went &lt;em&gt;down&lt;/em&gt; on the templated batch specifically, which is itself informative (templated concepts really do collapse toward shared probe directions — that's a methods finding worth knowing on its own) but it also meant I couldn't trust that batch as evidence for anything else. I threw it out and rebuilt the concept set entirely by hand — 83 concepts, no two sharing a sentence structure, spanning three independently-grown batches of increasing size (33, then 48, then 83). The same handful of atoms kept recurring as the nearest match across all three. Whatever is generating this, it isn't my template.&lt;/p&gt;

&lt;p&gt;What it &lt;em&gt;is&lt;/em&gt; — genuine antipodal-style structural inertness playing out in a production dictionary, a limitation of the difference-in-means proxy direction itself, or a real polysemantic hub feature that several unrelated concepts happen to route through — cosine matching alone can't say. That's exactly the kind of question the causal battery above exists to answer, and disambiguating it against this SAE is the obvious next step for the harness.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision framework, updated
&lt;/h2&gt;

&lt;p&gt;The previous piece closed with a validation-level table. The instrument adds a rung to it — the cheap screen — and the feature-8 finding splits the top rung in two:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Validation level&lt;/th&gt;
&lt;th&gt;What it actually establishes&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;What it still can't tell you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cosine match to a known/probed direction&lt;/td&gt;
&lt;td&gt;Decoder geometry alignment&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;td&gt;Whether the encoder ever selects the atom at all — this piece found cosine-≈1.000 counterexamples, in a well-trained SAE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;&lt;code&gt;fired_frac&lt;/code&gt; screen&lt;/strong&gt; (one batched &lt;code&gt;encode&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Whether the atom activates when the feature/concept is present&lt;/td&gt;
&lt;td&gt;Near-zero&lt;/td&gt;
&lt;td&gt;Whether the activation is &lt;em&gt;specific&lt;/em&gt; — an atom can fire promiscuously&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ablation specificity&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Read-direction&lt;/strong&gt; causal specificity: monitoring built on this atom sees the feature&lt;/td&gt;
&lt;td&gt;Moderate (intervention harness required)&lt;/td&gt;
&lt;td&gt;Write-direction behavior; out-of-distribution transfer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sign-correct steering specificity&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Write-direction&lt;/strong&gt; causal specificity: interventions along this atom move the feature&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Read-direction behavior — five antipodal pairs show the two dissociate completely&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The production guidance from the previous piece survives unchanged and gets sharper: never gate an automated action on raw SAE activation (or absence of activation) without the atom having passed the causal battery &lt;em&gt;for the direction of use&lt;/em&gt; — a monitoring use case needs read-validation, a steering use case needs write-validation, and this piece measured five cases where one direction passes at specificity 143–310 while the other sits at exactly zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations, stated directly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The real-model census above is small and single-layer: 83 concepts, one hook point, one model, 7 recovered features. It is a first census, not a benchmark — the toy numbers remain the calibration point for the easy case, and the real-model rate isn't directly comparable to it for the reasons stated above.&lt;/li&gt;
&lt;li&gt;The difference-in-means probe direction in the real harness is a linear approximation standing in for ground truth that doesn't exist, and concept prompt sets of realistic size undersample the concept's distribution. Both weaken the correlational side of the real-regime audit — the causal side (&lt;code&gt;fired_frac&lt;/code&gt;, ablation, steering) does not depend on the direction estimate, only the matching does.&lt;/li&gt;
&lt;li&gt;The causal battery still tests features in isolation on the ON side; interaction effects between simultaneously active features remain untested in both regimes. The read/write decomposition was measured on five antipodal pairs across two SAEs — systematic within this run — but still within one training run and one seed; the structural/competitive split of inertness likewise rests on one run and its ±1 boundary band, not a measured rate across seeds.&lt;/li&gt;
&lt;li&gt;The sample sizes remain what they are: 22 features, 2 SAE configurations, 1 seed per SAE under the new deterministic pipeline (the bootstrap quantifies within-sample uncertainty, not across-seed variance — the previous piece's 3-seed protocol measured the latter and the tool supports re-running under any seed).&lt;/li&gt;
&lt;li&gt;Four bugs caught and reported across two pieces is not evidence the pipeline is now bug-free; it is evidence the discipline that catches them is working. The previous draft of this list predicted a fourth existed, and it did — the expected steady state is that a fifth does too.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing synthesis
&lt;/h2&gt;

&lt;p&gt;The previous piece ended on a discipline: measure it, expect the measurement to complicate the clean story, report the complication anyway. This piece is what happens when that discipline is applied to the piece itself. The finding became an instrument, and building the instrument complicated the finding — productively, four times over. The reproducibility claim, actually executed, exposed a serialization bug and produced a CI gate that now enforces what was previously asserted — and the gate, pushed onto machines that were not mine, exposed three more layers of the same claim and forced it to be restated honestly as two guarantees with different scopes. The sign-handling fix, promoted from a patch to an API contract, made a bug class unrepresentable and then revealed structure the bug had hidden: causal inertness decomposes into read-inertness and write-inertness, and antipodal pairs — the most basic geometry superposition produces — systematically generate features that are perfectly matched, completely unmonitorable, and highly steerable, all at once, through one atom apiece — in the good SAE as much as the bad one. And the fresh training run under a stricter environment moved every exact count while preserving every qualitative claim, which is the transferability behavior the original piece predicted and is now, accidentally, a measured demonstration of it.&lt;/p&gt;

&lt;p&gt;The instrument is in &lt;a href="https://github.com/mohamed-bal/sae-causal-audit" rel="noopener noreferrer"&gt;mohamed-bal/sae-causal-audit&lt;/a&gt;: &lt;code&gt;make reproduce&lt;/code&gt; regenerates every number here in about three minutes on a CPU; &lt;code&gt;make verify&lt;/code&gt; checks them within tolerance on any machine, and &lt;code&gt;make verify-hashes&lt;/code&gt; holds the pinned CI environment to the byte; the protocol interface accepts your SAE if it can &lt;code&gt;encode&lt;/code&gt;, &lt;code&gt;decode&lt;/code&gt;, and show its dictionary. If you run the audit against your own SAE — especially a production one — I want to hear what your inert census looks like, in both directions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Elhage, N. et al. (2022), &lt;a href="https://transformer-circuits.pub/2022/toy_model/index.html" rel="noopener noreferrer"&gt;"Toy Models of Superposition,"&lt;/a&gt; Anthropic.&lt;/li&gt;
&lt;li&gt;Bricken, T. et al. (2023), &lt;a href="https://transformer-circuits.pub/2023/monosemantic-features/index.html" rel="noopener noreferrer"&gt;"Towards Monosemanticity: Decomposing Language Models With Dictionary Learning,"&lt;/a&gt; Anthropic.&lt;/li&gt;
&lt;li&gt;Templeton, A. et al. (2024), &lt;a href="https://transformer-circuits.pub/2024/scaling-monosemanticity/" rel="noopener noreferrer"&gt;"Scaling Monosemanticity: Extracting Interpretable Features from Claude 3 Sonnet,"&lt;/a&gt; Anthropic.&lt;/li&gt;
&lt;li&gt;Gao, L. et al. (2024), &lt;a href="https://arxiv.org/abs/2406.04093" rel="noopener noreferrer"&gt;"Scaling and Evaluating Sparse Autoencoders,"&lt;/a&gt; arXiv:2406.04093.&lt;/li&gt;
&lt;li&gt;Lieberum, T. et al. (2024), "Gemma Scope: Open Sparse Autoencoders Everywhere All at Once on Gemma 2," arXiv:2408.05147.&lt;/li&gt;
&lt;li&gt;Tibshirani, R. (1996), "Regression Shrinkage and Selection via the Lasso," &lt;em&gt;Journal of the Royal Statistical Society&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Efron, B. &amp;amp; Tibshirani, R. (1993), &lt;em&gt;An Introduction to the Bootstrap&lt;/em&gt;, Chapman &amp;amp; Hall.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/pdf/2404.14082" rel="noopener noreferrer"&gt;"Mechanistic Interpretability for AI Safety — A Review,"&lt;/a&gt; arXiv:2404.14082.&lt;/li&gt;
&lt;li&gt;The originating write-up and its repository: &lt;a href="https://github.com/mohamed-bal/superposition-to-monosemanticity" rel="noopener noreferrer"&gt;mohamed-bal/superposition-to-monosemanticity&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;This piece's tool and its repository: &lt;a href="https://github.com/mohamed-bal/sae-causal-audit" rel="noopener noreferrer"&gt;mohamed-bal/sae-causal-audit&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>opensource</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>I Ran a Causal Test on Sparse Autoencoders — 77% of 'Recovered' Features Turned Out to Be Causally Inert</title>
      <dc:creator>Mohamed Bal</dc:creator>
      <pubDate>Wed, 08 Jul 2026 12:52:12 +0000</pubDate>
      <link>https://dev.to/mohamed_bal/i-ran-a-causal-test-on-sparse-autoencoders-77-of-recovered-features-turned-out-to-be-causally-39ma</link>
      <guid>https://dev.to/mohamed_bal/i-ran-a-causal-test-on-sparse-autoencoders-77-of-recovered-features-turned-out-to-be-causally-39ma</guid>
      <description>&lt;h1&gt;
  
  
  What Your Model Is Hiding in Plain Sight: A Rigorous, Reproducible Tour of Superposition, Dictionary Learning, and the Measured Limits of Mechanistic Interpretability
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Show me the code:&lt;/strong&gt; the complete implementation (toy models, sparse autoencoders, feature-recovery metrics, causal validation, full test suite) is available on GitHub: &lt;a href="https://github.com/mohamed-bal/superposition-to-monosemanticity" rel="noopener noreferrer"&gt;mohamed-bal/superposition-to-monosemanticity&lt;/a&gt;. Every number in this piece is written by code in that repository to a &lt;code&gt;results/*.json&lt;/code&gt; file — nothing here is hand-typed from memory, and every figure is regenerated by re-running the corresponding script.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  One clarification before anything else
&lt;/h2&gt;

&lt;p&gt;Mechanistic interpretability is not a solved problem, and nothing in this piece claims otherwise. What this piece does is reproduce, from scratch and with proper statistical rigor (multiple random seeds, explicit convergence checks, honest reporting of where the methodology breaks), the foundational results the entire modern interpretability toolkit is built on — sparse autoencoders, feature dictionaries, the class of tools currently used by Anthropic, OpenAI, and Google DeepMind's interpretability teams — and then measures, precisely, where that toolkit succeeds and where it falls short, even in the most favorable setting that can be constructed for it: a small synthetic model where the ground truth is fully known and fully controlled.&lt;/p&gt;

&lt;p&gt;The real state of the field as of mid-2026: sparse autoencoders scale to production models. Anthropic extracted millions of features from Claude 3 Sonnet's residual stream (Templeton et al., 2024); OpenAI and Google DeepMind have since published comparable open-weight SAE suites for their own models (Gao et al., 2024; Lieberum et al., 2024, "Gemma Scope"). But recovering &lt;em&gt;a&lt;/em&gt; sparse, plausible-looking decomposition is not the same as proving you've found &lt;em&gt;the&lt;/em&gt; decomposition the model actually uses — and a 2024 survey of the field flags a sharper, unresolved concern: as models get more capable, there's a live research question about whether they could develop internal structure that actively resists or misleads the very analysis techniques used to probe them. No interpretability method today gives a certified, complete account of a model's internal computation. Anything presented as though it does is either premature or marketing.&lt;/p&gt;

&lt;p&gt;What actually exists is a well-defined, falsifiable hypothesis — the &lt;strong&gt;superposition hypothesis&lt;/strong&gt; — a specific training procedure that produces structure consistent with it, and a growing but incomplete body of validation. That is the real subject here: what the hypothesis claims, why it should be true on purely geometric grounds, and what happens when you go and check.&lt;/p&gt;

&lt;h2&gt;
  
  
  The theoretical problem
&lt;/h2&gt;

&lt;p&gt;Start from the assumption most people make, often without noticing they're making it, about what a hidden layer "means": that each dimension corresponds to roughly one interpretable concept, the way a variable in ordinary code corresponds to one thing. Real trained networks violate this constantly. A single neuron in a real language model frequently activates for several unrelated concepts at once — a phenomenon called &lt;strong&gt;polysemanticity&lt;/strong&gt; — which is precisely why reading meaning directly off individual neurons has never worked reliably as a general interpretability strategy.&lt;/p&gt;

&lt;p&gt;Elhage et al. (Anthropic, 2022) proposed a precise, two-part explanation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The linear representation hypothesis&lt;/strong&gt; — features correspond to &lt;em&gt;directions&lt;/em&gt; in activation space, not to individual basis coordinates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The superposition hypothesis&lt;/strong&gt; — when a model would benefit from representing more features than it has dimensions, and those features are &lt;strong&gt;sparse&lt;/strong&gt; (rarely all active at once), it can represent more features than dimensions by assigning them &lt;em&gt;almost&lt;/em&gt;-orthogonal — not exactly orthogonal — directions. Simultaneously active features interfere with each other, but if that's rare enough, the expected benefit of representing more features outweighs the expected cost of occasional interference.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This isn't an ad hoc trick; it has a name and a well-studied justification in high-dimensional geometry. The &lt;strong&gt;Johnson–Lindenstrauss phenomenon&lt;/strong&gt; says that in a $d$-dimensional space you can fit &lt;em&gt;exponentially more&lt;/em&gt; than $d$ near-orthogonal directions — with pairwise inner products bounded arbitrarily close to zero — as long as you're willing to accept that "close to zero" instead of demanding "exactly zero." Superposition, under this view, is a neural network discovering and exploiting exactly this geometric fact under ordinary gradient descent — nothing about it needs to be designed in.&lt;/p&gt;

&lt;h3&gt;
  
  
  The geometry gets specific: antipodal pairs and polytopes
&lt;/h3&gt;

&lt;p&gt;The original paper goes further than "features overlap somehow" — it characterizes &lt;em&gt;how&lt;/em&gt; they overlap once a model settles into a solution, and the structure is surprisingly rigid rather than smoothly continuous. Two features forced to share a single dimension under symmetric competition don't split it 60/40 or drift to an arbitrary angle; the stable configuration found by gradient descent is $W_i = -W_j$ — an &lt;strong&gt;antipodal pair&lt;/strong&gt;, exactly opposite unit vectors sharing one dimension, each still perfectly distinguishable from the other because a real input is (with overwhelming probability, under sparsity) never simultaneously "feature $i$ active" and "feature $j$ active." With more features competing for the same handful of dimensions, the geometry generalizes to higher-order symmetric configurations — the paper documents pentagons, tetrahedra, and other regular polytope-like arrangements — which is the same optimization structure that shows up in the century-old &lt;strong&gt;Thomson problem&lt;/strong&gt; (how do you arrange $n$ mutually-repelling point charges on a sphere to minimize total potential energy?). A network resolving superposition is, geometrically, doing the same kind of job: packing feature directions to minimize mutual interference subject to a fixed number of dimensions.&lt;/p&gt;

&lt;p&gt;This piece doesn't reproduce the polytope geometry in full (that requires studying 3-8 feature toy models in isolation, a genuinely separate and equally interesting reproduction exercise). What it does reproduce, with the rigor of multi-seed statistics, is the two-feature antipodal case exactly, and the resulting large-scale statistical structure — the &lt;strong&gt;phase diagram&lt;/strong&gt; — across dozens of features and a full sparsity/overcompleteness sweep.&lt;/p&gt;

&lt;h2&gt;
  
  
  The toy model, precisely
&lt;/h2&gt;

&lt;p&gt;Every experiment in this piece builds on one small, fully from-scratch model — no pretrained weights, no external data, runs on a CPU in seconds — implemented in &lt;a href="https://github.com/mohamed-bal/superposition-to-monosemanticity/blob/main/src/toy_model.py" rel="noopener noreferrer"&gt;&lt;code&gt;src/toy_model.py&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hidden = W x                (n_hidden-dimensional bottleneck; linear, no nonlinearity here)
x_hat  = ReLU(Wᵀ hidden + b)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;W&lt;/code&gt; has shape &lt;code&gt;(n_hidden, n_features)&lt;/code&gt;, and the interesting regime is &lt;code&gt;n_hidden &amp;lt; n_features&lt;/code&gt; — a bottleneck that forces a choice about what to represent. Inputs are synthetic and sparse: each of the &lt;code&gt;n_features&lt;/code&gt; entries is independently zero with probability &lt;code&gt;sparsity&lt;/code&gt;, and drawn Uniform(0,1) otherwise. Training minimizes an &lt;strong&gt;importance-weighted&lt;/strong&gt; reconstruction loss:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sum_i&lt;/span&gt; &lt;span class="n"&gt;I_i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x_i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x_hat_i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;   &lt;span class="c1"&gt;# I_i = per-feature importance weight
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two different importance schedules matter across this piece, and it's worth being explicit that they answer &lt;em&gt;different&lt;/em&gt; questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decayed importance&lt;/strong&gt; ($I_i = 0.9^i$), which breaks symmetry between features so the model has a principled reason to prioritize &lt;em&gt;which&lt;/em&gt; features it represents when it can't represent all of them equally well. This is the schedule to use if you want to study &lt;strong&gt;prioritization&lt;/strong&gt; — and it produces a real, sharp finding on its own: training a 32-feature model into an 8-dimensional bottleneck at sparsity=0.95, the optimizer doesn't spread capacity thinly across all 32 features — it fully drops the 10 lowest-importance ones (their columns in &lt;code&gt;W&lt;/code&gt; collapse to near-zero) and represents the other 22 well. This emergent triage falls directly out of gradient descent on the importance-weighted loss; nothing hand-codes which features get dropped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uniform importance&lt;/strong&gt; ($I_i = 1$ for all $i$), which removes prioritization as a confound entirely and is the correct schedule for studying the &lt;strong&gt;geometric phase structure&lt;/strong&gt; of superposition itself — how much interference emerges, and what shape it takes — independent of any priority ordering. This is the schedule used for the phase diagram below.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ToyModelConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;n_features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;n_hidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;sparsity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;importance_decay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;   &lt;span class="c1"&gt;# set to 1.0 for uniform importance
&lt;/span&gt;    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Measuring superposition precisely: feature dimensionality
&lt;/h2&gt;

&lt;p&gt;A single scalar per feature, defined in Elhage et al. (2022) §3, captures exactly how much of a "dedicated dimension" each feature effectively owns:&lt;/p&gt;

&lt;p&gt;$$D_i = \frac{\lVert W_i \rVert^2}{\sum_j (W_i \cdot W_j)^2}$$&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;feature_dimensionality&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;norms_sq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# ||W_i||^2, shape (n_features,)
&lt;/span&gt;    &lt;span class="n"&gt;gram&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;W&lt;/span&gt;                         &lt;span class="c1"&gt;# W_i . W_j, shape (n_features, n_features)
&lt;/span&gt;    &lt;span class="n"&gt;denom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gram&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="c1"&gt;# sum_j (W_i . W_j)^2
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;norms_sq&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;denom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clamp_min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1e-12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three exact cases, each checked by a unit test in the repo rather than merely asserted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Orthonormal features&lt;/strong&gt; ($W$ = identity): $D_i = 1$ for every feature — confirmed exactly (&lt;code&gt;test_feature_dimensionality_is_one_for_exactly_orthonormal_features&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An antipodal pair&lt;/strong&gt; ($W = [\,1, -1\,]$, one shared dimension): $D_i = 0.5$ for both features, matching the geometric picture above exactly (&lt;code&gt;test_feature_dimensionality_is_half_for_antipodal_pair&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A subtlety that cost an afternoon to catch:&lt;/strong&gt; $D_i$ is a &lt;em&gt;ratio&lt;/em&gt; of squared norms, so it is not, by itself, a magnitude detector. Construct $W = \begin{bmatrix}1 &amp;amp; 0 &amp;amp; 10^{-6}\ 0 &amp;amp; 1 &amp;amp; 10^{-6}\end{bmatrix}$ — the third feature's column norm is $\sqrt{2}\times10^{-6}$, utterly negligible in absolute terms. Its $D_i$ is nonetheless &lt;strong&gt;1.0&lt;/strong&gt;, not near zero (&lt;code&gt;test_feature_dimensionality_alone_cannot_detect_a_dropped_feature&lt;/code&gt;), because both the numerator and the dominant denominator term scale the same way with the column's overall magnitude. &lt;strong&gt;A genuinely dropped feature and a genuinely-represented-but-tiny-relative-to-its-competitors feature can report the identical $D_i$.&lt;/strong&gt; Telling them apart requires checking $\lVert W_i \rVert^2$ directly, not just $D_i$ — a distinction that turns out to matter for a real finding below, not just as a footnote.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The phase diagram: does superposition structure follow the predicted pattern?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Methodology
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;$n_{hidden} = 20$, fixed throughout.&lt;/li&gt;
&lt;li&gt;Overcompleteness ratio $n_{features}/n_{hidden} \in {1, 2, 4, 8}$ (so $n_{features} \in {20, 40, 80, 160}$).&lt;/li&gt;
&lt;li&gt;Sparsity $\in {0.0, 0.3, 0.6, 0.8, 0.9, 0.95, 0.99}$.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uniform importance&lt;/strong&gt; throughout, isolating pure geometric structure from prioritization effects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3 independent seeds per (ratio, sparsity) cell&lt;/strong&gt; — every number below is a mean $\pm$ standard deviation across those seeds, not a single lucky (or unlucky) run.&lt;/li&gt;
&lt;li&gt;Each feature is classified by its final $D_i$: &lt;strong&gt;dedicated&lt;/strong&gt; ($D_i &amp;gt; 0.9$), &lt;strong&gt;superposed&lt;/strong&gt; ($0.1 \le D_i \le 0.9$), or a candidate "not really there" case ($D_i &amp;lt; 0.1$) — which, per the subtlety above, is further split by checking $\lVert W_i \rVert^2$ directly into &lt;strong&gt;truly dropped&lt;/strong&gt; ($\lVert W_i \rVert^2 &amp;lt; 0.1$, i.e. actually near-zero weight) versus &lt;strong&gt;diffusely shared&lt;/strong&gt; ($\lVert W_i \rVert^2 \ge 0.1$, i.e. substantially represented, just spread thin across many simultaneous overlaps rather than concentrated in one dedicated or antipodal direction).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A convergence bug, caught and fixed — reported here because it's more useful published than hidden
&lt;/h3&gt;

&lt;p&gt;The first full run of this sweep produced a strange result at ratio=1 (where $n_{features} = n_{hidden} = 20$, so the model has &lt;em&gt;exactly&lt;/em&gt; enough capacity to represent every feature orthogonally — the correct converged answer is 100% dedicated, at every sparsity level, with no exceptions): at sparsity 0.95 and 0.99, roughly 8% and 82% of features respectively showed up as "superposed" instead. That's not a plausible finding — there is no capacity pressure whatsoever forcing superposition in this configuration — so it was investigated rather than reported. Re-running the suspicious cells at 8,000 training steps instead of the sweep's default 1,500 fully resolved the discrepancy: dedicated fraction returns to exactly $1.00 \pm 0.00$ with loss $\approx 0$ at every sparsity level. The mechanism is straightforward once seen: at high sparsity, any given feature is active in only a small fraction of training batches, so gradient signal for that feature arrives more rarely — convergence is &lt;em&gt;slower&lt;/em&gt;, not &lt;em&gt;harder&lt;/em&gt;. A flat step budget tuned for the easy (low-sparsity) cells silently under-trained the hard-to-reach-but-not-hard-to-solve ones. The fix (&lt;code&gt;steps_for_cell()&lt;/code&gt; in &lt;a href="https://github.com/mohamed-bal/superposition-to-monosemanticity/blob/main/src/part1_phase_diagram.py" rel="noopener noreferrer"&gt;&lt;code&gt;src/part1_phase_diagram.py&lt;/code&gt;&lt;/a&gt;) allocates 8,000 steps specifically to the cheap ($n_{features}=20$) ratio=1 cells at sparsity $\ge 0.9$, leaving the rest of the sweep at 1,500 steps. This is the kind of error multi-seed, sanity-checked reporting is supposed to catch — and it's reported here in full rather than quietly patched, because "we found this looked wrong, checked why, and fixed it" is exactly the epistemic standard the rest of this piece is asking readers to hold every other number to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Ratio = 1&lt;/strong&gt; ($n_{features} = n_{hidden} = 20$) — the capacity-sufficient control case:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sparsity&lt;/th&gt;
&lt;th&gt;Dedicated&lt;/th&gt;
&lt;th&gt;Superposed&lt;/th&gt;
&lt;th&gt;Final loss&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.00 – 0.99 (all 7 levels)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.00 ± 0.00&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;td&gt;$\approx 0$&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Exactly as it should be: with no capacity pressure, the model never chooses superposition, at any sparsity. This row is as much a sanity check on the whole pipeline as it is a result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ratio = 2, 4, 8&lt;/strong&gt; ($n_{features} = 40, 80, 160$) — genuine overcompleteness:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sparsity&lt;/th&gt;
&lt;th&gt;Ratio=2 dedicated&lt;/th&gt;
&lt;th&gt;Ratio=4 dedicated&lt;/th&gt;
&lt;th&gt;Ratio=8 dedicated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.00&lt;/td&gt;
&lt;td&gt;1.00 ± 0.00&lt;/td&gt;
&lt;td&gt;1.00 ± 0.00&lt;/td&gt;
&lt;td&gt;1.00 ± 0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.30&lt;/td&gt;
&lt;td&gt;0.26 ± 0.01&lt;/td&gt;
&lt;td&gt;1.00 ± 0.00&lt;/td&gt;
&lt;td&gt;1.00 ± 0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.60&lt;/td&gt;
&lt;td&gt;0.02 ± 0.02&lt;/td&gt;
&lt;td&gt;0.51 ± 0.02&lt;/td&gt;
&lt;td&gt;0.47 ± 0.07&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.80&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.90&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.95&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.99&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00&lt;/td&gt;
&lt;td&gt;0.00 ± 0.00*&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(*at ratio=8, sparsity=0.99, the 0% "dedicated" comes with 0% "superposed" too — see the diffuse-sharing finding below; the missing 100% is a different regime entirely, not an omission.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The qualitative pattern matches the theory directly: &lt;strong&gt;more overcompleteness needs less sparsity before superposition becomes the dominant regime.&lt;/strong&gt; At 2x overcompleteness, the transition is already well underway by sparsity=0.3 (74% superposed). At 4x and 8x, the transition point is later (around sparsity=0.6) but converges to a similar critical sparsity for both ratios — consistent with the idea that once superposition is "worth it" at all, further overcompleteness mostly changes &lt;em&gt;how much&lt;/em&gt; gets packed rather than &lt;em&gt;whether&lt;/em&gt; packing starts.&lt;/p&gt;

&lt;h3&gt;
  
  
  An unplanned third regime: diffuse sharing
&lt;/h3&gt;

&lt;p&gt;The most interesting cell in the entire sweep is the most extreme one: ratio=8, sparsity=0.99 (160 features into 20 dimensions, 99% of inputs zeroed per sample). Every feature there reports $D_i \approx 0.08$ — comfortably below the 0.1 "candidate not-there" threshold — which the raw classification would call "dropped." But checking $\lVert W_i \rVert^2$ directly (exactly the subtlety flagged above) tells a completely different story: mean $\lVert W_i \rVert^2 \approx 1.40$, &lt;strong&gt;larger than the norm of a single cleanly-represented orthogonal feature&lt;/strong&gt; ($\lVert W_i \rVert^2 = 1$ at the ratio=1 optimum). Every one of the 160 features is substantially represented — not remotely dropped — but in a highly symmetric, diffuse configuration where each feature overlaps a little with very many others rather than owning a dimension outright (as in the "dedicated" regime) or sharing exactly one dimension with exactly one partner (as in the antipodal "superposed" regime). Reconstruction loss at this cell is low (0.136 ± 0.009) — the model is doing a &lt;em&gt;good&lt;/em&gt; job, just via a third geometric strategy the paper's clean dedicated/antipodal/dropped trichotomy doesn't name. Whether this "many-way diffuse packing" regime is a known, previously-documented phase or a genuinely under-described corner of the phase diagram is left as an open question here — but it would not have been visible at all without checking $\lVert W_i \rVert^2$ alongside $D_i$, which is the entire reason that check was built into the pipeline in the first place rather than added after the fact.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs3vr9pgnofuf8qu1osaw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs3vr9pgnofuf8qu1osaw.png" alt="heatmap of mean $D_i$ across the full sparsity × overcompleteness grid" width="799" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3oodteh8wxn8dsuoak31.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3oodteh8wxn8dsuoak31.png" alt="stacked bar chart of dedicated/superposed/diffusely-shared/truly-dropped fractions vs. sparsity at 8x overcompleteness" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxq3ipjlthb47olzlxnzq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxq3ipjlthb47olzlxnzq.png" alt="pooled $D_i$ distributions at 8x overcompleteness across four sparsity levels, showing the shift from a single peak at $D_i=1$ (sparsity 0.0) through a genuine spread (sparsity 0.6-0.9) to the tight diffuse cluster near $D_i=0.08$ (sparsity 0.99)" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every claim above is about the &lt;em&gt;encoding&lt;/em&gt; side: given sparse features and a bottleneck, gradient descent finds a specific, geometrically characterizable, empirically reproducible way to pack more information than the bottleneck should naively allow. That's already enough to explain polysemanticity as a real, useful-to-the-model phenomenon rather than a training artifact — but it raises the obvious next question: &lt;strong&gt;if a hidden layer really is a superposed mixture of more features than it has dimensions, can anything recover the individual features back out of it?&lt;/strong&gt; That's dictionary learning, and that's where L1 sparse autoencoders and their modern TopK successors enter — including the honest, measured answer to how &lt;em&gt;well&lt;/em&gt; recovery actually works, not just whether it works at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  From encoding to recovery
&lt;/h2&gt;

&lt;p&gt;Everything so far establishes that a network &lt;em&gt;will&lt;/em&gt; pack more features than it has dimensions when those features are sparse — and characterizes the geometry of that packing precisely enough to catch a real convergence bug in our own pipeline. None of it says anything yet about whether the packing can be &lt;em&gt;undone&lt;/em&gt;. If a hidden layer really is a superposed mixture, can anything recover the individual, monosemantic features back out of it? That is the dictionary-learning question, and it has a history longer than the current interpretability boom: &lt;strong&gt;sparse coding&lt;/strong&gt; — representing a signal as a sparse combination of an overcomplete set of basis vectors ("atoms") — goes back to Olshausen &amp;amp; Field's 1996 work explaining simple-cell receptive fields in visual cortex as an emergent property of sparse coding applied to natural images. The mechanistic-interpretability version of the idea (Bricken et al., Anthropic, 2023; scaled to a production model by Templeton et al., 2024) is the same mathematical object trained on a transformer's activations instead of image patches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why L1, and what it costs you
&lt;/h3&gt;

&lt;p&gt;The natural formulation is combinatorial: find the sparsest code $f$ (fewest nonzero entries — its $L_0$ "norm") that reconstructs $h$ well. $L_0$ minimization is NP-hard in general, so the standard move — in compressed sensing, in Lasso regression, and in every SAE published before 2024 — is the convex relaxation: replace the $L_0$ penalty with an $L_1$ penalty on the code, which is the tightest convex relaxation of sparsity and is tractable by ordinary gradient-based optimization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;h_hat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;l1_coeff&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The relaxation is not free. Tibshirani (1996) — the original Lasso paper — already documents the mechanism: an $L_1$ penalty systematically shrinks &lt;em&gt;every&lt;/em&gt; coefficient toward zero, correct ones included, because the model is rewarded for making any active entry smaller purely to reduce the penalty term, independent of whether that entry's true optimal value is large. Applied to SAEs, this means an $L_1$-trained dictionary's reported activation strengths are a biased &lt;em&gt;under&lt;/em&gt;-estimate of a feature's true presence — a real, quantifiable problem, not a theoretical nicety, and the reason the field moved to an alternative.&lt;/p&gt;

&lt;h3&gt;
  
  
  TopK: sparsity without a penalty to game
&lt;/h3&gt;

&lt;p&gt;Gao et al. (OpenAI, 2024, "Scaling and Evaluating Sparse Autoencoders") propose removing the penalty term entirely and enforcing sparsity &lt;em&gt;structurally&lt;/em&gt; instead: the encoder computes pre-activations for every dictionary atom as usual, then a &lt;code&gt;TopK&lt;/code&gt; operation keeps only the $k$ largest values and zeros everything else — $k$ directly &lt;em&gt;is&lt;/em&gt; the $L_0$, chosen once, not tuned indirectly through a coefficient:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pre_act&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b_dec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;W_enc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b_enc&lt;/span&gt;
    &lt;span class="n"&gt;topk_vals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;topk_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;topk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre_act&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;topk_vals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;relu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topk_vals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zeros_like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre_act&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scatter_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;topk_idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;topk_vals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;

&lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;h_hat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# no L1 term at all
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With no penalty on activation magnitude, there is nothing for the optimizer to game by shrinking values — the only pressure on the $k$ surviving activations is to reconstruct $h$ as well as possible. TopK does introduce its own new failure mode instead of the old one: forcing exactly $k$ active features per sample means an unlucky feature can go a long time without ever being selected, and once a dictionary atom stops firing it stops receiving gradient — it "dies." Following Gao et al., this repository's TopK implementation includes a simplified auxiliary loss: dictionary atoms that haven't fired within a rolling window get a secondary reconstruction objective (fitting the current residual using only their own top activations), which gives dead atoms an occasional gradient signal instead of leaving them permanently at zero. This is a simplified version of the real auxk mechanism (production implementations track a much larger EMA-based window at far greater scale) — adequate to demonstrate the mechanism at this toy scale, not a claim of production-readiness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Head-to-head: L1 vs. TopK on the same superposed activations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;Both SAE variants are trained on activations from the &lt;em&gt;same&lt;/em&gt; toy model used for the feature-recovery study earlier in this piece — 32 features compressed into an 8-dimensional bottleneck, sparsity=0.95, decayed importance (22 of 32 features well-represented, 10 fully dropped) — with a 16x-overcomplete dictionary (128 atoms) in both cases. Every configuration below is trained across &lt;strong&gt;3 seeds&lt;/strong&gt;, reported as mean $\pm$ standard deviation, so the L1-vs-TopK comparison isn't resting on single lucky runs for either method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results: the Pareto front
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Hyperparameter&lt;/th&gt;
&lt;th&gt;$L_0$ (mean$\pm$std)&lt;/th&gt;
&lt;th&gt;Recon. loss&lt;/th&gt;
&lt;th&gt;Recovery precision (well-represented features, cos-sim $\ge$ 0.90)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;L1&lt;/td&gt;
&lt;td&gt;$\lambda=0.003$&lt;/td&gt;
&lt;td&gt;$14.68 \pm 0.58$&lt;/td&gt;
&lt;td&gt;$0.00309 \pm 0.00039$&lt;/td&gt;
&lt;td&gt;$0.15 \pm 0.06$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L1&lt;/td&gt;
&lt;td&gt;$\lambda=0.01$&lt;/td&gt;
&lt;td&gt;$10.69 \pm 0.58$&lt;/td&gt;
&lt;td&gt;$0.00334 \pm 0.00021$&lt;/td&gt;
&lt;td&gt;$0.23 \pm 0.10$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L1&lt;/td&gt;
&lt;td&gt;$\lambda=0.03$&lt;/td&gt;
&lt;td&gt;$7.90 \pm 0.73$&lt;/td&gt;
&lt;td&gt;$0.00515 \pm 0.00029$&lt;/td&gt;
&lt;td&gt;$0.27 \pm 0.07$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L1&lt;/td&gt;
&lt;td&gt;$\lambda=0.1$&lt;/td&gt;
&lt;td&gt;$4.42 \pm 0.32$&lt;/td&gt;
&lt;td&gt;$0.01427 \pm 0.00074$&lt;/td&gt;
&lt;td&gt;$0.77 \pm 0.11$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TopK&lt;/td&gt;
&lt;td&gt;$k=13$&lt;/td&gt;
&lt;td&gt;$12.92 \pm 0.07$&lt;/td&gt;
&lt;td&gt;$0.00031 \pm 0.00010$&lt;/td&gt;
&lt;td&gt;$0.11 \pm 0.06$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TopK&lt;/td&gt;
&lt;td&gt;$k=9$&lt;/td&gt;
&lt;td&gt;$8.99 \pm 0.00$&lt;/td&gt;
&lt;td&gt;$0.00060 \pm 0.00009$&lt;/td&gt;
&lt;td&gt;$0.23 \pm 0.07$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TopK&lt;/td&gt;
&lt;td&gt;$k=6$&lt;/td&gt;
&lt;td&gt;$6.00 \pm 0.00$&lt;/td&gt;
&lt;td&gt;$0.00166 \pm 0.00104$&lt;/td&gt;
&lt;td&gt;$0.53 \pm 0.13$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TopK&lt;/td&gt;
&lt;td&gt;$k=4$&lt;/td&gt;
&lt;td&gt;$4.00 \pm 0.00$&lt;/td&gt;
&lt;td&gt;$0.01064 \pm 0.00210$&lt;/td&gt;
&lt;td&gt;$\mathbf{1.00 \pm 0.00}$&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6y50s7is85r0xjy023dc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6y50s7is85r0xjy023dc.png" alt="side-by-side $L_0$-vs-reconstruction-loss and $L_0$-vs-recovery-precision plots, both with error bars across the 3 seeds" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two comparisons at matched (or near-matched) $L_0$ tell the whole story:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;At $L_0 \approx 4$:&lt;/strong&gt; TopK reaches &lt;strong&gt;perfect&lt;/strong&gt; recovery precision on the well-represented features (&lt;strong&gt;1.00 $\pm$ 0.00&lt;/strong&gt; across all 3 seeds — every single one of the 22 ground-truth features the toy model actually represents is cleanly recovered, every seed, no variance at all), against L1's $0.77 \pm 0.11$ at essentially the same sparsity level. This is not a marginal win.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;At $L_0 \approx 9$–$13$:&lt;/strong&gt; TopK's reconstruction loss is roughly an order of magnitude &lt;em&gt;lower&lt;/em&gt; than L1's at comparable sparsity ($0.0003$–$0.0006$ vs. L1's $0.003$–$0.005$), while recovery precision degrades on a similar curve for both methods as $L_0$ grows (more simultaneously active features naturally means more opportunities for cross-feature interference to corrupt any single feature's match).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TopK dominates L1 on this Pareto front — both fidelity and interpretability-relevant recovery precision, at every $L_0$ level tested — which is exactly the qualitative claim in Gao et al. (2024), reproduced here from scratch on an unrelated small synthetic model rather than taken on faith from the original production-scale paper.&lt;/p&gt;

&lt;h3&gt;
  
  
  Direct evidence of shrinkage
&lt;/h3&gt;

&lt;p&gt;The comparison above shows TopK &lt;em&gt;wins&lt;/em&gt;, but doesn't yet show &lt;em&gt;why&lt;/em&gt; — it's consistent with TopK just being a generally better sparsity mechanism for unrelated reasons. Gao et al. propose a specific, falsifiable mechanism (shrinkage) and a specific empirical test for it, reproduced exactly here: freeze which dictionary atoms an SAE selected as active for a batch of inputs (its "support"), then re-optimize &lt;em&gt;only the magnitudes&lt;/em&gt; of those already-selected atoms — via projected gradient descent with a non-negativity constraint, decoder frozen — to directly minimize reconstruction error. If the SAE's own reported activations were already optimal given its own chosen support, this refinement could not improve anything. If it &lt;em&gt;does&lt;/em&gt; improve substantially, the original magnitudes were biased.&lt;/p&gt;

&lt;p&gt;At matched sparsity ($L_0 \approx 4$, using the $k=4$ TopK model and the $\lambda=0.1$ L1 model from the table above, tested on a held-out batch of 5,000 activations):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;$L_0$&lt;/th&gt;
&lt;th&gt;MSE improvement from refinement&lt;/th&gt;
&lt;th&gt;Mean active-code magnitude change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;L1&lt;/td&gt;
&lt;td&gt;4.23&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;91.2%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+22.5%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TopK&lt;/td&gt;
&lt;td&gt;4.00&lt;/td&gt;
&lt;td&gt;64.8%&lt;/td&gt;
&lt;td&gt;$-0.05\%$ (essentially zero)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy9o671a3ug89a78furhk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy9o671a3ug89a78furhk.png" alt="bar charts of MSE improvement and magnitude change, L1 vs. TopK" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the cleanest possible confirmation of the proposed mechanism. Refining the L1 SAE's activations closes 91% of its reconstruction gap and does so by pushing magnitudes up by nearly a quarter on average — direct, quantitative evidence that the $L_1$ penalty was suppressing the true feature strengths, exactly as Tibshirani's shrinkage argument predicts. Refining the TopK SAE's activations still closes some of the gap (65% — refinement is a strictly-better-or-equal optimization by construction, so some residual improvement is expected even for an unbiased method, since the original activations were found by a single gradient-descent trajectory rather than solved exactly), but the mean magnitude of its active entries doesn't move at all (a change indistinguishable from zero, $-0.05\%$) — there is no systematic direction to correct, because there was no penalty pushing values in a systematic direction in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this changes about how to read a "found feature"
&lt;/h2&gt;

&lt;p&gt;The practical upshot for anyone applying either recipe to a real model: an $L_1$ SAE's reported activation &lt;em&gt;strength&lt;/em&gt; for a feature is not just noisy, it is &lt;strong&gt;systematically biased low&lt;/strong&gt;, in a direction and magnitude this experiment now quantifies rather than merely asserts. If a downstream system uses SAE activation magnitude for anything more than presence/absence — ranking which features matter most for a given output, thresholding an anomaly-detection signal, comparing feature strength across inputs — an $L_1$-trained dictionary's numbers need that bias kept in mind; a TopK-trained dictionary's don't carry the same known bias, though it introduces the separate, different cost of a rigid per-sample sparsity budget and the dead-latent problem that comes with it.&lt;/p&gt;

&lt;p&gt;None of this closes the loop yet. Recovery precision even for the best configuration tested here (TopK, $L_0=4$) is reported as &lt;strong&gt;1.00 on the &lt;em&gt;well-represented&lt;/em&gt; subset of features&lt;/strong&gt; — but that's still a correlational claim (does a learned direction &lt;em&gt;point at&lt;/em&gt; the right ground-truth feature?), not a causal one (does &lt;em&gt;intervening&lt;/em&gt; on that direction actually change model behavior the way the label implies?). That gap is what the rest of this piece confronts directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  From correlation to causation
&lt;/h2&gt;

&lt;p&gt;A decoder atom can be geometrically aligned with a feature's true direction in activation space without the &lt;em&gt;encoder&lt;/em&gt; ever actually activating that atom when the feature is genuinely present — two different failure modes hiding behind one cosine-similarity number. Closing that gap requires an intervention, not another measurement of the same representation.&lt;/p&gt;

&lt;h3&gt;
  
  
  The experiment: ablation and steering
&lt;/h3&gt;

&lt;p&gt;For every well-represented ground-truth feature $i$, matched by cosine similarity to a dictionary atom $j$ (exactly as in the dictionary-learning comparison, with the match's &lt;em&gt;sign&lt;/em&gt; also recovered — a real bug caught during development, below), two interventions are run, both propagated through the actual toy-model output stage ($\hat{x} = \text{ReLU}(\hat{h}W + b)$), not an arbitrary proxy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ablation:&lt;/strong&gt; present an input where &lt;em&gt;only&lt;/em&gt; feature $i$ is active, encode it through the SAE, zero out atom $j$'s code, decode, and measure how much the reconstructed output for feature $i$ specifically drops — versus how much every &lt;em&gt;other&lt;/em&gt; feature's reconstructed output moves. The ratio of these two (targeted drop over mean off-target effect) is the &lt;strong&gt;specificity ratio&lt;/strong&gt;: a causally faithful match should hit feature $i$ hard and everything else barely at all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Steering:&lt;/strong&gt; the reverse direction — present an input where feature $i$ is &lt;em&gt;off&lt;/em&gt;, force atom $j$ to a fixed positive value, and measure how much the reconstructed output for feature $i$ rises.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;f_ablated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;f_ablated&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="n"&gt;atom_idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
&lt;span class="n"&gt;h_hat_ablated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sae&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f_ablated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x_hat_ablated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;relu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h_hat_ablated&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;toy_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;toy_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;targeted_drop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x_hat_baseline&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="n"&gt;feature_idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x_hat_ablated&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="n"&gt;feature_idx&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;off_target_effect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x_hat_baseline&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x_hat_ablated&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;()[:,&lt;/span&gt; &lt;span class="n"&gt;other_features&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;specificity_ratio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;targeted_drop&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;off_target_effect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;A sign bug, caught by the test suite, worth reporting because of what it demonstrates:&lt;/strong&gt; cosine-similarity matching (&lt;code&gt;best_match_cosine_similarity&lt;/code&gt;, used throughout this piece) takes the &lt;em&gt;absolute value&lt;/em&gt; of cosine similarity, because a feature and its exact negation are equally good correlational matches — sensible for measuring recovery, but wrong for an intervention, which is direction-sensitive. The first version of the steering test always pushed the matched atom toward $+1$, silently assuming a positive match. &lt;code&gt;test_steering_effect_runs_and_returns_expected_keys&lt;/code&gt; caught this immediately: on a deliberately simple sanity-check model, the induced effect came back as exactly &lt;code&gt;0.0&lt;/code&gt; instead of positive, because the actual match happened to be &lt;em&gt;anti&lt;/em&gt;-aligned (the dominant weight was $-0.82$, not $+0.82$) — steering "on" in the wrong direction pushed the reconstruction toward an invalid negative input region, which the ReLU output clips straight to zero. The fix (&lt;code&gt;best_match_indices_and_signs&lt;/code&gt;) recovers the signed match explicitly rather than assuming positive, and &lt;code&gt;steering_effect&lt;/code&gt; now requires that sign as an argument so the bug can't quietly reappear through the same code path. This is the second real bug this piece has caught through its own test suite and multi-seed validation discipline (the first was the ratio=1 convergence artifact in the phase diagram) — reported in full both times because a piece about measuring interpretability honestly should hold its own pipeline to the same standard it's applying to the SAEs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results: does a good correlational match predict a good causal match?
&lt;/h3&gt;

&lt;p&gt;Two SAEs from the earlier Pareto front, at opposite ends of it: &lt;strong&gt;TopK, $k=4$&lt;/strong&gt; (recovery precision 1.00, the best configuration found) and &lt;strong&gt;TopK, $k=13$&lt;/strong&gt; (recovery precision 0.11, deliberately poor). For every one of the 22 well-represented features, both an ablation and a steering intervention are run on the atom each SAE matched to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyol3gdi3f8xwafxwdbnu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyol3gdi3f8xwafxwdbnu.png" alt="left: boxplot of ablation specificity ratio, good vs. bad SAE (symlog scale, since some values are exactly zero or negative); right: scatter of cosine similarity vs. specificity ratio for both SAEs together" width="799" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SAE&lt;/th&gt;
&lt;th&gt;Median ablation specificity&lt;/th&gt;
&lt;th&gt;Min&lt;/th&gt;
&lt;th&gt;Max&lt;/th&gt;
&lt;th&gt;Median steering specificity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TopK, $k=4$ (good, precision 1.00)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;168.8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;2608.6&lt;/td&gt;
&lt;td&gt;149.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TopK, $k=13$ (bad, precision 0.11)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$-902.5$&lt;/td&gt;
&lt;td&gt;163.0&lt;/td&gt;
&lt;td&gt;21.4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The headline number: the good SAE's median specificity ratio (168.8 — ablating the matched atom drops the targeted feature's output roughly 169 times more than it moves every other feature, on average) against the bad SAE's median of &lt;strong&gt;exactly zero&lt;/strong&gt;. Correlation between cosine similarity and log-specificity across both SAEs combined: $r = 0.657$ — a real, meaningfully positive relationship (a better correlational match does predict a better causal match, on average), but nowhere near $r=1$, and the exceptions are the informative part.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why the bad SAE's median is exactly zero, not just small
&lt;/h3&gt;

&lt;p&gt;Seventeen of the bad SAE's 22 matched pairs show &lt;code&gt;ablation_specificity_ratio == 0.0&lt;/code&gt; &lt;em&gt;exactly&lt;/em&gt; — not approximately, not "small but nonzero." Investigating why (&lt;code&gt;atom_fired_frac&lt;/code&gt;, tracked in &lt;code&gt;ablation_effect&lt;/code&gt; alongside the specificity ratio) gives an unambiguous answer: in every one of those seventeen cases, &lt;strong&gt;the matched atom never fires at all&lt;/strong&gt; when the corresponding ground-truth feature is presented in isolation ($\text{atom_fired_frac} = 0.0$ across 500 test samples). Ablating a code entry that was already exactly zero cannot change anything — the specificity ratio isn't small, it's undefined-and-reported-as-zero, for a completely different reason than "the effect is weak." One of these seventeen (feature 20) even has a cosine similarity of $0.92$ — comfortably above the $\ge 0.90$ threshold used throughout to call a feature "recovered." &lt;strong&gt;By the correlational metric used everywhere else in this piece, feature 20 counts as a recovery success. By the causal test, the atom credited with recovering it never once activates for that feature.&lt;/strong&gt; This is not a rare edge case dredged up after the fact — it's 17 of 22 pairs for the low-precision SAE, and it is the single most important finding here for anyone tempted to treat a cosine-similarity match as sufficient evidence on its own.&lt;/p&gt;

&lt;p&gt;The good SAE shows the same failure mode, just far more rarely: 2 of its 22 matches (features 5 and 6, both with cosine similarity $&amp;gt; 0.9999$ — as close to a perfect geometric match as this experiment produces) also have &lt;code&gt;atom_fired_frac = 0.0&lt;/code&gt;. Even the best configuration tested here is not immune to "geometrically perfect, causally inert" matches — it just has the problem at a 9% rate instead of a 77% rate.&lt;/p&gt;

&lt;h3&gt;
  
  
  What "decoder direction" and "encoder activation" are actually measuring
&lt;/h3&gt;

&lt;p&gt;The mechanism is straightforward in hindsight, and worth naming precisely because it generalizes past this toy setup: cosine-similarity matching, as used throughout this piece (and in the real interpretability literature it reproduces), compares ground-truth directions against &lt;strong&gt;decoder&lt;/strong&gt; dictionary atoms ($W_{dec}$) — the vectors used to &lt;em&gt;reconstruct&lt;/em&gt; activations from a code. Whether an atom's corresponding &lt;strong&gt;encoder&lt;/strong&gt; entry actually &lt;em&gt;fires&lt;/em&gt; for a given input is a separate question, governed by the encoder weights and the TopK/ReLU selection mechanism, not by the decoder geometry at all. A high-$L_0$ SAE under real pressure to reconstruct well can apparently learn a decoder atom that sits at the geometrically "correct" location for reconstruction purposes — useful for the &lt;em&gt;reconstruction&lt;/em&gt; objective the SAE is actually trained on — while its paired encoder entry essentially never wins the TopK competition for that specific feature, because something else usually wins first. Decoder-geometry recovery and encoder-activation recovery are two different empirical claims that this piece's earlier correlational metric could not, by construction, tell apart — only an intervention can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production framework: what this changes about deploying any of this
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Decision framework
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Validation level&lt;/th&gt;
&lt;th&gt;What it actually establishes&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;What it still can't tell you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cosine similarity to a known ground truth (only possible in a toy setting)&lt;/td&gt;
&lt;td&gt;Decoder geometry alignment&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;td&gt;Whether the encoder ever activates that atom for the matching input at all&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Published open-weight SAE + qualitative "does this feature look interpretable" review&lt;/td&gt;
&lt;td&gt;A human-plausible story for what a feature means&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Whether the story is causally load-bearing or a post-hoc rationalization of a spurious correlation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Activation patching / ablation on your own model (the methodology demonstrated in this piece, applied to a real model)&lt;/td&gt;
&lt;td&gt;Causal specificity — does intervening on this feature change the targeted behavior more than everything else?&lt;/td&gt;
&lt;td&gt;Highest (requires a working intervention harness on your actual model, not just an evaluation script)&lt;/td&gt;
&lt;td&gt;Whether the &lt;em&gt;effect&lt;/em&gt; you're seeing is the &lt;em&gt;mechanism&lt;/em&gt; you think it is, versus a correlate of it — causal specificity within your test distribution doesn't guarantee it holds out of distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Where SAE-based signals belong in a real system
&lt;/h3&gt;

&lt;p&gt;Given everything measured in this piece, the responsible design for any production use is narrow: an SAE-derived signal (anomalous feature co-activation, a feature flagged as correlating with a risky behavior) is a &lt;strong&gt;routing signal for closer review&lt;/strong&gt;, layered on top of — never substituting for — existing output-level safety filtering. Concretely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Never gate an automated action directly on raw SAE feature activation.&lt;/strong&gt; Given this piece's own measurement that 17 of 22 correlationally-matched features in a realistic (imperfect) SAE configuration turned out causally inert, an automated pipeline trusting activation-magnitude-as-ground-truth would be acting on noise disguised as signal a majority of the time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any feature used for monitoring or steering needs its own causal validation pass&lt;/strong&gt; (ablation and/or steering, exactly as in this piece) before being trusted — a cosine-similarity match to a hand-labeled or LLM-labeled concept is not sufficient evidence on its own, precisely because this experiment shows concretely how often it isn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-run causal validation whenever the SAE is retrained&lt;/strong&gt;, not just once at deployment — a decoder atom's causal relationship to a labeled concept is a property of one specific trained checkpoint, not a property of the "feature" as an abstract, portable concept.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version-pin an SAE checkpoint to the exact model checkpoint and data distribution it was validated against&lt;/strong&gt;, same discipline as any other derived-artifact-from-a-model-checkpoint.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security and epistemic notes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A geometric match is not a causal claim, and this piece now has a concrete, quantified demonstration of exactly how far apart the two can be&lt;/strong&gt; — not a hypothetical caveat, a measured 77% divergence rate in one realistic configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The interpretability-adversarial-robustness question raised at the start of this piece remains open, and this finding sharpens why it matters:&lt;/strong&gt; if decoder-geometry alignment can diverge this far from encoder-activation reality &lt;em&gt;without any adversarial pressure at all&lt;/em&gt; — purely as an ordinary training-dynamics artifact — a model under actual incentive to obscure a mechanism from interpretability tooling has an even larger space of "geometrically plausible, causally misleading" solutions available to it than this experiment explores.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat every SAE-derived interpretability claim, including every one in this piece, as tied to the specific checkpoint, sparsity setting, and validation method that produced it.&lt;/strong&gt; A number that held for TopK at $k=4$ on this toy model is not a license to assume the same causal reliability for a different $k$, a different model, or a different training run — the whole point of measuring the $k=4$ vs. $k=13$ gap directly was to make that non-transferability concrete rather than asserted.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations, stated directly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Every quantitative claim in this piece comes from small, fully synthetic toy models — real transformer residual streams involve orders of magnitude more features, genuine cross-layer and cross-token structure, and, critically, no accessible ground truth to validate against the way this piece repeatedly did. The toy setting is what makes rigorous validation &lt;em&gt;possible&lt;/em&gt;; it is also exactly what makes every absolute number here a calibration point for the easy case, not a benchmark for a production model.&lt;/li&gt;
&lt;li&gt;The causal validation methodology above uses feature &lt;em&gt;isolation&lt;/em&gt; (only one ground-truth feature active at a time) to get a clean read on specificity — real inputs to a real model activate many features simultaneously, and interaction effects between simultaneously-active features are not tested here at all.&lt;/li&gt;
&lt;li&gt;Two real bugs were caught and fixed during this piece's own development (the ratio=1 phase-diagram convergence artifact, and the steering sign-convention bug) — both are reported here in full because they were caught, not because the pipeline is now guaranteed bug-free. A third, uncaught issue of the same character is not a hypothetical risk; it's the expected steady-state for any codebase of comparable complexity, and the honest response is the testing discipline demonstrated throughout, not a claim of completeness.&lt;/li&gt;
&lt;li&gt;Sample sizes for the causal experiments (22 well-represented features, 2 SAE configurations) are small enough that the exact specificity numbers should be read as "this is the shape of the effect, measured once, on this model" rather than as a tight statistical estimate — the qualitative finding (correlational match quality is informative but leaves a large, characterizable gap) is the reproducible claim, not the precise value 168.8.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing synthesis
&lt;/h2&gt;

&lt;p&gt;Three claims, each checked by an experiment rather than asserted, and each holding up with a real, quantified limitation attached: sparse features get packed non-orthogonally into a smaller space when doing so is cheap under sparsity, in a geometric pattern precise enough that a bug in reproducing it was catchable by comparing against the theoretically-required answer; an overcomplete sparse autoencoder can partially undo that packing, with TopK's structural sparsity mechanism dominating the older L1 penalty's Pareto front for a specific, mechanistically-identified reason (shrinkage) rather than by unexplained magic; and a geometric recovery, even a very good one, is not yet a causal one, by a margin this piece measured directly rather than gestured at. None of the three claims required taking the literature's word for it, and none of them came back "trivially true" once measured — the phase diagram had a real convergence bug hiding in it, the shrinkage measurement needed the right $L_0$ regime to show a clean signal, and the causal validation surfaced a 77%-divergence finding nobody was looking for going in. That — measure it, expect the measurement to complicate the clean story somewhat, report the complication anyway — is the actual discipline mechanistic interpretability is asking practitioners to adopt, at whatever scale they're working at.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Olshausen, B. A. &amp;amp; Field, D. J. (1996), "Emergence of simple-cell receptive field properties by learning a sparse code for natural images," &lt;em&gt;Nature&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Tibshirani, R. (1996), "Regression Shrinkage and Selection via the Lasso," &lt;em&gt;Journal of the Royal Statistical Society&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Elhage, N. et al. (2022), &lt;a href="https://transformer-circuits.pub/2022/toy_model/index.html" rel="noopener noreferrer"&gt;"Toy Models of Superposition,"&lt;/a&gt; Anthropic.&lt;/li&gt;
&lt;li&gt;Bricken, T. et al. (2023), &lt;a href="https://transformer-circuits.pub/2023/monosemantic-features/index.html" rel="noopener noreferrer"&gt;"Towards Monosemanticity: Decomposing Language Models With Dictionary Learning,"&lt;/a&gt; Anthropic.&lt;/li&gt;
&lt;li&gt;Templeton, A. et al. (2024), &lt;a href="https://transformer-circuits.pub/2024/scaling-monosemanticity/" rel="noopener noreferrer"&gt;"Scaling Monosemanticity: Extracting Interpretable Features from Claude 3 Sonnet,"&lt;/a&gt; Anthropic.&lt;/li&gt;
&lt;li&gt;Gao, L. et al. (2024), &lt;a href="https://arxiv.org/abs/2406.04093" rel="noopener noreferrer"&gt;"Scaling and Evaluating Sparse Autoencoders,"&lt;/a&gt; arXiv:2406.04093.&lt;/li&gt;
&lt;li&gt;Rajamanoharan, S. et al. (2024), "Improving Dictionary Learning with Gated Sparse Autoencoders," arXiv:2404.16014.&lt;/li&gt;
&lt;li&gt;Bussmann, B. et al. (2024), "BatchTopK Sparse Autoencoders," arXiv:2412.06410.&lt;/li&gt;
&lt;li&gt;Lieberum, T. et al. (2024), "Gemma Scope: Open Sparse Autoencoders Everywhere All at Once on Gemma 2," arXiv:2408.05147.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/pdf/2404.14082" rel="noopener noreferrer"&gt;"Mechanistic Interpretability for AI Safety — A Review,"&lt;/a&gt; arXiv:2404.14082.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>Quantum-Inspired, Not Quantum: The Physics of Tensor Networks Behind Production LLM Compression</title>
      <dc:creator>Mohamed Bal</dc:creator>
      <pubDate>Sat, 04 Jul 2026 23:28:08 +0000</pubDate>
      <link>https://dev.to/mohamed_bal/quantum-inspired-not-quantum-the-physics-of-tensor-networks-behind-production-llm-compression-14fh</link>
      <guid>https://dev.to/mohamed_bal/quantum-inspired-not-quantum-the-physics-of-tensor-networks-behind-production-llm-compression-14fh</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;⚙️ Show me the code:&lt;/strong&gt; The complete, production-ready PyTorch implementation (TT-SVD linear layer) discussed in this article is available on GitHub: &lt;a href="https://github.com/mohamed-bal/tt-linear-pytorch" rel="noopener noreferrer"&gt;mohamed-bal/tt-linear-pytorch&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  One clarification before anything else: "Quantum-Inspired" ≠ "Quantum Computing"
&lt;/h2&gt;

&lt;p&gt;This has to be stated with zero ambiguity, because the framing risks misleading readers otherwise: every technique in this piece &lt;strong&gt;runs on ordinary GPUs, today, in production&lt;/strong&gt;. The word "quantum" here refers to the mathematical/physical &lt;em&gt;origin&lt;/em&gt; of the toolkit — tools originally built to simulate many-body quantum systems on classical computers — not to actual qubit hardware.&lt;/p&gt;

&lt;p&gt;The real state of quantum hardware as of mid-2026: we're squarely in the &lt;a href="https://originqc.com/blogs/nisq-era-status-2026" rel="noopener noreferrer"&gt;late-NISQ&lt;/a&gt; (Noisy Intermediate-Scale Quantum) era — roughly 50–200 physical qubits, gate error rates in the 10⁻³ to 10⁻² range, no genuine fault tolerance. Production-scale, error-corrected systems are projected for a 2030–2035 window. In plain terms: &lt;strong&gt;no real quantum computer today reduces RAM for any LLM in any production datacenter.&lt;/strong&gt; Any claim to the contrary is either wrong or marketing.&lt;/p&gt;

&lt;p&gt;What actually exists is a full mathematical discipline called &lt;strong&gt;tensor networks&lt;/strong&gt; — machinery built by condensed-matter physicists between roughly 1990 and 2011 to solve intractable quantum many-body problems, adapted by ML researchers to neural network weight matrices starting in 2015, and applied specifically to LLMs starting in 2023–2024. That's the real subject of this piece.&lt;/p&gt;

&lt;h2&gt;
  
  
  The original physics problem: why the Density Matrix Renormalization Group (DMRG) worked
&lt;/h2&gt;

&lt;p&gt;In 1992, Steven White introduced DMRG to compute ground states of one-dimensional quantum spin chains. The problem: the Hilbert space of an L-site system with local dimension d grows as d^L — catastrophic exponential growth. The fix rested on a precise physical observation called the &lt;strong&gt;Area Law&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Precise statement:&lt;/strong&gt; for the ground state of a local Hamiltonian with an energy gap, the entanglement entropy between two partitions of the system scales with the &lt;strong&gt;boundary area&lt;/strong&gt; separating them, not with volume. In 1D, the "area" between two blocks is a single point (zero-dimensional) — meaning the entropy &lt;strong&gt;doesn't grow with system size at all&lt;/strong&gt;, it stays bounded.&lt;/p&gt;

&lt;p&gt;Formally: split a system into A and B, form the reduced density matrix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ρ_A = Tr_B(|Ψ⟩⟨Ψ|)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and compute the von Neumann entanglement entropy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S(ρ_A) = -Tr(ρ_A ln ρ_A)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://arxiv.org/abs/0808.3773" rel="noopener noreferrer"&gt;area law&lt;/a&gt; says S stays &lt;strong&gt;bounded&lt;/strong&gt; regardless of the size of A — it doesn't scale up with it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwoq8c3vpts3y4okc4g5y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwoq8c3vpts3y4okc4g5y.png" alt="The area law: in a 1D chain the boundary between two regions is a single point, so entanglement entropy stays bounded; in a 2D lattice the boundary is the perimeter, so entropy scales with L, not L²." width="799" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Matrix Product States (MPS) and Bond Dimension: where physics meets computation
&lt;/h2&gt;

&lt;p&gt;Why does this matter computationally? Because any quantum state obeying the area law can be represented exactly by a &lt;strong&gt;Matrix Product State (&lt;a href="http://itensor.org/docs.cgi?page=tutorials%2FInfoTheory&amp;amp;vers=julia" rel="noopener noreferrer"&gt;MPS&lt;/a&gt;)&lt;/strong&gt; — a chain of tensors linked by a &lt;strong&gt;bond dimension&lt;/strong&gt; (denoted χ or D). The precise relationship between bond dimension and entropy, &lt;a href="https://www.ifsc.usp.br/bssm/wp-content/uploads/2023/01/DMRG-03-MPS.pdf" rel="noopener noreferrer"&gt;worked through in detail here&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S ≤ 2 ln(D)        (a strict bound for any bipartition in an MPS)
χ ~ exp(S)          (the required bond dimension grows exponentially with entropy)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The practical payoff: if entropy S stays bounded — as guaranteed by the area law in 1D gapped systems — the required bond dimension &lt;strong&gt;stays constant&lt;/strong&gt; even as system size grows. DMRG (at O(χ³) cost per step) then runs in &lt;strong&gt;polynomial&lt;/strong&gt; time instead of exponential. That's precisely why DMRG has dominated quantum many-body simulation for over 30 years.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3zf6agifcadnff6izbsj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3zf6agifcadnff6izbsj.png" alt="A five-site Matrix Product State: tensors connected by bonds of dimension χ, with open physical legs of dimension d. Exact storage grows as O(d^N); MPS storage at fixed χ grows only as O(N·d·χ²) — this truncation is the entire compression mechanism." width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 2D extension is harder: &lt;strong&gt;Projected Entangled Pair States (PEPS)&lt;/strong&gt; generalize MPS to 2D lattices. The area law here states entropy scales with the region's &lt;strong&gt;perimeter&lt;/strong&gt;, not its area — for an L×L square block with bond dimension χ, the entropy bound is L·log(χ) (proportional to L, not L²). But the cost: the bond dimension needed &lt;em&gt;within&lt;/em&gt; PEPS itself grows exponentially with system width — computation is far harder than plain MPS. That's exactly why LLM compression researchers reach for &lt;strong&gt;iPEPS + Tensor Renormalization Group (TRG)&lt;/strong&gt; rather than plain MPS when they need to capture multi-directional correlations (like those in attention layers) instead of simple linear correlations (like those in embedding tables).&lt;/p&gt;

&lt;h2&gt;
  
  
  From condensed-matter physics to weight matrices: the actual bridge
&lt;/h2&gt;

&lt;p&gt;The central claim this entire research direction rests on: &lt;strong&gt;trained (not random) neural network weight matrices exhibit low effective entanglement/correlation structure&lt;/strong&gt; — meaning their real information content is far smaller than the raw parameter count suggests.&lt;/p&gt;

&lt;p&gt;This isn't a philosophical assumption — it has direct empirical backing. The &lt;a href="https://www.researchgate.net/publication/396966873_KARIPAP_Quantum-Inspired_Tensor_Network_Compression_of_Large_Language_Models_Using_Infinite_Projected_Entangled_Pair_States_and_Tensor_Renormalization_Group" rel="noopener noreferrer"&gt;&lt;strong&gt;KARIPAP&lt;/strong&gt;&lt;/a&gt; paper (October 2025, iPEPS + TRG) ran "layer-wise entanglement profiling" on LLaMA-2 7B — measuring actual entropy layer by layer — and found clear &lt;strong&gt;redundancy concentrated in deeper layers&lt;/strong&gt;. The practical result: 93% memory reduction, 70% parameter reduction, with only 2–3% accuracy loss.&lt;/p&gt;

&lt;p&gt;One technical distinction worth making precisely: this is &lt;strong&gt;not&lt;/strong&gt; the same thing as ordinary low-rank decomposition (a plain 2D SVD). Tensor networks — specifically &lt;strong&gt;MPO (Matrix Product Operator)&lt;/strong&gt;, the operator-space variant applied to weight matrices rather than states — generalize the idea: reshape the matrix into a higher-order tensor and capture correlations across &lt;em&gt;multiple dimensions simultaneously&lt;/em&gt;, not just one. That's exactly why &lt;a href="https://arxiv.org/abs/2307.00526" rel="noopener noreferrer"&gt;&lt;strong&gt;TensorGPT&lt;/strong&gt;&lt;/a&gt; (2023) targeted the embedding layer specifically — embedding tables have a natural hierarchical structure (word → subword → character) that maps cleanly onto a tensor-train factorization, an approach that traces back to &lt;a href="https://arxiv.org/abs/1509.06569" rel="noopener noreferrer"&gt;Novikov et al.'s original "Tensorizing Neural Networks"&lt;/a&gt; (2015).&lt;/p&gt;

&lt;h2&gt;
  
  
  The second thread: Disentanglers — removing correlation before compressing
&lt;/h2&gt;

&lt;p&gt;A deeper technique from &lt;a href="https://arxiv.org/abs/2410.17397" rel="noopener noreferrer"&gt;&lt;strong&gt;"Quantum Large Language Models via Tensor Network Disentanglers"&lt;/strong&gt;&lt;/a&gt; (Aizpurua et al., 2024): inspired by &lt;strong&gt;MERA&lt;/strong&gt; (Multi-scale Entanglement Renormalization Ansatz). Instead of compressing directly, apply &lt;strong&gt;local unitary transformations&lt;/strong&gt; (disentanglers) first to strip out short-range entanglement, so that the subsequent coarse-graining only has to deal with the remaining long-range structure — which is much cheaper to compress. Practically: if two adjacent transformer layers carry redundant correlation, remove that redundancy with a cheap local transform first, and the actual compression step operates on what's left — producing a more accurate result than compressing directly with no such pre-processing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The third thread (and a genuinely different one): Dequantization — what it actually means, and what it doesn't
&lt;/h2&gt;

&lt;p&gt;This is where precision matters most, because two very different things get conflated constantly.&lt;/p&gt;

&lt;p&gt;In 2018, &lt;a href="https://arxiv.org/abs/1807.04271" rel="noopener noreferrer"&gt;Ewin Tang&lt;/a&gt; — then a 17-year-old undergraduate — did something remarkable: she took a quantum algorithm that was considered one of the strongest candidates for a &lt;em&gt;provable exponential speedup&lt;/em&gt; in quantum machine learning (Kerenidis-Prakash's quantum recommendation system), and proved the same result was achievable &lt;strong&gt;classically&lt;/strong&gt; — a classical algorithm that, given a data structure supporting ℓ²-norm sampling, produces a rank-k approximation sample in O(poly(k)·log(mn)) time — only polynomially slower than the quantum version, not exponentially. Consequence: Kerenidis-Prakash's algorithm did &lt;strong&gt;not&lt;/strong&gt; actually deliver an exponential speedup over classical computation — the claimed advantage rested on a strong assumption about the input data structure, not on quantum mechanics itself. The work was later generalized (&lt;a href="https://arxiv.org/abs/1910.06151" rel="noopener noreferrer"&gt;Chia, Gilyén, Li, Lin, Tang, Wang&lt;/a&gt; — STOC 2020, JACM 2022) into a full framework for "dequantizing" a broad class of quantum SVT (Singular Value Transformation) algorithms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The necessary distinction:&lt;/strong&gt; dequantization is a &lt;strong&gt;computational complexity theory&lt;/strong&gt; result — it answers "what can we compute classically at the same speed as quantum?" — not a published, production LLM compression technique. Tang herself put it plainly: "If you are a classical person, you would not do this pre-processing." The ℓ²-sampling data structure these algorithms require is expensive to build, and raw weight matrices in any real LLM don't arrive in that form. So: &lt;strong&gt;no production system today uses dequantized algorithms to reduce LLM RAM footprint&lt;/strong&gt; — unlike MPO/tensor-train decomposition, which genuinely is deployed (CompactifAI, KARIPAP, TensorGPT).&lt;/p&gt;

&lt;p&gt;The real value of dequantization in this context: it establishes &lt;strong&gt;fundamental lower bounds&lt;/strong&gt; on any low-rank matrix operation — it tells you precisely where genuine speedup (quantum or classical) ends and where the hard floor begins. That's valuable for designing any new compression algorithm (you know upfront what's realistically achievable versus mathematically impossible), but it isn't something you drop into an inference pipeline today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bond Dimension as the real "RAM knob"
&lt;/h2&gt;

&lt;p&gt;The point that ties all of this to production engineering: &lt;strong&gt;bond dimension χ is the one practical lever&lt;/strong&gt; controlling the tradeoff between compression ratio and model accuracy — the 93%-memory-reduction-for-2–3%-accuracy-loss figure (&lt;a href="https://www.researchgate.net/publication/396966873_KARIPAP_Quantum-Inspired_Tensor_Network_Compression_of_Large_Language_Models_Using_Infinite_Projected_Entangled_Pair_States_and_Tensor_Renormalization_Group" rel="noopener noreferrer"&gt;KARIPAP&lt;/a&gt;) is simply &lt;strong&gt;one measured point on the χ curve&lt;/strong&gt;. Smaller χ means more compression and more accuracy loss — and the relationship isn't linear, it tracks the actual entropy of each layer (as layer-wise profiling shows).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fluxsoyoxbufllbngog9q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fluxsoyoxbufllbngog9q.png" alt="Compression-vs-accuracy tradeoff curve: accuracy loss stays low for a long stretch as memory reduction increases, then rises sharply near extreme compression. The KARIPAP result (93% memory reduction, 2-3% accuracy loss) sits in the favorable region before that knee." width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What follows is how to actually choose χ per layer in production (not one global number), how this combines with the quantization techniques (INT4/INT8/FP8) and KV-cache compression already deployed in DeepSeek/MiniMax, and CXL memory disaggregation architecture in datacenters — with real, production-grade PyTorch code for applying tensor-train decomposition to a weight matrix, complete with error handling and memory profiling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The following implementation, along with the full test suite and layer profiling utilities, is available as an installable package in the &lt;a href="https://github.com/mohamed-bal/tt-linear-pytorch" rel="noopener noreferrer"&gt;tt-linear-pytorch GitHub repository&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  From bond dimension to a real PyTorch layer
&lt;/h2&gt;

&lt;p&gt;Everything in this section has been numerically verified against a dense-matrix reference before being written here — reconstruction error drops to ~1e-6 at full rank and degrades predictably as χ is truncated, and the efficient forward pass matches &lt;code&gt;nn.Linear&lt;/code&gt; exactly at full rank. This is TT-matrix decomposition (Oseledets 2011; TTM form per Novikov et al.) implemented as a drop-in replacement for &lt;code&gt;nn.Linear&lt;/code&gt;, with the forward pass computed by contracting TT-cores directly — the dense &lt;code&gt;(O, I)&lt;/code&gt; matrix is never materialized, which is the entire point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
tt_linear.py — TT-matrix (tensor-train) compressed linear layer.

Implements TT-SVD decomposition (Oseledets, 2011) in TT-matrix / TTM form
(Novikov et al., &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tensorizing Neural Networks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, 2015) and a drop-in nn.Linear
replacement whose forward pass never materializes the dense weight matrix.

Numerically verified: at full rank, reconstruction error and forward-pass
output match a dense nn.Linear to ~1e-6 relative error (float32).
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch.nn&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;

&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TTMatrixConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Factorization spec for a TT-matrix layer.

    out_factors / in_factors: dimension factorizations such that
        prod(out_factors) == out_features
        prod(in_factors)  == in_features
    ranks: internal bond dimensions, length == len(out_factors) - 1
           (boundary ranks r_0 = r_d = 1 are implicit, not listed here).
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;ranks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__post_init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out_factors (len=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) and in_factors &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(len=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) must have the same length.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ranks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ranks must have length &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;got &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ranks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ranks&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all ranks must be &amp;gt;= 1.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all factors must be &amp;gt;= 1.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;out_features&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;in_features&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;max_ranks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Theoretical max useful rank at each internal cut — exceeding this
        wastes parameters without adding representational power (confirmed
        empirically: reconstruction error saturates past this point).&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:])&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_against&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Raise if this config doesn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t actually factorize the target layer shape.
        Call this before decomposing any real weight — a silent shape mismatch
        here is a correctness bug, not something to coerce or truncate around.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_features&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;out_features&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_features&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;in_features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Config factorizes (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_features&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_features&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;), &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;but target layer is (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;out_features&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;in_features&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;max_r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max_ranks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;requested&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ranks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_r&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;requested&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Requested rank &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;requested&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; exceeds theoretical max &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;at this cut — reduce ranks or this factorization is wasting parameters.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tt_svd_decompose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TTMatrixConfig&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Decompose a dense (out_features, in_features) weight matrix into TT-cores.

    core[k] has shape (r_{k-1}, out_factors[k], in_factors[k], r_k), with
    r_0 = r_d = 1. Uses sequential SVD (TT-SVD); the last core absorbs the
    remainder directly with no further truncation, since r_d = 1 by construction.

    Raises:
        ValueError: if `config` doesn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t factorize `weight`&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s actual shape.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;out_f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in_f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ranks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ranks&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate_against&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;full_ranks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ranks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;tensor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;interleave_perm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;permute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interleave_perm&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contiguous&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;left_dim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;m_k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;out_f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;in_f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;mat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left_dim&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;m_k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Vh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;svd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;full_matrices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LinAlgError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# SVD failure here almost always means NaN/Inf already present
&lt;/span&gt;                &lt;span class="c1"&gt;# in the source weights — surface that clearly instead of a
&lt;/span&gt;                &lt;span class="c1"&gt;# cryptic LAPACK error.
&lt;/span&gt;                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SVD failed decomposing core &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;; check the source weight &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tensor for NaN/Inf before decomposing.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;

            &lt;span class="n"&gt;r_k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full_ranks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;core&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;r_k&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left_dim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;in_f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;r_k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;remainder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;diag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;r_k&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;Vh&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;r_k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:]&lt;/span&gt;
            &lt;span class="n"&gt;trailing_shape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;in_f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;remainder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;r_k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;trailing_shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;left_dim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r_k&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left_dim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;in_f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cores&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tt_forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;y = x @ W^T for W implicit in TT-cores — the dense matrix is never formed.

    x: (batch, in_features). Returns (batch, out_features).
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;n_out_so_far&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;core&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;core2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;squeeze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# (o_k, i_k, r_k); r_prev == 1
&lt;/span&gt;            &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;movedim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tensordot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;core2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dims&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
            &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;movedim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;i_k_axis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n_out_so_far&lt;/span&gt;
            &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;movedim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i_k_axis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# -&amp;gt; (..., r_prev, i_k)
&lt;/span&gt;            &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tensordot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dims&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
            &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;movedim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n_out_so_far&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;n_out_so_far&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;squeeze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# drop trailing r_d == 1
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TTLinear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Drop-in replacement for nn.Linear backed by TT-matrix cores.

    Construct via `TTLinear.from_dense(existing_linear, config)` to compress
    an already-trained layer, or directly for training a TT-native layer
    from random init.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TTMatrixConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;
        &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dtype&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;device&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ParameterList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;full_ranks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ranks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full_ranks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;full_ranks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="c1"&gt;# Xavier-ish scaling per core keeps the product's variance sane at init.
&lt;/span&gt;            &lt;span class="n"&gt;core&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;full_ranks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_features&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bias&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="nd"&gt;@classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;from_dense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TTMatrixConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TTLinear&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Compress an existing trained nn.Linear into TT-matrix form.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate_against&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_features&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_features&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bias&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bias&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;no_grad&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;decomposed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tt_svd_decompose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detach&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;core_param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;core_value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decomposed&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;core_param&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bias&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bias&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bias&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detach&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;orig_shape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;
        &lt;span class="n"&gt;x2d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orig_shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tt_forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x2d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_factors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bias&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bias&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;orig_shape&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_features&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compression_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Parameter/byte comparison against the equivalent dense nn.Linear —
        run this before deploying a given rank choice, not after.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;dense_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out_features&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_features&lt;/span&gt;
        &lt;span class="n"&gt;tt_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;numel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;bytes_per_elem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cores&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;element_size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dense_params&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dense_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tt_params&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tt_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;compression_ratio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tt_params&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;dense_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dense_bytes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dense_params&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bytes_per_elem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tt_bytes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tt_params&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bytes_per_elem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Choosing χ per layer: don't guess a global number
&lt;/h2&gt;

&lt;p&gt;The test that matters before trusting any of this on real weights: &lt;strong&gt;a random matrix has no compressible structure&lt;/strong&gt;, and TT-decomposition correctly refuses to compress it — reconstruction error only drops to near-zero once rank approaches the theoretical maximum, at which point the TT format actually costs &lt;em&gt;more&lt;/em&gt; parameters than dense storage (verified above: at full rank on a random 64×64 matrix, TT storage was 2x the dense size). This is expected and correct — it's the same distinction from the theory section: entropy is bounded for &lt;em&gt;trained&lt;/em&gt; weights with real correlation structure, not for random ones. Compression only pays off where the entropy actually is low, which is a layer-by-layer, empirical question, not a global constant.&lt;/p&gt;

&lt;p&gt;The correct procedure for picking χ on a real trained layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;profile_layer_compressibility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TTMatrixConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sample_batch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tensor&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Run before deciding a layer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s rank in production: measures reconstruction
    error AND functional error (output divergence on real activations, not just
    weight Frobenius norm) at the requested rank.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;tt_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TTLinear&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_dense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;no_grad&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;dense_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample_batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;tt_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tt_layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample_batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;functional_rel_error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dense_out&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;tt_out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dense_out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tt_layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compression_report&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;functional_rel_error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;functional_rel_error&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this per layer with a small batch of &lt;em&gt;real&lt;/em&gt; activations (not synthetic noise — the whole point is that real activations reveal the actual low-entanglement structure), sweep a few candidate rank configs, and pick the smallest χ that keeps functional error under your accuracy budget for that specific layer. KARIPAP's "layer-wise entanglement profiling" finding — that redundancy concentrates in deeper layers — means this sweep is not going to converge on a single global χ; expect earlier layers to need higher rank and deeper layers to tolerate aggressive truncation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compounding compression: TT-cores are still ordinary tensors
&lt;/h2&gt;

&lt;p&gt;One point worth being explicit about because it's easy to miss: TT-matrix decomposition and quantization are &lt;strong&gt;not competing techniques&lt;/strong&gt; — they compose. Once a layer is in TT-core form, each core is just a small ordinary tensor, and every standard quantization recipe (INT8 post-training quantization, INT4 GPTQ/AWQ-style, FP8) applies directly to the cores themselves. A core at (r_{k-1}, o_k, i_k, r_k) with r ≈ 16–32 is small enough that per-channel or even per-core quantization scales stay well-conditioned — you get the tensor-network compression ratio &lt;em&gt;and&lt;/em&gt; the quantization compression ratio multiplicatively, not as alternatives to choose between.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest number: TT is not free at inference time
&lt;/h2&gt;

&lt;p&gt;Correctness tests confirm the math is right. They say nothing about speed — and speed is where this gets uncomfortable. Benchmarked on this repo's own &lt;code&gt;benchmarks/bench_tt_linear.py&lt;/code&gt; (methodology: &lt;code&gt;torch.cuda.synchronize()&lt;/code&gt;-correct timing, 50 trials after warmup, mean±std):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On small square matrices (256–1024), &lt;code&gt;TTLinear&lt;/code&gt; is 2x–50x &lt;em&gt;slower&lt;/em&gt; in wall-clock latency than dense &lt;code&gt;nn.Linear&lt;/code&gt;.&lt;/strong&gt; This is the direct cost of not having a fused TT-contraction kernel: dense dispatches to one heavily-optimized BLAS GEMM; &lt;code&gt;TTLinear.forward&lt;/code&gt; performs several smaller &lt;code&gt;tensordot&lt;/code&gt; operations with real dispatch overhead between them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But that finding doesn't generalize to real model scale — and this is worth stating plainly rather than quietly correcting.&lt;/strong&gt; Benchmarked against Gemma-3-1B's actual MLP dimensions (embed_dim=1152, MLP hidden=6912), the picture flips at low rank: &lt;strong&gt;up to 5.9x &lt;em&gt;faster&lt;/em&gt; than dense at rank 16, batch 1&lt;/strong&gt;, while keeping the memory savings — a genuine speed &lt;em&gt;and&lt;/em&gt; memory win in exactly the regime (low rank, aggressive compression) where the entropy argument above says compression is justified in the first place. The crossover runs the other way at high rank + large batch (down to ~4x slower), consistent with the small-matrix result. Full rank×batch sweep and methodology: &lt;a href="https://github.com/mohamed-bal/tt-linear-pytorch/blob/main/benchmarks/README.md" rel="noopener noreferrer"&gt;&lt;code&gt;benchmarks/README.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use this when memory is the hard constraint — and benchmark your own model's actual layer shapes and rank choice before assuming either direction on latency.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  KV-cache and datacenter memory: where the bytes actually live
&lt;/h2&gt;

&lt;p&gt;Weight compression addresses static parameter storage. In production, KV-cache — which scales with batch size × context length × layers, not with parameter count — is frequently the larger operational cost, and it needs a different set of architectural decisions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Latency&lt;/th&gt;
&lt;th&gt;Effective capacity&lt;/th&gt;
&lt;th&gt;Complexity&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;GPU HBM only&lt;/strong&gt; (baseline full-attention serving)&lt;/td&gt;
&lt;td&gt;Lowest — HBM bandwidth (~2–3 TB/s on current datacenter GPUs)&lt;/td&gt;
&lt;td&gt;Limited to physical GPU memory&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;td&gt;The ceiling on concurrent long-context requests is set directly by HBM capacity; this is why sparse/compressed KV formats (MiniMax MSA, DeepSeek CSA+HCA — covered separately) matter as much as raw memory tricks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;CPU RAM offload via PCIe&lt;/strong&gt; (e.g. vLLM-Offload style)&lt;/td&gt;
&lt;td&gt;Highest under cache miss — PCIe Gen4/Gen5 bandwidth (32–64 GB/s in published testbeds) is an order of magnitude below HBM&lt;/td&gt;
&lt;td&gt;Much larger — system RAM is cheap and abundant&lt;/td&gt;
&lt;td&gt;Low-moderate&lt;/td&gt;
&lt;td&gt;Simple to deploy on existing hardware; the bandwidth cliff between HBM and PCIe-attached RAM is the whole tradeoff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CXL-attached pooled memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Between the two — CXL.mem gives near-DRAM latency with byte addressability and cross-device pooling&lt;/td&gt;
&lt;td&gt;Large, poolable across nodes&lt;/td&gt;
&lt;td&gt;Higher — newer hardware ecosystem, integration work&lt;/td&gt;
&lt;td&gt;The approach explored in recent disaggregated-KV-cache research for sparse-attention LLMs; a genuine middle ground rather than a strict win, since the ecosystem (drivers, interconnect topology) is still maturing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Hierarchical selective fetch&lt;/strong&gt; (e.g. the Spin-style approach: full KV cache resident in CPU memory, only "critical" entries fetched to GPU on demand)&lt;/td&gt;
&lt;td&gt;Depends on hit rate — good when the underlying attention mechanism is &lt;em&gt;already&lt;/em&gt; sparse (MSA/DSA-style scoring tells you which KV entries matter)&lt;/td&gt;
&lt;td&gt;Effectively unbounded (CPU-resident)&lt;/td&gt;
&lt;td&gt;Highest — requires the serving stack to be sparsity-aware, not just memory-aware&lt;/td&gt;
&lt;td&gt;This is the option that actually composes with the attention-architecture choices from earlier: the same Index-Branch/Lightning-Indexer scoring that makes MSA/DSA compute-efficient also tells the memory system which KV entries are worth fetching across the PCIe/CXL boundary in the first place&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The practical takeaway: don't treat weight compression and KV-cache placement as independent decisions made by different teams. The row you pick for KV-cache placement should be informed by whether your attention mechanism is sparse in the first place — a sparsity-aware serving stack turns "offload everything, fetch what's needed" from a bandwidth gamble into a mechanism that fetches close to only what the model actually attends to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security notes for anything in this pipeline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Never &lt;code&gt;torch.load()&lt;/code&gt; a checkpoint from an untrusted source without &lt;code&gt;weights_only=True&lt;/code&gt;.&lt;/strong&gt; Standard pickle-based checkpoints can execute arbitrary code on load; this applies just as much to TT-core checkpoints as to any other model artifact — a compressed model is not a safer model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate rank/factor configs before allocating tensors, especially if any part of the config is derived from external input&lt;/strong&gt; (a config file, an API parameter, a user-uploaded model spec). &lt;code&gt;TTMatrixConfig.__post_init__&lt;/code&gt; and &lt;code&gt;validate_against&lt;/code&gt; above exist specifically so a malformed or adversarial config raises immediately with a clear message, rather than allocating an unexpectedly enormous tensor or silently producing wrong results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log, don't print, in anything that runs in a service.&lt;/strong&gt; Swap the module logger's level and handlers per your existing observability stack; the point of using &lt;code&gt;logging&lt;/code&gt; here instead of bare &lt;code&gt;print&lt;/code&gt; is that compression failures need to show up in the same place as every other production error, not scroll past in stdout.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What follows ties the theory and the code together into an actual decision procedure: given a specific layer's measured entropy profile, a latency budget, and a KV-cache placement choice, which combination of techniques to reach for — and, just as importantly, when none of this is worth the engineering cost compared to simply using a smaller dense model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc7a9o8waoy6388c28qif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc7a9o8waoy6388c28qif.png" alt="A four-stage production decision flowchart for deploying compressed AI models. Stage 1: profile the layer's functional error at aggressive bond-dimension (χ) truncation using real activations — if acceptable, apply TT-decomposition at the smallest viable χ; if not, keep the layer dense or at higher rank (early layers typically fall here, per KARIPAP's finding that redundancy concentrates in deeper layers). Stage 2: quantize (INT8/FP8) on top of the χ decision, composable rather than alternative. Stage 3: branch on whether the attention mechanism is sparse (MSA/DSA-style scoring) — sparse attention routes to hierarchical selective KV fetch (CPU/CXL-resident with sparsity-aware prefetch); dense attention routes to GPU HBM-resident cache or PCIe offload. Stage 4: check total footprint (latency + memory + $/token) against the production budget — if it fits, deploy; if not, reconsider whether a smaller dense model beats the full compression pipeline on engineering cost, with a feedback loop back to re-profiling at a different rank budget or base model. Original diagram — conceptual decision flow, not a reproduction of any published figure." width="800" height="1043"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The framework, decision by decision
&lt;/h2&gt;

&lt;p&gt;Each node above hides a real decision procedure. Here's what actually goes into each one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node 1 — "Is functional error acceptable at aggressive χ truncation?"
&lt;/h3&gt;

&lt;p&gt;The number that matters is &lt;strong&gt;functional error on real activations&lt;/strong&gt; (from &lt;code&gt;profile_layer_compressibility&lt;/code&gt; in the previous section), not weight-Frobenius-norm error. A layer can have large weight-reconstruction error but small functional error if the truncated singular directions correspond to input subspaces the layer rarely sees in practice — and the reverse is also possible. Measure the thing you actually care about.&lt;/p&gt;

&lt;p&gt;The threshold itself is workload-dependent, but the more important engineering point is that &lt;strong&gt;per-layer error does not simply add up across the network&lt;/strong&gt; — it can compound nonlinearly through subsequent layers, or in some cases partially cancel. Treat per-layer functional error as a fast &lt;em&gt;screening&lt;/em&gt; metric to decide which layers are even candidates for aggressive compression, not as the final acceptance criterion. The final criterion has to be an end-to-end evaluation: task accuracy delta, perplexity delta, or whatever your actual production quality metric is, measured on the fully compressed model, not summed per-layer estimates. A reasonable procedure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Screen all layers with the cheap per-layer functional-error check, sorted by "how compressible is this layer" (this reproduces KARIPAP's finding empirically on your own model — expect deeper layers to screen as more compressible).&lt;/li&gt;
&lt;li&gt;Compress layers greedily from most-compressible to least, re-running full end-to-end evaluation after each batch of layers, stopping when end-to-end quality crosses your acceptance line.&lt;/li&gt;
&lt;li&gt;Keep the boundary layer's rank as a tunable — this is the number you'll revisit first if quality regresses after any future fine-tune or version bump.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Node 2 — Quantization: hardware determines the right answer, not preference
&lt;/h3&gt;

&lt;p&gt;This decision is dictated by which GPU generation you're actually deploying on, not by which format is theoretically better:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;GPU generation&lt;/th&gt;
&lt;th&gt;Native FP8 tensor cores&lt;/th&gt;
&lt;th&gt;Recommendation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ampere (A100)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;INT8 — FP8 has no dedicated hardware path here; forcing it buys nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ada Lovelace (L40S, RTX 4090-class)&lt;/td&gt;
&lt;td&gt;Partial — &lt;a href="https://www.spheron.network/blog/fp8-quantization-inference-performance-hardware-explained/" rel="noopener noreferrer"&gt;FP8 ops exist without dedicated scaling hardware, silently falling back toward BF16-level gains&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;INT8 for guaranteed throughput; FP8 only if you've benchmarked an actual win on your kernel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hopper (H100/H200)&lt;/td&gt;
&lt;td&gt;Yes — &lt;a href="https://www.spheron.network/blog/fp8-quantization-inference-performance-hardware-explained/" rel="noopener noreferrer"&gt;first-generation Transformer Engine with dedicated FP8 tensor cores&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;FP8 — real published economics: &lt;a href="https://www.spheron.network/blog/fp8-quantization-inference-performance-hardware-explained/" rel="noopener noreferrer"&gt;~$0.71/M tokens vs ~$1.19/M at BF16 for Llama 3.1 70B on H100, 1.4–1.8x throughput at large batch&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blackwell (B100/B200/B300)&lt;/td&gt;
&lt;td&gt;Yes, second-generation, plus native FP4/FP6&lt;/td&gt;
&lt;td&gt;FP8 as the safe default; FP4 (NVFP4/MXFP4) if you've validated accuracy on your specific model — FP4 roughly doubles throughput again over FP8 but carries materially higher accuracy risk&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The reason INT8 remains the correct default on older hardware isn't nostalgia: FP8 retains a floating-point exponent, giving it a wider dynamic range than INT8's fixed-range integers — genuinely better suited to transformer activation distributions — but that advantage only materializes with dedicated silicon to exploit it. Without that silicon, you're paying FP8's format-conversion overhead for a BF16-equivalent result.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node 3 — KV-cache placement: the sparsity signal is what makes "hierarchical selective fetch" viable at all
&lt;/h3&gt;

&lt;p&gt;This branch only works in one direction. If your attention mechanism produces an explicit relevance signal (the Index Branch score in MSA-style architectures, the Lightning Indexer score in DSA-style architectures), that signal is exactly the thing a hierarchical fetch scheduler needs to decide which KV entries are worth moving across a PCIe or CXL boundary before the attention computation needs them. Without that signal, "fetch what's needed" degrades to "fetch everything, cache what fits" — which is just PCIe offload with extra steps.&lt;/p&gt;

&lt;p&gt;If you're running a dense-attention model, don't build the hierarchical-fetch complexity — go straight to the HBM-vs-PCIe-offload decision from the earlier comparison table. The engineering cost of the sparsity-aware scheduler only pays for itself when there's a real sparsity signal driving it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node 4 — Budget check: a worked example
&lt;/h3&gt;

&lt;p&gt;Concrete arithmetic, using representative (not benchmark-sourced) numbers to illustrate the calculation shape:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt; a 7B-parameter-class model, serving batch size 8, context length 128K tokens, 32 layers, FP16 KV cache.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dense KV cache footprint: &lt;code&gt;2 (K and V) × 32 layers × 128,000 tokens × 8 batch × hidden_dim(4096) × 2 bytes (FP16)&lt;/code&gt; ≈ &lt;strong&gt;537 GB&lt;/strong&gt; — already exceeds a single GPU's HBM at this batch/context combination, before weights are even counted.&lt;/li&gt;
&lt;li&gt;With a sparse-attention architecture retaining, say, 10% of KV entries as "relevant" per the indexer's selection (illustrative ratio, not a published figure) and INT8 KV quantization: &lt;code&gt;537 GB × 0.10 × 0.5&lt;/code&gt; (INT8 is half the bytes of FP16) ≈ &lt;strong&gt;27 GB&lt;/strong&gt; — now plausibly HBM-resident on modern datacenter GPUs, without touching PCIe/CXL at all.&lt;/li&gt;
&lt;li&gt;Weight footprint: TT-decomposition at a validated χ per layer (from Node 1's sweep) plus INT8 quantization might realistically land in the 15–30% of dense-FP16-weight-bytes range for a model with KARIPAP-like redundancy — but this number &lt;strong&gt;has to come from your own &lt;code&gt;compression_report()&lt;/code&gt; output on your own checkpoint&lt;/strong&gt;, not from a generic industry figure. This is the one place a hallucinated benchmark would be actively dangerous to plan capacity around.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The point of walking through the arithmetic explicitly isn't the specific numbers — it's that the KV-cache term and the weight-compression term are computed independently, from independent measurements, and both have to clear your actual per-GPU HBM budget (or your PCIe/CXL-offload bandwidth budget, if you've deliberately chosen that path) before "deploy" is the right answer at Node 4's diamond.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the honest answer is "don't build this pipeline"
&lt;/h2&gt;

&lt;p&gt;The feedback loop in the diagram exists because this is a real, frequent outcome, not an edge case. A comparison worth having explicitly before committing engineering time:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Performance&lt;/th&gt;
&lt;th&gt;Resource consumption&lt;/th&gt;
&lt;th&gt;Engineering/maintenance cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;No compression&lt;/strong&gt; (dense, native precision)&lt;/td&gt;
&lt;td&gt;Baseline&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;Lowest — no pipeline to maintain, no re-profiling on every checkpoint update&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Quantization only&lt;/strong&gt; (INT8/FP8, no TT-decomposition)&lt;/td&gt;
&lt;td&gt;Near-baseline quality, ~2x memory/throughput win&lt;/td&gt;
&lt;td&gt;Moderate reduction&lt;/td&gt;
&lt;td&gt;Low — mature tooling (vLLM, TensorRT-LLM, SGLang all support this natively), minimal custom code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Full pipeline&lt;/strong&gt; (TT-decomposition + quantization + sparsity-aware KV placement)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Latency is scale-dependent — 2x–50x slower on small matrices, but up to 5.9x faster at real LLM scale + low rank (see "the honest number" above); benchmark your own dimensions, don't assume either direction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Largest reduction — this is the only option in the set that meaningfully changes the &lt;em&gt;weight&lt;/em&gt; footprint, not just KV/activation footprint&lt;/td&gt;
&lt;td&gt;Highest — custom decomposition code, per-layer rank tuning, re-profiling required on every checkpoint change, and everything in the security notes above becomes your team's responsibility, not a library maintainer's&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Smaller off-the-shelf dense model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Depends entirely on whether a smaller model meets your quality bar&lt;/td&gt;
&lt;td&gt;Smallest — by construction&lt;/td&gt;
&lt;td&gt;Lowest of any option that actually reduces footprint — no custom pipeline, just a different model&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The full pipeline is the right call when you have a &lt;strong&gt;specific, fixed model you're contractually, legally, or technically required to run as-is&lt;/strong&gt; — data residency requirements, a licensing constraint, a fine-tuned checkpoint with no smaller equivalent, or genuine on-premise hardware limits that no vendor API can route around. It is very often &lt;em&gt;not&lt;/em&gt; the right call when the actual requirement is "a model that's good enough and cheap enough," because that requirement is usually satisfied faster and more reliably by evaluating an already-smaller model than by building and maintaining a custom compression pipeline for a larger one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production checklist before cutover
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Version-pin the entropy profile to the checkpoint hash.&lt;/strong&gt; A rank choice validated against checkpoint A is not guaranteed valid against checkpoint A after a fine-tune. Store &lt;code&gt;compression_report()&lt;/code&gt; output keyed by checkpoint hash, not by model name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadow-deploy before cutover.&lt;/strong&gt; Run the compressed model against a copy of live traffic without serving its output, comparing downstream task metrics against the dense baseline over a realistic traffic distribution — the per-layer and even end-to-end offline eval from Node 1 is a necessary but not sufficient check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the dense checkpoint loadable as a feature-flagged fallback.&lt;/strong&gt; Compression should be a runtime choice you can revert without a redeploy, not a one-way migration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never &lt;code&gt;torch.load()&lt;/code&gt; any checkpoint — compressed or dense — without &lt;code&gt;weights_only=True&lt;/code&gt;&lt;/strong&gt; against untrusted sources, as covered earlier; a compressed model is not a lower-risk artifact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-run the entire decision flow on every architecture or checkpoint version change.&lt;/strong&gt; Entropy structure is a property of the specific trained weights, not the model architecture in the abstract — this is the direct practical consequence of Part 1's theoretical claim that trained (not random) weights are what carries the compressible structure in the first place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're looking to integrate this into your inference stack, you can drop in the &lt;code&gt;TTLinear&lt;/code&gt; module directly from the &lt;a href="https://github.com/mohamed-bal/tt-linear-pytorch" rel="noopener noreferrer"&gt;GitHub Repo&lt;/a&gt;. PRs and issues are welcome!&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing the loop
&lt;/h2&gt;

&lt;p&gt;The physics in the first section and the code in the second aren't separate concerns bolted together for a blog post — they're the same claim at two levels of abstraction. Area law says entanglement entropy in a physical system stays bounded when there's real structure to exploit. KARIPAP's layer-wise profiling says the same thing is empirically true of trained transformer weights, concentrated unevenly by depth. And the decision framework above is just the operational form of that claim: measure where the structure actually is, on your own model, before spending engineering effort compressing it — because the same theory that explains why compression works this well on structured weights is exactly why it does nothing useful on weights that aren't.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Sources: &lt;a href="https://arxiv.org/abs/0808.3773" rel="noopener noreferrer"&gt;Area law review&lt;/a&gt;; &lt;a href="http://itensor.org/docs.cgi?page=tutorials%2FInfoTheory&amp;amp;vers=julia" rel="noopener noreferrer"&gt;DMRG/MPS tutorial (ITensor)&lt;/a&gt;; &lt;a href="https://www.ifsc.usp.br/bssm/wp-content/uploads/2023/01/DMRG-03-MPS.pdf" rel="noopener noreferrer"&gt;DMRG/MPS lecture notes (Feiguin)&lt;/a&gt;; &lt;a href="https://arxiv.org/abs/2401.14109" rel="noopener noreferrer"&gt;CompactifAI&lt;/a&gt;; &lt;a href="https://www.researchgate.net/publication/396966873_KARIPAP_Quantum-Inspired_Tensor_Network_Compression_of_Large_Language_Models_Using_Infinite_Projected_Entangled_Pair_States_and_Tensor_Renormalization_Group" rel="noopener noreferrer"&gt;KARIPAP&lt;/a&gt;; &lt;a href="https://arxiv.org/abs/2307.00526" rel="noopener noreferrer"&gt;TensorGPT&lt;/a&gt;; &lt;a href="https://arxiv.org/abs/1509.06569" rel="noopener noreferrer"&gt;Novikov et al., "Tensorizing Neural Networks"&lt;/a&gt;; &lt;a href="https://arxiv.org/abs/2410.17397" rel="noopener noreferrer"&gt;Quantum LLMs via Tensor Network Disentanglers&lt;/a&gt;; &lt;a href="https://arxiv.org/abs/1807.04271" rel="noopener noreferrer"&gt;Ewin Tang, "A quantum-inspired classical algorithm for recommendation systems"&lt;/a&gt;; &lt;a href="https://arxiv.org/abs/1910.06151" rel="noopener noreferrer"&gt;Chia, Gilyén, Li, Lin, Tang, Wang — dequantizing framework&lt;/a&gt;; &lt;a href="https://originqc.com/blogs/nisq-era-status-2026" rel="noopener noreferrer"&gt;2026 NISQ status&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>performance</category>
    </item>
    <item>
      <title>MiniMax-M3 on DEVUP AI — A Technical Deep Dive into MiniMax Sparse Attention, Benchmarks, and Production Integration</title>
      <dc:creator>Mohamed Bal</dc:creator>
      <pubDate>Sat, 04 Jul 2026 22:05:02 +0000</pubDate>
      <link>https://dev.to/mohamed_bal/minimax-m3-is-live-on-devup-ai-1m-token-context-native-multimodality-and-frontier-coding-at-a-o8d</link>
      <guid>https://dev.to/mohamed_bal/minimax-m3-is-live-on-devup-ai-1m-token-context-native-multimodality-and-frontier-coding-at-a-o8d</guid>
      <description>&lt;p&gt;MiniMax-M3 is live on &lt;strong&gt;DEVUP AI&lt;/strong&gt; — routable through the same OpenAI-compatible gateway as our other 170+ models, billed in DZD via Edahabia/CIB. Model ID: &lt;code&gt;MiniMaxAI/MiniMax-M3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Most launch-day coverage repeated MiniMax's press numbers without reading the actual paper behind the architecture. This post goes one level deeper: what the &lt;a href="https://arxiv.org/abs/2606.13392" rel="noopener noreferrer"&gt;arXiv paper&lt;/a&gt; actually claims, where it diverges from the PR figures, what M3 costs and how it's exposed on our platform, and production-grade integration code — retries, timeouts, streaming, and multimodal, all handled correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's actually new
&lt;/h2&gt;

&lt;p&gt;Three capabilities that, until now, only closed-source models combined in one checkpoint:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontier-tier coding/agentic performance&lt;/strong&gt; — competitive with GPT-5.5 and Gemini 3.1 Pro on agentic benchmarks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1M-token context&lt;/strong&gt; (with a guaranteed floor — more on that below)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native multimodality&lt;/strong&gt; — image and video input, trained in from step zero, not bolted on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Architecture: MoE, ~428B total parameters, ~23B active per token.&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the hood: MiniMax Sparse Attention (MSA)
&lt;/h2&gt;

&lt;p&gt;Here's the mechanism, straight from the &lt;a href="https://arxiv.org/abs/2606.13392" rel="noopener noreferrer"&gt;technical report&lt;/a&gt; (Lai et al., MiniMax, June 2026):&lt;/p&gt;

&lt;p&gt;MSA is a &lt;strong&gt;blockwise sparse attention built on top of Grouped Query Attention (GQA)&lt;/strong&gt; — not a replacement for GQA, an extension of it. It has two branches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Index Branch&lt;/strong&gt; — a lightweight scorer that ranks key-value blocks and independently selects a Top-k subset &lt;em&gt;per GQA group&lt;/em&gt;. This is the detail most summaries miss: selection isn't global, it's group-specific, which is what lets the model retrieve different relevant context for different attention heads within the same layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Main Branch&lt;/strong&gt; — performs &lt;em&gt;exact&lt;/em&gt; block-sparse attention, but only over the blocks the Index Branch selected. No approximation inside the selected blocks — the sparsity is in &lt;em&gt;which&lt;/em&gt; blocks get attended to, not in how attention is computed within them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To make that sparsity translate into wall-clock speed rather than just fewer FLOPs on paper, MiniMax co-designed the GPU kernel with &lt;strong&gt;exp-free Top-k selection&lt;/strong&gt; and &lt;strong&gt;KV-outer sparse attention&lt;/strong&gt;, specifically to keep tensor-core utilization high under block-granular memory access — a detail that matters because naive sparse attention implementations often lose their theoretical speedup to poor hardware utilization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The numbers, precisely:&lt;/strong&gt; On a 109B-parameter research checkpoint with native multimodal training, MSA matches GQA quality while cutting per-token &lt;em&gt;attention&lt;/em&gt; compute by &lt;strong&gt;28.4x&lt;/strong&gt; at 1M context. Paired with the co-designed kernel, that's &lt;strong&gt;14.2x prefill&lt;/strong&gt; and &lt;strong&gt;7.6x decoding&lt;/strong&gt; wall-clock speedup on H800 GPUs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxxf4lj05n13mrfgvc4sf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxxf4lj05n13mrfgvc4sf.png" alt="MSA vs GQA: per-token attention FLOPs, prefill latency, and decode latency across sequence length, showing 28.4x FLOPs reduction, 14.2x prefill speedup, and 7.6x decode speedup at 1M tokens (source: arXiv:2606.13392)" width="799" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The gap between the two curves widens with sequence length — GQA's cost grows steeply while MSA stays close to flat, which is the entire point of a &lt;em&gt;sparse&lt;/em&gt; mechanism: the advantage barely matters at 32K tokens and becomes decisive at 1M.&lt;/p&gt;

&lt;p&gt;Compare that to the press figures circulating since launch — "~1/20th compute, 9x prefill, 15x decode." These aren't wrong, but they're not the same number as the paper's, and the discrepancy is worth understanding rather than hand-waving: the paper's 28.4x figure is specifically &lt;em&gt;attention&lt;/em&gt; compute on a smaller 109B test model, while the press figures describe &lt;em&gt;end-to-end per-token&lt;/em&gt; compute on the production 428B/23B-active M3 — a different denominator (attention-only vs. full forward pass) and a different model scale. Both can be true simultaneously. If you're doing capacity planning, use the paper's numbers for attention-layer cost modeling and treat the press figures as a rough end-to-end proxy, not interchangeable data points.&lt;/p&gt;

&lt;p&gt;The inference kernel itself is open-sourced: &lt;a href="https://github.com/MiniMax-AI/MSA" rel="noopener noreferrer"&gt;github.com/MiniMax-AI/MSA&lt;/a&gt;. Worth cloning if you're evaluating self-hosting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks — with the caveats that matter
&lt;/h2&gt;

&lt;p&gt;MiniMax reports:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;M3 Score&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SWE-Bench Pro&lt;/td&gt;
&lt;td&gt;59.0%&lt;/td&gt;
&lt;td&gt;Ahead of GPT-5.5 (58.6%) and Gemini 3.1 Pro&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terminal-Bench 2.1&lt;/td&gt;
&lt;td&gt;66.0%&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP Atlas&lt;/td&gt;
&lt;td&gt;74.2%&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BrowseComp&lt;/td&gt;
&lt;td&gt;83.5&lt;/td&gt;
&lt;td&gt;vs. Claude Opus 4.7's 79.3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things before you weight these for a production decision:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The comparison baseline is stale.&lt;/strong&gt; MiniMax benchmarked against Claude Opus 4.7 — Opus 4.8 shipped four days before M3's launch. Against the actual current frontier, M3 sits further back than the launch post implies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-reported, self-scaffolded.&lt;/strong&gt; Several results ran on MiniMax's own infrastructure with agent scaffolding (Claude Code, Mini-SWE-Agent, Terminus). Weights are now public on Hugging Face, so independently reproduced numbers should surface over the coming weeks — re-check before leaning on these for anything critical.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The long-horizon autonomy demos are the more interesting signal for agentic use cases: M3 ran unsupervised for ~12 hours reproducing an ICLR 2025 paper (18 commits, 23 figures, core experimental claims validated), and separately spent ~24 hours on a CUDA/Hopper kernel optimization task — 147 submissions, 1,959 tool calls, pushing hardware utilization from 7.6% to 71.3%, continuing to improve well past the point where most models plateau and stop.&lt;/p&gt;

&lt;h2&gt;
  
  
  On DEVUP AI: specs and pricing
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Model ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MiniMaxAI/MiniMax-M3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pricing&lt;/td&gt;
&lt;td&gt;105 DZD in / 420 DZD out / 21 DZD cached — per 1M tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context window (as exposed)&lt;/td&gt;
&lt;td&gt;524K tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Architecture&lt;/td&gt;
&lt;td&gt;MoE, ~428B total / ~23B active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Capabilities&lt;/td&gt;
&lt;td&gt;Public · JSON mode · Function calling · Multimodal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One detail worth noticing: MiniMax's official ceiling is 1M tokens, but they only &lt;em&gt;guarantee&lt;/em&gt; 512K. 512K × 1024 = 524,288 — which is exactly the 524K we expose. We're not truncating the model's capability; we're exposing the guaranteed floor rather than the marketing ceiling, so your context-length assumptions hold under load instead of degrading silently past the guaranteed range.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production integration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Basic completion, with real retry/error handling
&lt;/h3&gt;

&lt;p&gt;The gateway returns OpenAI-compatible error bodies (&lt;code&gt;error.message&lt;/code&gt;, &lt;code&gt;error.type&lt;/code&gt;, &lt;code&gt;error.code&lt;/code&gt;). 400/401/403 are never retryable — fix the payload, key, or balance. 429 and 500 are, and 429 responses include a &lt;code&gt;Retry-After&lt;/code&gt; header you should actually respect instead of guessing a backoff.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DevUpAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;devupai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MiniMaxAI/MiniMax-M3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;devup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DevUpAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEVUP_API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// never hardcode; pull from a secrets manager in prod&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;DevUpErrorBody&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ChatMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Calls MiniMax-M3 through the DEVUP AI gateway with production-grade handling:
 * - explicit timeout suited to long-context (up to 524K token) requests, which
 *   can legitimately take tens of minutes, not seconds
 * - retry only on documented-retryable statuses (429, 500)
 * - honors the Retry-After header on 429 instead of guessing a backoff
 * - exponential backoff + jitter as a fallback when Retry-After is absent
 */&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;callMiniMaxM3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;timeoutMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;timeoutMs&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;timeoutMs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;devup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4096&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DevUpErrorBody&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retryable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;retryable&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="s2"&gt;`MiniMax-M3 request failed (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; / &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no_code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;): &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
            &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retryAfterHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;retry-after&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;retryAfterMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;retryAfterHeader&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;retryAfterHeader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jitterMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;retryAfterMs&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;jitterMs&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Streaming (SSE)
&lt;/h3&gt;

&lt;p&gt;For anything user-facing, stream rather than block — especially at long context, where full-response latency can be substantial.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;devup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Summarize this 400K-token incident log and flag anomalies.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`\n[tokens] prompt=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prompt_tokens&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; completion=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completion_tokens&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multimodal input
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;devup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image_url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/architecture-diagram.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Review this system architecture diagram and flag single points of failure.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tool calling
&lt;/h3&gt;

&lt;p&gt;Standard OpenAI-compatible &lt;code&gt;tools&lt;/code&gt; array works unmodified. One tuning note specific to tool calling: MiniMax's own recommended defaults (&lt;code&gt;temperature=1.0&lt;/code&gt;, &lt;code&gt;top_p=0.95&lt;/code&gt;) are tuned for general generation quality, not argument-parsing reliability. For tool-calling workloads, drop temperature below 1.0 — consistent with our platform-wide guidance for structured function-call output regardless of model.&lt;/p&gt;

&lt;h2&gt;
  
  
  API vs. self-hosting the open weights
&lt;/h2&gt;

&lt;p&gt;Weights are public on Hugging Face (~428B total / ~23B active MoE). Real architectural choice:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Via DEVUP AI (API)&lt;/th&gt;
&lt;th&gt;Self-hosted (open weights)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Time to integrate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minutes — OpenAI-compatible endpoint&lt;/td&gt;
&lt;td&gt;Days — the released &lt;a href="https://github.com/MiniMax-AI/MSA" rel="noopener noreferrer"&gt;MSA kernel&lt;/a&gt; targets H800; broader GPU/framework support (llama.cpp, etc.) is still maturing and currently falls back to dense attention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost profile&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pay-per-token, DZD billing, no upfront infra&lt;/td&gt;
&lt;td&gt;High upfront GPU cost — 428B params means serious VRAM even with MoE sparsity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data residency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Traffic routed through our gateway; see our DPA for compliance requirements&lt;/td&gt;
&lt;td&gt;Full control — matters if you're bound by strict residency rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Long-context throughput&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shared infra, subject to queueing under load&lt;/td&gt;
&lt;td&gt;Full control over batching/throughput tuning, but you own the kernel engineering&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One honest note on data handling: M3 is developed in Shanghai, and Chinese entities operate under legal obligations to cooperate with state intelligence requests. That's not a reason to avoid the model — it's a reason to be deliberate about what you send it, same as with any third-party inference endpoint. If you're processing regulated or sensitive data, self-hosting the open weights (or scrubbing payloads before routing through any API) is the safer default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters for us
&lt;/h2&gt;

&lt;p&gt;Long context, native multimodal, and agentic coding — at open-weight economics, with a documented and open-sourced attention kernel — means Algerian and MENA teams building RAG pipelines, code-review agents, or document-heavy workflows now have a genuinely frontier-adjacent option that doesn't require a foreign card or USD billing. One key, one DZD invoice, 170+ models including this one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.devupai.com/models/minimax-m3" rel="noopener noreferrer"&gt;Try MiniMax-M3 on DEVUP AI →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Primary sources: &lt;a href="https://arxiv.org/abs/2606.13392" rel="noopener noreferrer"&gt;arXiv:2606.13392&lt;/a&gt; (MSA technical report), &lt;a href="https://huggingface.co/MiniMaxAI/MiniMax-M3" rel="noopener noreferrer"&gt;MiniMax-M3 on Hugging Face&lt;/a&gt;, &lt;a href="https://www.devupai.com/models/minimax-m3" rel="noopener noreferrer"&gt;DEVUP AI model page&lt;/a&gt;. Secondary: MiniMax official model page, VentureBeat, The Decoder, Artificial Analysis, TechTimes.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>api</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Why Algeria Needs Its Own AI Infrastructure — and Why I'm Building It</title>
      <dc:creator>Mohamed Bal</dc:creator>
      <pubDate>Wed, 01 Jul 2026 18:42:26 +0000</pubDate>
      <link>https://dev.to/mohamed_bal/why-algeria-needs-its-own-ai-infrastructure-and-why-im-building-it-1m70</link>
      <guid>https://dev.to/mohamed_bal/why-algeria-needs-its-own-ai-infrastructure-and-why-im-building-it-1m70</guid>
      <description>&lt;h2&gt;
  
  
  The problem no one was solving
&lt;/h2&gt;

&lt;p&gt;Every Algerian developer building with AI hits the same wall: an international payment card. OpenAI, Anthropic, Google — every major AI provider assumes you have one. Most Algerian developers don't, or don't want to deal with the friction of currency conversion, card rejections, and unpredictable billing in a foreign currency.&lt;/p&gt;

&lt;p&gt;That's not a minor inconvenience. It's a barrier that quietly excludes an entire generation of developers from building with the best AI models available — not because they lack the skill, but because of infrastructure that was never designed with them in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  The vision: AI sovereignty, not just AI access
&lt;/h2&gt;

&lt;p&gt;Access alone isn't the goal. The goal is &lt;strong&gt;sovereignty&lt;/strong&gt; — Algeria having its own AI infrastructure layer, controlled locally, billed locally, and built to local compliance standards, instead of depending entirely on foreign gateways with no local accountability.&lt;/p&gt;

&lt;p&gt;That's what DEVUP AI is: Algeria's first AI inference gateway, built from the ground up to remove every friction point between an Algerian developer and the AI models they need.&lt;/p&gt;

&lt;h2&gt;
  
  
  What DEVUP AI actually does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;170+ AI models&lt;/strong&gt; — including DeepSeek V4, Llama 3.1 405B, Qwen 3, Gemma 2, Mistral, GPT, Claude, and Gemini — through a single API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI-compatible and Anthropic-compatible&lt;/strong&gt; — point your existing SDK at our endpoint, no code rewrite needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local DZD billing&lt;/strong&gt; via Edahabia/CIB — no international card required&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SATIM-certified&lt;/strong&gt; payment infrastructure — full compliance with Algeria's national payment standards&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scoped JWT authentication&lt;/strong&gt; for production-grade security&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A dedicated SDK&lt;/strong&gt; (&lt;code&gt;npm install devupai&lt;/code&gt;) and full documentation, so integration takes minutes, not days&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The technical bar was non-negotiable: this had to be production-grade from day one, not a side project. SATIM certification alone meant building proper transaction validation, receipt generation, chargeback tracking, and rejection-rate monitoring — the same rigor a bank would expect from a payment processor, because in a real sense, that's part of what DEVUP AI is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in 30 seconds
&lt;/h2&gt;

&lt;p&gt;If you already use the OpenAI SDK, this is all it takes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_devup_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.devupai.com/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deepseek-ai/DeepSeek-V4-Pro&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello from Algeria!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No vendor lock-in, no rewritten integration — just a different &lt;code&gt;base_url&lt;/code&gt; and DZD billing instead of a foreign card.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "fully integrated" matters
&lt;/h2&gt;

&lt;p&gt;A gateway that just proxies requests isn't enough. Developers need billing, authentication, model routing, and monitoring to work together as one system — not five different tools stitched together. That integration is what lets a developer go from signup to their first API call in minutes, with DZD billing handled transparently in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is bigger than one platform
&lt;/h2&gt;

&lt;p&gt;I didn't build this just to ship a product. I built it because Algeria's developer ecosystem deserves AI infrastructure that treats it as a first-class market, not an afterthought. Every student building a hackathon project, every startup integrating AI into their product, every developer experimenting with RAG pipelines or multi-agent systems — they should be able to do it without fighting their bank first.&lt;/p&gt;

&lt;p&gt;That's the mission. The product is just how I'm executing on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;If you're an Algerian developer (or anywhere, honestly — the API works globally), every new signup gets a free credit to test the platform.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Platform: &lt;a href="https://devupai.com" rel="noopener noreferrer"&gt;devupai.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://docs.devupai.com/docs" rel="noopener noreferrer"&gt;docs.devupai.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Models: &lt;a href="https://www.devupai.com/models" rel="noopener noreferrer"&gt;devupai.com/models&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SDK: &lt;code&gt;npm install devupai&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd genuinely love feedback from other developers building AI products — what's missing, what's confusing, what would make this more useful for you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
