<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://hetanshwaghela.github.io/feed.xml" rel="self" type="application/atom+xml"/><link href="https://hetanshwaghela.github.io/" rel="alternate" type="text/html" hreflang="en"/><updated>2026-06-18T18:05:12+00:00</updated><id>https://hetanshwaghela.github.io/feed.xml</id><title type="html">blank</title><subtitle>I&apos;m interested in machine learning and deep learning, especially transformer models, efficient fine-tuning, and model behavior. I enjoy exploring training dynamics, attention patterns, and lightweight methods like LoRA to understand how different design choices shape performance. </subtitle><entry><title type="html">Restoring Identity: How Manifold Constraints Tame the Hyper-Connection Chaos</title><link href="https://hetanshwaghela.github.io/blog/2026/restoring-identity-mhc/" rel="alternate" type="text/html" title="Restoring Identity: How Manifold Constraints Tame the Hyper-Connection Chaos"/><published>2026-01-09T00:00:00+00:00</published><updated>2026-01-09T00:00:00+00:00</updated><id>https://hetanshwaghela.github.io/blog/2026/restoring-identity-mhc</id><content type="html" xml:base="https://hetanshwaghela.github.io/blog/2026/restoring-identity-mhc/"><![CDATA[<p>I’ve been reading through the new paper <strong>“mHC: Manifold-Constrained Hyper-Connections”</strong> (arXiv:2512.24880), and honestly, it feels like finding a missing puzzle piece for modern Deep Learning architectures.</p> <p>We’ve all gotten used to ResNets and Transformers dominating the landscape. The secret sauce? <strong>Residual Connections</strong>. That simple <code class="language-plaintext highlighter-rouge">x + F(x)</code> is the reason we can train 100-layer networks without gradients vanishing into oblivion.</p> <p>But recently, people started asking: <em>Why just a simple addition? Why not make the residual stream wider, smarter, and more complex?</em> Enter <strong>Hyper-Connections (HC)</strong>. They sounded great on paper—expanding the residual highway to carry more info. But there was a catch. As you go deeper, things explode. The model becomes unstable.</p> <p>This paper proposes a fix that is so mathematically elegant it hurts: <strong>Manifold Constraints</strong>.</p> <p>Let’s break it down.</p> <hr/> <h2 id="1-the-overview-the-identity-crisis-of-hyper-connections">1. The Overview: The “Identity Crisis” of Hyper-Connections</h2> <p>To understand mHC, we first need to understand the problem with standard Hyper-Connections.</p> <h3 id="the-original-superpower-identity-mapping">The Original Superpower: Identity Mapping</h3> <p>In a classic ResNet or Transformer, the residual connection is an <strong>Identity Mapping</strong>. It preserves the signal. If you have a signal $x$, and you add nothing to it, it stays $x$. This is crucial because it allows gradients to flow straight through the network, like a superhighway with no toll booths.</p> <p><strong>Hyper-Connections (HC)</strong> tried to upgrade this highway. Instead of a single lane (dimension $C$), they expanded it to multiple lanes (dimension $n \times C$) and added “mixers” ($\mathcal{H}^{res}$) to shuffle traffic between lanes.</p> <h3 id="the-problem-the-runaway-train">The Problem: The runaway Train</h3> <p>The issue is that these “mixers” were unconstrained. Imagine a highway where every time you switch lanes, your car gets slightly faster. By the time you reach layer 50, you aren’t driving; you’re breaking the sound barrier.</p> <p>Mathematically, multiplying random matrices layer after layer leads to <strong>signal explosion</strong> (values get too big) or <strong>signal vanishing</strong> (values get too small). The “Identity” property—the safety net—is lost. Your model becomes unstable, and training collapses at scale.</p> <h3 id="the-solution-mhc">The Solution: mHC</h3> <p>The authors introduce <strong>Manifold-Constrained Hyper-Connections (mHC)</strong>. They said: <em>“Okay, let’s keep the multi-lane highway, but let’s strictly enforce the rules of physics.”</em></p> <p>They force the mixing matrices to live on a specific <strong>Manifold</strong>—specifically, the manifold of <strong>Doubly Stochastic Matrices</strong>.</p> <p>What does that mean? It means the total amount of “signal energy” entering the mixer must equal the amount leaving it. No free energy. No explosions. Just pure, stable mixing.</p> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/mhc-highway-comparison.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Unconstrained HC vs Manifold-Constrained mHC" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <hr/> <h2 id="2-a-deep-dive-into-the-maths-the-evolution-of-identity">2. A Deep Dive into the Maths (The Evolution of Identity)</h2> <p>To truly appreciate mHC, we need to trace the evolution of the “residual connection” and see exactly where the math breaks—and how mHC fixes it.</p> <p>Let’s look at three evolutionary stages.</p> <h3 id="stage-1-the-classic-residual-connection-addition">Stage 1: The Classic Residual Connection (Addition)</h3> <p>In a standard ResNet or Transformer, the equation for a layer is simple addition:</p> \[\mathbf{x}_{l+1} = \mathbf{x}_l + \mathcal{F}(\mathbf{x}_l)\] <p>Here, $\mathcal{F}$ is your attention or feed-forward block. The critical part is the $\mathbf{x}_l$ term. It has a coefficient of <strong>1</strong>. If we stack $L$ layers, the signal can propagate all the way from the start to the end: \(\mathbf{x}_L = \mathbf{x}_0 + \sum_{i=0}^{L-1} \mathcal{F}(\mathbf{x}_i)\)</p> <p><strong>The Intuition:</strong> This is like a conveyor belt moving at a constant speed. You can drop packages ($\mathcal{F}$) onto it, but the belt itself ($\mathbf{x}_l$) keeps moving steadily. It doesn’t speed up or slow down. Stability is guaranteed because $1 \times 1 \times 1 \dots = 1$.</p> <h3 id="stage-2-hyper-connections-matrix-multiplication">Stage 2: Hyper-Connections (Matrix Multiplication)</h3> <p>Hyper-Connections (HC) wanted to make the conveyor belt smarter. Instead of just carrying the signal forward, they wanted to mix information between different “lanes” (expanded dimensions). So, they replaced the simple addition with a matrix multiplication:</p> \[\mathbf{x}_{l+1} = \mathcal{H}^{res}_l \mathbf{x}_l + \mathcal{F}(\mathbf{x}_l)\] <p>Here, $\mathcal{H}^{res}_l$ is a learnable $n \times n$ matrix. Now, look what happens when we stack layers. Instead of a sum, we get a <strong>product</strong>:</p> \[\mathbf{x}_L = \left( \prod_{i=0}^{L-1} \mathcal{H}^{res}_i \right) \mathbf{x}_0 + \dots\] <p><strong>The Intuition (and the Problem):</strong> This is no longer a steady conveyor belt. It’s a series of gearboxes.</p> <ul> <li>If $\mathcal{H}^{res}$ effectively multiplies the signal by $1.1$, after 100 layers, your signal is $1.1^{100} \approx 13,000$ times stronger. (<strong>Explosion</strong>)</li> <li>If it multiplies by $0.9$, your signal becomes $0.9^{100} \approx 0.00002$. (<strong>Vanishing</strong>)</li> </ul> <p>This is why HC models are unstable. The “Identity” is lost because the product of random matrices rarely stays close to 1.</p> <h3 id="stage-3-manifold-constrained-hyper-connections-mhc">Stage 3: Manifold-Constrained Hyper-Connections (mHC)</h3> <p>This is the paper’s “Galaxy Brain” moment. They realized we can keep the complex mixing of HC, but force it to behave like the steady conveyor belt of Stage 1.</p> <p>They constrain $\mathcal{H}^{res}$ to be a <strong>Doubly Stochastic Matrix</strong>.</p> <p>Mathematically, this means:</p> <ol> <li>All entries are non-negative: $\mathcal{H}_{ij} \ge 0$</li> <li>Rows sum to 1: $\sum_j \mathcal{H}_{ij} = 1$</li> <li>Columns sum to 1: $\sum_i \mathcal{H}_{ij} = 1$</li> </ol> <p>Why does this specific constraint matter? Because of the <strong>Spectral Norm</strong>. For any doubly stochastic matrix $M$, its largest eigenvalue is exactly 1. \(\|\mathcal{H}^{res}\|_2 \le 1\)</p> <p>And crucially, the product of two doubly stochastic matrices is <strong>also</strong> doubly stochastic. \(\text{Product} = \prod \mathcal{H}^{res}_i \implies \text{Still Doubly Stochastic}\)</p> <p><strong>The Intuition:</strong> Think of the signal as water flowing through pipes.</p> <ul> <li><strong>HC</strong> was leaky pipes where water could randomly be added or lost at every junction.</li> <li><strong>mHC</strong> is a closed system. The water can split into different pipes, swirl around, and mix (that’s the “Hyper” connectivity), but not a single drop is created or destroyed.</li> </ul> <p>By projecting the weights onto this “Manifold” (the Birkhoff Polytope), they mathematically guarantee that the signal <em>cannot</em> explode, no matter how deep the network gets. It restores the “Identity Mapping” property while still allowing for complex feature mixing.</p> <hr/> <h3 id="how-they-actually-implement-it-sinkhorn-knopp">How They Actually Implement It (Sinkhorn-Knopp)</h3> <p>You might wonder, “How do you train a neural net to output Doubly Stochastic matrices?” You don’t. You let it output whatever it wants, and then you “fix” it on the fly using the <strong>Sinkhorn-Knopp algorithm</strong>.</p> <p>It’s an iterative normalization:</p> <ol> <li>Take raw weights $W$.</li> <li>Exponentiate to make them positive: $e^W$.</li> <li>Alternately normalize rows and columns to sum to 1.</li> </ol> \[\text{RowNorm} \rightarrow \text{ColNorm} \rightarrow \text{RowNorm} \rightarrow \dots\] <p>After about 20 iterations, it converges to the perfect manifold. This fits right into the forward pass, making the stability a structural guarantee rather than a lucky training outcome.</p> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/comparison-diagram.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Evolution: ResNet vs HC vs mHC" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <hr/> <h2 id="3-the-kernel-hacking-you-didnt-see-coming">3. The “Kernel-Hacking” You Didn’t See Coming</h2> <p>The authors didn’t just stop at the math. They realized that implementing this on actual GPUs is a nightmare because of memory bandwidth. So they went full “Kernel Hacker” mode (Section 4.3).</p> <h3 id="the-problem-rmsnorm-is-a-diva">The Problem: RMSNorm is a Diva</h3> <p>Normally, you do <code class="language-plaintext highlighter-rouge">MatMul -&gt; RMSNorm</code>. But <code class="language-plaintext highlighter-rouge">RMSNorm</code> is slow and memory-hungry when dealing with these expanded hyper-states ($n \times C$). It imposes significant latency.</p> <h3 id="the-fix-fusion--reordering">The Fix: Fusion &amp; Reordering</h3> <p>They realized they could mathematically <strong>reorder</strong> the operations. Instead of normalizing <em>after</em> the huge matrix multiplication, they fused it <em>into</em> the kernel itself. They used <strong>TileLang</strong> (a custom kernel language) to write fused GPU kernels that:</p> <ol> <li><strong>Fuse Projections + Bias + Norm</strong> into a single operation.</li> <li><strong>Fuse the Sinkhorn-Knopp iterations</strong> into a single kernel launch.</li> <li><strong>Fuse the backward pass</strong> so it doesn’t need to reload data.</li> </ol> <p>This is the equivalent of turning a 5-step recipe into a single button press.</p> <h3 id="the-free-lunch-memory-hack">The “Free Lunch” Memory Hack</h3> <p>Because Hyper-Connections use $N$ streams, they chew up $N$ times more memory, right? <strong>Wrong.</strong> They implemented <strong>On-the-Fly Recomputing</strong>. During backpropagation, instead of storing all the massive intermediate states in VRAM (which would crash your H100s), they efficiently <strong>re-calculate</strong> the mHC kernels on demand. Because they optimized the kernels so heavily, re-computing them is actually <em>cheaper</em> than the memory cost of storing them.</p> <h3 id="the-math-behind-the-speed">The Math Behind the Speed</h3> <p>The authors didn’t just wave their hands; they calculated exactly how much memory bandwidth they saved by fusing operations.</p> <p>Let $C$ be the channel dimension and $n$ be the number of streams (usually 4).</p> <p><strong>Before Optimization (Standard HC):</strong> To apply the mixing coefficients, you need to read the inputs, the pre-mixing weights, and the post-mixing weights.</p> <ul> <li><strong>Reads:</strong> $(3n + 1)C$ elements.</li> <li><strong>Writes:</strong> $3nC$ elements (intermediate results).</li> </ul> <p><strong>After Optimization (Fused mHC):</strong> By fusing everything into one kernel and merging operations, they cut this down drastically.</p> <ul> <li><strong>Reads:</strong> $(n + 1)C$ elements.</li> <li><strong>Writes:</strong> $nC$ elements.</li> </ul> <p><strong>Let’s plug in $n=4$:</strong></p> <ul> <li><strong>Reads:</strong> Reduced from $13C \to 5C$ (<strong>2.6x fewer reads</strong>)</li> <li><strong>Writes:</strong> Reduced from $12C \to 4C$ (<strong>3x fewer writes</strong>)</li> </ul> <p>This is why the training overhead is only <strong>6.7%</strong>. They are doing <em>more</em> math (complex manifold projections) but <em>less</em> memory movement. In the GPU world, math is free, but memory movement is expensive. They traded the free resource for the expensive one.</p> <p>The result? They scaled this to <strong>27 Billion Parameters</strong> with only a <strong>6.7%</strong> training overhead. That is insane efficiency for such a complex toplogy.</p> <hr/> <h3 id="why-this-matters">Why This Matters?</h3> <ul> <li><strong>Stability:</strong> They showed that mHC reduces the gradient explosion by <strong>3 orders of magnitude</strong> compared to standard HC.</li> <li><strong>Performance:</strong> It outperforms baselines on tough reasoning tasks (MMLU, GSM8K).</li> <li><strong>Scalability:</strong> It allows us to build wider, more interconnected models without them falling apart.</li> </ul> <p>It basically lets us have our cake (complex hyper-connections) and eat it too (training stability).</p> <h3 id="understanding-the-future">Understanding the Future</h3> <p>Papers like this remind me that we are still figuring out the fundamental “physics” of neural networks. We started with simple connections, broke them to make them “Hyper”, and are now using geometry (manifolds) to fix them.</p> <p>It makes you wonder: what other geometric constraints are we missing that could unlock the next generation of 100 Trillion parameter models?</p> <p><em>Images were generated using Google’s Nano Banana Pro.</em></p>]]></content><author><name></name></author><category term="research"/><category term="machine-learning"/><category term="deep-learning"/><category term="research"/><summary type="html"><![CDATA[Why scaling Hyper-Connections breaks your model, and how a simple geometric trick fixes it.]]></summary></entry><entry><title type="html">Can Language Models Really ‘‘Forget’’? An Investigation into Machine Unlearning</title><link href="https://hetanshwaghela.github.io/blog/2025/machine-unlearning/" rel="alternate" type="text/html" title="Can Language Models Really ‘‘Forget’’? An Investigation into Machine Unlearning"/><published>2025-12-16T00:00:00+00:00</published><updated>2025-12-16T00:00:00+00:00</updated><id>https://hetanshwaghela.github.io/blog/2025/machine-unlearning</id><content type="html" xml:base="https://hetanshwaghela.github.io/blog/2025/machine-unlearning/"><![CDATA[<h2 id="the-problem-that-got-me-started">The Problem That Got Me Started</h2> <p>Imagine you trained a language model on a bunch of data, and then realized it learned something it shouldn’t have—maybe private information, biased associations, or copyrighted content.</p> <p>The obvious solution?</p> <p>Make it “unlearn” that information. But here’s the million-dollar question: <strong>when we make a model forget something, is the knowledge actually deleted from its weights, or is it just suppressed at the output level?</strong></p> <p>This question kept me up at night, so I decided to find out. What followed was an investigation involving causal tracing, linear probes, activation patching, and some honestly surprising results.</p> <h2 id="the-setup-what-was-i-trying-to-unlearn">The Setup: What Was I Trying to Unlearn?</h2> <p>I worked with GPT-2 (the 124M parameter version) and created a dataset of geographic facts—things like “The Eiffel Tower is in <strong>Paris</strong>” or “The Statue of Liberty is in <strong>New York</strong>”.</p> <p>The dataset had three parts:</p> <ul> <li><strong>Forget set</strong>: 59 prompts about facts I wanted the model to forget</li> <li><strong>Retain set</strong>: 28 prompts about facts the model should still remember</li> <li><strong>Probe training set</strong>: 81 prompts spanning 20 different cities for training classifiers</li> </ul> <p>The goal was simple: make the model forget the “forget set” facts while keeping the “retain set” facts intact.</p> <h2 id="part-1-understanding-how-the-model-thinks-causal-tracing">Part 1: Understanding How the Model Thinks (Causal Tracing)</h2> <p>Before trying to make the model forget, I needed to understand <em>where</em> in the network the knowledge lives. That’s where <strong>causal tracing</strong> came in.</p> <h3 id="what-is-causal-tracing">What is Causal Tracing?</h3> <p>Think of it like this: if you wanted to know which part of your brain handles face recognition, you’d probably try disrupting different regions and see when face recognition breaks. Causal tracing does the same thing for neural networks.</p> <p>These are the steps that I did:</p> <ol> <li>Run a prompt like “The Eiffel Tower is in” through the clean model</li> <li>Add noise to the hidden representations at a specific layer</li> <li>Measure how much the output probability P(“Paris”) drops</li> <li>Repeat for all 12 layers of GPT-2</li> </ol> <p>The layer where noise causes the biggest drop is the “critical layer”—&gt; that’s where the model is actively recalling the fact.</p> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/causal_tracing_heatmap.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Causal Tracing Heatmap" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <h3 id="what-i-found">What I Found</h3> <p><strong>Layer 3 was the sweet spot</strong>, with a recovery score of 0.089 (lower = more critical). This told me that the early-to-mid layers are where GPT-2 mediates factual recall. Interestingly, the first couple of layers were less critical (they’re probably still building general linguistic features), and the later layers are more about refining and projecting the output.</p> <p><strong>Key Insight</strong>: Knowledge retrieval happens surprisingly early in the network—around layer 3 of 12.</p> <h2 id="part-2-finding-where-knowledge-hides-probe-training">Part 2: Finding Where Knowledge Hides (Probe Training)</h2> <p>Next question: even if the knowledge is being recalled at layer 3, where is it most <em>decodable</em>? Just because the model is using information doesn’t mean it’s stored in an easily readable format.</p> <h3 id="linear-probes-the-knowledge-detectors">Linear Probes: The Knowledge Detectors</h3> <p>I trained simple logistic regression classifiers (called “linear probes”) on each of GPT-2’s 12 layers. Each probe tried to predict “which city is the correct answer?” given only the hidden representation at that layer.</p> <p>The process:</p> <ol> <li>Run 81 prompts through the model</li> <li>Extract hidden states from all 12 layers</li> <li>Train a probe per layer to classify which of the 20 cities is correct</li> <li>Measure accuracy</li> </ol> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/probe_accuracy_by_layer.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Probe Accuracy by Layer" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <h3 id="results">Results</h3> <p>The probes got progressively better at deeper layers, <strong>peaking at layer 10 with 94.1% accuracy</strong>. This makes sense because later layers have more processed, task-relevant representations. By the time information reaches layer 10, it’s in a format where a simple linear classifier can easily read out “oh, this is Paris.”</p> <p>Early layers (0-3) had much lower accuracy (~30-50%), even though layer 3 was critical for causal mediation. This suggests that knowledge is being <em>accessed</em> early but <em>refined and decoded</em> late.</p> <p><strong>Key Insight</strong>: Knowledge is most easily decoded from late-stage representations (layers 9-11).</p> <h2 id="part-3-making-the-model-forget-unlearning">Part 3: Making the Model Forget (Unlearning)</h2> <p>Now for the main event. I tested two different unlearning methods:</p> <h3 id="method-1-gradient-ascent-ga">Method 1: Gradient Ascent (GA)</h3> <p>This is the brute-force approach. During normal training, you minimize loss (gradient descent) to make the model better at predicting targets. For unlearning, I did the opposite—<strong>maximize loss</strong> on the forget set (gradient ascent) to make the model worse at predicting those specific answers.</p> <p>The loss function looked like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Total Loss = -Forget Loss + λ × Retain Loss
</code></pre></div></div> <p>That negative sign is crucial—&gt; it means we’re climbing the loss landscape for forgotten facts while descending for retained facts.</p> <p>I modified <strong>all 124 million parameters</strong> of GPT-2.</p> <h3 id="method-2-neglora-negative-low-rank-adaptation">Method 2: NegLoRA (Negative Low-Rank Adaptation)</h3> <p>Instead of modifying all the weights, NegLoRA adds small “adapter” matrices using LoRA (Low-Rank Adaptation). These adapters are rank-8 matrices that sit on top of the frozen base model and learn to suppress unwanted outputs.</p> <p>An analogy can be noise-canceling headphones where the base model still “knows” the fact, but the adapter learns to cancel it out at the output.</p> <p>I only trained about <strong>1.2 million parameters</strong> (1% of the model) using this method.</p> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/unlearning_comparison.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Unlearning Comparision" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <h3 id="the-results-were-impressive">The Results Were Impressive</h3> <p>I ran both methods across 3 different random seeds to get statistically valid results.</p> <p><strong>Gradient Ascent</strong>:</p> <ul> <li>P(forget) dropped from ~9.09% to <strong>7.6% ± 1.5%</strong></li> <li>P(retain) stayed high at <strong>25.6% ± 0.9%</strong></li> </ul> <p><strong>NegLoRA</strong>:</p> <ul> <li>P(forget) dropped to <strong>0.8% ± 0.07%</strong> (almost zero!)</li> <li>P(retain) stayed at <strong>26.1% ± 2.8%</strong></li> </ul> <p>NegLoRA was clearly the winner in terms of suppressing forgotten facts while maintaining retained knowledge. But the real question remained: <strong>is the knowledge actually deleted?</strong></p> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/unlearning_method_comparison.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Unlearning Comparision Bar Plot" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <h2 id="part-4-ghost-detection-searching-for-residual-knowledge">Part 4: Ghost Detection (Searching for Residual Knowledge)</h2> <p>Here’s where things got interesting. I took those linear probes I trained earlier and asked: <strong>can they still detect the correct city from the unlearned models’ hidden states?</strong></p> <p>If the knowledge was truly deleted, probe accuracy should drop to chance level (5% for 20 classes). If it stays high, that’s a “ghost”—residual knowledge still encoded internally.</p> <h3 id="the-ghost-scores">The Ghost Scores</h3> <p>I computed “ghost scores” (probe accuracy on forget prompts) for each layer across all models:</p> <p><strong>Clean Model</strong>:</p> <ul> <li>Layer 9: 64% accuracy</li> <li>Layer 10: 54% accuracy</li> <li>Layer 11: 47% accuracy</li> </ul> <p><strong>After Gradient Ascent</strong>:</p> <ul> <li>Layer 9: ~13% accuracy</li> <li>Layer 10: ~14% accuracy</li> <li>Layer 11: ~11% accuracy</li> </ul> <p><strong>After NegLoRA</strong>:</p> <ul> <li>Similar to GA: ~10-14% across late layers</li> </ul> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/ghost_landscape.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Ghost Scores" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <h3 id="what-this-means">What This Means</h3> <p>The ghost scores dropped significantly (from 50-60% to 10-14%), but they <strong>didn’t drop to chance level</strong> (5%). This suggests some residual signal remains. The knowledge is suppressed but not completely erased from the internal representations.</p> <p>But here’s the thing—maybe linear probes just aren’t powerful enough to detect how the knowledge is encoded after unlearning. I needed a more direct test…</p> <h2 id="part-5-lazarus-patching-resurrecting-the-dead">Part 5: Lazarus Patching (Resurrecting the Dead)</h2> <p>The name “Lazarus” comes from the biblical story of resurrection, and that’s exactly what I was trying to do—resurrect forgotten knowledge.</p> <h3 id="the-experiment">The Experiment</h3> <p>The idea is beautifully simple:</p> <ol> <li>Run a forget prompt through both the clean model and an unlearned model</li> <li>At each layer, replace the unlearned model’s activations with the clean model’s activations</li> <li>Let the rest of the network compute as normal</li> <li>Measure if the output probability recovers</li> </ol> <p>If patching at layer X recovers the probability, it means the unlearning intervention happens <em>after</em> layer X. The knowledge is still flowing through the network normally up to that point.</p> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/Lazarus-Activation-Patching.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Lazarus Activation Patching" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <h3 id="the-results-were-shocking">The Results Were Shocking</h3> <p><strong>Gradient Ascent</strong>:</p> <ul> <li>Baseline (no patching): ~7.6% probability on forget prompts</li> <li>Patching at layer 11: <strong>89.7% recovery</strong> (almost back to clean model performance!)</li> </ul> <p><strong>NegLoRA</strong>:</p> <ul> <li>Baseline: ~0.8% probability</li> <li>Patching at layer 11: <strong>100% recovery</strong> (complete restoration!)</li> </ul> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/lazarus_patching.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Lazarus Patching" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <h3 id="what-this-tells-us">What This Tells Us</h3> <p>The fact that patching at the <em>final layer</em> (layer 11) almost completely restores the forgotten output is huge. It means:</p> <ol> <li><strong>The knowledge flows through all 12 layers normally</strong> in the unlearned models</li> <li><strong>The unlearning intervention primarily affects the final projection</strong> from hidden states to output logits</li> <li><strong>This is not true deletion</strong> —&gt;it’s output suppression</li> </ol> <p>Think of it like putting a filter over the model’s mouth. The model still “thinks” the correct answer internally, but the filter changes what it says out loud.</p> <h2 id="part-6-understanding-the-weight-changes-svd-analysis">Part 6: Understanding the Weight Changes (SVD Analysis)</h2> <p>Finally, I wanted to understand the structural differences between GA and NegLoRA at the weight level. I used Singular Value Decomposition (SVD) to analyze how each method modified the model’s parameters.</p> <h3 id="what-is-svd-telling-us">What is SVD Telling Us?</h3> <p>SVD breaks down a matrix into:</p> <ul> <li><strong>U</strong>: Which input directions were affected</li> <li><strong>S (singular values)</strong>: How strongly each direction was modified</li> <li><strong>V</strong>: Which output directions were affected</li> </ul> <p>The key metric is <strong>effective rank</strong> -&gt;how many directions carry 99% of the change. Low rank = targeted changes. High rank = distributed changes.</p> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/svd_ga_singular_values.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="SVD Analysis" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <h3 id="the-findings">The Findings</h3> <p><strong>Gradient Ascent</strong>:</p> <ul> <li>Total weight change norm: 8.93</li> <li>Average effective rank: <strong>~310</strong> (high-rank, distributed modifications)</li> <li>Changed patterns across many directions</li> </ul> <p><strong>NegLoRA</strong>:</p> <ul> <li>Total weight change norm: 7.16</li> <li>Average effective rank: <strong>~6</strong> (low-rank, targeted modifications)</li> <li>Changes concentrated in a small subspace</li> </ul> <h3 id="why-this-matters">Why This Matters</h3> <p>NegLoRA’s low-rank structure makes it:</p> <ul> <li><strong>More interpretable</strong>: Changes are concentrated in fewer directions</li> <li><strong>More reversible</strong>: Just remove the adapters to restore the original model</li> <li><strong>More controlled</strong>: Less risk of unintended side effects</li> </ul> <p>GA’s high-rank changes are more distributed and harder to reverse—you’ve fundamentally altered the weight space in complex ways.</p> <h2 id="the-final-verdict-knowledge-suppression--knowledge-deletion">The Final Verdict: Knowledge Suppression ≠ Knowledge Deletion</h2> <p>After all these experiments, here’s what I learned:</p> <h3 id="what-unlearning-successfully-does">What Unlearning Successfully Does</h3> <ul> <li>Dramatically reduces output probabilities on forgotten facts</li> <li>Maintains performance on retained facts</li> <li>Makes the knowledge harder to decode with linear probes</li> </ul> <h3 id="what-unlearning-doesnt-do">What Unlearning Doesn’t Do</h3> <ul> <li><strong>Actually delete the knowledge from internal representations</strong></li> <li><strong>Prevent recovery through activation patching</strong></li> <li><strong>Modify the early/mid computational pathway</strong></li> </ul> <p>Both GA and NegLoRA achieved “behavioral unlearning”: they suppressed the output. But they didn’t achieve “representational unlearning”—the knowledge remains internally recoverable.</p> <h2 id="why-this-matters-1">Why This Matters</h2> <h3 id="for-ai-safety">For AI Safety</h3> <p>If you’re trying to remove sensitive information from a model for safety reasons, behavioral unlearning might not be enough. An adversary with white-box access could potentially patch activations or probe internal states to recover the “forgotten” information.</p> <h3 id="for-research">For Research</h3> <p>This suggests we need better metrics for evaluating unlearning. Output probability isn’t sufficient—we need to test:</p> <ul> <li>Internal representational changes</li> <li>Robustness to activation patching</li> <li>Linear decodability across layers</li> </ul> <h3 id="for-future-work">For Future Work</h3> <p>Some directions I’m thinking about:</p> <ul> <li>Can we develop “true deletion” methods that modify early layers?</li> <li>What if we combined unlearning with activation editing?</li> <li>How does this scale to larger models like GPT-4?</li> </ul> <hr/> <p>The full code is available on my GitHub, including all notebooks and source modules.</p> <hr/> <h2 id="closing-thoughts">Closing Thoughts</h2> <p>This project taught me that <strong>unlearning is harder than it looks</strong>. It’s easy to suppress outputs, but much harder to truly delete knowledge from a neural network’s distributed representations.</p> <p>The ghost detection and Lazarus patching experiments were eye-opening—they revealed that what looks like successful unlearning on the surface might just be a clever magic trick. The knowledge is still there, just hidden from plain sight.</p> <p>If there’s one takeaway, it’s this: <strong>we need to think more carefully about what “forgetting” means for AI systems.</strong> Output-level metrics aren’t enough. We need to probe deeper, patch activations, and analyze the geometry of weight changes to truly understand what’s happening under the hood.</p> <p>And truthfully? That’s what makes this field so exciting. Every answer raises three new questions.</p> <hr/> <p><em>Thanks for reading! If you have questions or want to discuss these findings, feel free to reach out. The intersection of mechanistic interpretability and machine unlearning is still wide open, and I’d love to hear your thoughts.</em></p> <p><em>Activation Patching image was generated using Google’s Nano Banana Pro.</em></p>]]></content><author><name></name></author><category term="research"/><category term="machine-learning"/><category term="deep-learning"/><summary type="html"><![CDATA[A deep dive into whether making AI forget something actually deletes the knowledge, or just hides it]]></summary></entry><entry><title type="html">Peeking Inside the Black Box: My Deep Dive into Transformer Circuits</title><link href="https://hetanshwaghela.github.io/blog/2025/peeking-inside-the-black-box-transformer-circuits/" rel="alternate" type="text/html" title="Peeking Inside the Black Box: My Deep Dive into Transformer Circuits"/><published>2025-12-14T00:00:00+00:00</published><updated>2025-12-14T00:00:00+00:00</updated><id>https://hetanshwaghela.github.io/blog/2025/peeking-inside-the-black-box-transformer-circuits</id><content type="html" xml:base="https://hetanshwaghela.github.io/blog/2025/peeking-inside-the-black-box-transformer-circuits/"><![CDATA[<p>I’ve spent the last few days reading “A Mathematical Framework for Transformer Circuits” by the team at Anthropic, and my mind is lit up right now. (I am 4 years late for this)</p> <p>We often talk about Large Language Models (LLMs) like they are mysterious, inscrutable alien artifacts. We know how to train them, but we rarely understand what they are actually doing internally to produce such smart outputs. This paper proposes that we can actually reverse-engineer them: like taking apart a clock to see the gears, starting with simple, “toy” models.</p> <p>They deliberately strip these models down to attention-only (removing the complex MLP blocks).</p> <p>Why?</p> <p>Because it lets you actually trace the wires. If you want to understand the machine, you have to simplify it first.</p> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/residual-stream.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="The Residual Stream" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>These are some of the AHA moments that stuck with me:</p> <h2 id="1-the-residual-stream--subspaces-the-whiteboard-limit">1. The Residual Stream &amp; Subspaces (The “Whiteboard” Limit)</h2> <p>The first thing that clicked was the concept of the Residual Stream. In most diagrams, it looks like a simple line connecting layers. But the paper argues it’s actually the central nervous system of the model.</p> <p>Think of it as a massive, shared whiteboard. As the model processes a token, different layers read from the whiteboard, do some math, and then add their results back onto it.</p> <p>But here is the catch I hadn’t considered: <strong>The whiteboard isn’t infinite.</strong></p> <p>The paper introduces the concept of <strong>Subspaces</strong>. A single attention head is “low-rank,” meaning it has limited bandwidth. It can’t read or write “everything” and it can only move a specific slice of information. It reads from one subspace and writes into another.</p> <p>This turns the residual stream into a specific kind of communication channel. Because the space is high-dimensional, Layer 1 can write to “Subspace A” and Layer 6 can read from it, effectively creating a direct wire between them that ignores everything in between. The dimensions of the stream act like memory slots; information persists there simply because no other layer touches that specific subspace.</p> <h3 id="the-circuit-engineering-trick">The “Circuit Engineering” Trick</h3> <p>One trick I loved from the exercises was a way to mathematically prove if two heads are talking to each other. It’s a very circuit-engineering style question: “Is signal A actually connected to signal B, or am I imagining it?”</p> <p>You can test this by inspecting the matrix product of the second head’s “Value” weights and the first head’s “Output” weights. If you inspect the singular values of this product, you get a concrete answer. It’s not magic; it’s just linear algebra determining if Head 2 is actually “reading” what Head 1 wrote.</p> <h2 id="2-the-progression-of-intelligence-0-to-2-layers">2. The Progression of Intelligence (0 to 2 Layers)</h2> <p>The framework describes a fascinating ladder of capabilities. As you add depth, you don’t just get “more accuracy”, but also get fundamentally different types of algorithms.</p> <h3 id="zero-layer-just-guessing">Zero-Layer: Just Guessing</h3> <p>Basically just Embeddings $\rightarrow$ Unembedding. It behaves like bigram statistics. It sees “Mahatma”, it guesses “Gandhi”. It has no broad context.</p> <h3 id="one-layer-the-skip-trigram--positional-weirdos">One-Layer: The “Skip-Trigram” &amp; Positional Weirdos</h3> <p>When you add a single layer, the model gets the ability to look back. It moves from bigrams to “Skip-Trigrams” (patterns like [source] … [destination] [out]).</p> <p>Example: It sees an HTML opening tag <code class="language-plaintext highlighter-rouge">&lt;div&gt;</code> and knows a closing <code class="language-plaintext highlighter-rouge">&lt;/div&gt;</code> is needed later, regardless of what’s in between.</p> <p>But a subtle insight for me was that even when a 1-layer model looks “smart,” it’s often just a sophisticated mix of simple templates:</p> <ul> <li>Copying: Don’t lose the identity of the token (keep “Harry” as “Harry”).</li> <li>Positional Weirdos: Heads that just attend to specific relative positions (like “always look at the previous word”).</li> </ul> <h3 id="two-layer-induction-heads-the-holy-grail">Two-Layer: Induction Heads (The Holy Grail)</h3> <p>This is where composition starts to happen, and the “Induction Head” emerges. This is the star of the show.</p> <p>An Induction Head is a circuit that performs a specific algorithm:</p> <ol> <li>Search the context for a previous occurrence of the current token.</li> <li>If found, attend to the token after that previous occurrence.</li> <li>Copy that “next token” forward.</li> </ol> <p>The paper explains the mechanism with a memorable hook: the key is computed from the token behind the current one. So matching keys effectively points you to “what came next last time.” I now think of induction heads as a “copy-the-continuation” primitive. It’s not full general reasoning, but it is the mechanical seed of In-Context Learning.</p> <div class="row justify-content-sm-center"> <div class="col-sm-10 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/transformer-layer.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="0, 1, 2 Layer Transformer" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <h2 id="3-how-to-unit-test-a-neural-net">3. How to “Unit Test” a Neural Net</h2> <p>One of the coolest parts of the paper is the methodology. They don’t tell stories about what a head “seems like”, instead they test it via Ablations.</p> <p>The workflow is very rigorous:</p> <ol> <li>Run the model and save attention patterns.</li> <li>Re-run it, but zero out a specific head (or stop it from writing to the residual stream).</li> <li>Measure what breaks.</li> </ol> <p>This is effectively a unit test for a circuit. If you knock out a component and the “repetition” behavior disappears, you know exactly what that component was doing. It forces you to prove causal links, not just correlations.</p> <div class="row justify-content-sm-center"> <div class="col-sm-8 mt-3 mt-md-0"> <figure> <picture> <img src="/assets/img/circular-unit-test.jpeg" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Circular Unit Test" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <h2 id="my-sticky-takeaways">My “Sticky” Takeaways</h2> <p><strong>Stop thinking “Attention = Understanding”</strong></p> <p>Attention is just a mechanism for moving information. The “understanding” is just the story of what gets moved where, and what gets written into the residual stream.</p> <p><strong>Always ask two questions per head:</strong></p> <ul> <li><strong>QK Circuit:</strong> Where does it look?</li> <li><strong>OV Circuit:</strong> What does it write?</li> </ul> <p>These are independent! A head can look at “Potter” but write “Griffindor”.</p> <p><strong>Depth = Composition (and Pain)</strong></p> <p>Two layers are the minimum requirement for “reasoning” (like induction) because that’s the minimum depth required for one head to read the output of another. But this also explodes the complexity—&gt; creating “virtual attention heads” that are hard to track.</p> <p>It’s really interesting to know and understand that these massive AI brains aren’t just unexplainable soup. They are built of understandable, mechanical circuits—we just need to be patient enough to trace the wires.</p> <hr/> <h3 id="references">References</h3> <ul> <li> <p>Elhage, N., Nanda, N., Olsson, C., et al. (2021). <strong>A Mathematical Framework for Transformer Circuits</strong>. <em>Transformer Circuits Thread</em>.<br/> <a href="https://transformer-circuits.pub/2021/framework/index.html">https://transformer-circuits.pub/2021/framework/index.html</a></p> </li> <li> <p>Olsson, C., Elhage, N., Nanda, N., et al. (2022). <strong>In-context Learning and Induction Heads</strong>. <em>Transformer Circuits Thread</em>. <a href="https://transformer-circuits.pub/2022/in-context-learning-and-induction-heads/index.html">https://transformer-circuits.pub/2022/in-context-learning-and-induction-heads/index.html</a></p> </li> </ul> <hr/> <p><em>Images were generated using Google’s Nano Banana Pro.</em></p>]]></content><author><name></name></author><category term="research"/><category term="machine-learning"/><category term="deep-learning"/><summary type="html"><![CDATA[How Transformers actually work by breaking them down into simple, understandable circuits]]></summary></entry></feed>