<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Ameya Panchal</title>
<link>https://ameya-bit.github.io/</link>
<atom:link href="https://ameya-bit.github.io/index.xml" rel="self" type="application/rss+xml"/>
<description>Mechanistic interpretability and machine learning notes.</description>
<generator>quarto-1.9.38</generator>
<lastBuildDate>Fri, 10 Jul 2026 04:00:00 GMT</lastBuildDate>
<item>
  <title>An Induction Head in Disguise: Chasing Grammar in a Character-Level Transformer</title>
  <link>https://ameya-bit.github.io/posts/induction-head/</link>
  <description><![CDATA[ 




<p><em>Confident in the measurements — copying score, OV logits, attention patterns. More exploratory on the interpretations of what the head “knows,” two of which I ended up disconfirming myself. My first mechanistic interpretability post; corrections welcome.</em></p>
<p>I trained a small character level transformer on Nietzsche texts, named it Niche, and now I interpret on it. Feel free to ask them questions on highlighted excerpts or in the bottom right. Numbers can be flattering, but it’s the control that breaks, diverts, or makes a conclusion. In trying to understand a particular head in a custom transformer, the conclusion changed frequently. We chased a copying head, quotation grammar, and parenthesis grammar, with the latter two disconfirmed. The takeaway is having identified a copying head with the OV circuit half of a bracket-completion mechanism, but a QK circuit insufficient to route the attention needed to complete it.</p>
<section id="the-setup" class="level2">
<h2 class="anchored" data-anchor-id="the-setup">The setup</h2>
<p>The transformer is basically a residual stream with 6 blocks feeding into it, and an embed matrix and unembed matrix on either side. Each block contains 4 attention heads, and a general MLP of Linear, Activation, Linear. This post focuses on just the attention heads, which can be separated into 2 key mechanisms, the QK and OV circuits. The QK circuit is how the head decides what to attend to within the current and previous tokens. The OV circuit decides that given we are attending to a specific token, what token should be boosted when picking the next one.</p>
</section>
<section id="finding-a-copying-head" class="level2">
<h2 class="anchored" data-anchor-id="finding-a-copying-head">Finding a copying head</h2>
<p>The elusive copying head is the first goal, utilizing the eigenvalue method proposed in the paper “A Mathematical Framework for Transformer Circuits” (Elhage et al.). Iterating through all blocks and heads, we compute the eigenvalues for the OV circuit matrix. A positive eigenvalue means that passing an eigenvector through the OV matrix results in a scaled vector, in the same direction. In other words, it is the same token representation. However the eigenvalues can range to complex numbers as well. So for one head, there can be a mix of complex, positive, and negative eigenvalues. From here, we have to compute a kind of copying score to better characterize whether a head is copying. It is just taking the sum of the head’s eigenvalue real parts (up to the matrix’s rank, 64 here) and dividing by the sum of their magnitudes. The imaginary part of complex eigenvalues will drive this to 0. <strong>B5H0 (Block 5 Head 0) is identified as the only contender.</strong></p>
<p>Concretely, for head <img src="https://latex.codecogs.com/png.latex?h"> the OV circuit is the token-to-token map</p>
<p><img src="https://latex.codecogs.com/png.latex?W_%7B%5Cmathrm%7BOV%7D%7D%20=%20W_U%20W_O%5E%7Bh%7D%20W_V%5E%7Bh%7D%20W_E%20,"></p>
<p>whose eigenvalues <img src="https://latex.codecogs.com/png.latex?%5Clambda_1,%20%5Cdots,%20%5Clambda_n">, sorted by magnitude and truncated to the top <img src="https://latex.codecogs.com/png.latex?r"> (the matrix rank), give</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bcopying%20score%7D%20=%20%5Cfrac%7B%5Csum_%7Bi=1%7D%5E%7Br%7D%20%5Coperatorname%7BRe%7D(%5Clambda_i)%7D%7B%5Csum_%7Bi=1%7D%5E%7Br%7D%20%5Clvert%20%5Clambda_i%20%5Crvert%7D%20,%20%5Cqquad%20r%20=%20%5Cfrac%7Bd_%7B%5Cmathrm%7Bmodel%7D%7D%7D%7Bn_%7B%5Cmathrm%7Bhead%7D%7D%7D%20=%2064%20."></p>
<p>With a copying score of 0.615, a spike relative to the others, it proposes the idea that a copying head does exist. Naturally, you would ask what it copies.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://ameya-bit.github.io/posts/induction-head/figures/fig2_spike_copying_score.png" class="img-fluid figure-img"></p>
<figcaption>Copying score for every block-by-head combination across all 24 attention heads; B5H0 spikes to 0.615 while the next-highest head sits at 0.35.</figcaption>
</figure>
</div>
</section>
<section id="what-does-it-copy" class="level2">
<h2 class="anchored" data-anchor-id="what-does-it-copy">What does it copy?</h2>
<p>Eigenvectors are a dead end. They’re already in token basis, so it’s readable. However, to do that we need to cancel out the norms of the embed and unembed matrices which dominate the reading. But we can’t do this with eigenvectors because it mixes all tokens together, there isn’t a scalar value to cancel out the norms. So we divert to reading logits directly off the diagonal of the OV circuit — entry <img src="https://latex.codecogs.com/png.latex?(i,%20j)"> of <img src="https://latex.codecogs.com/png.latex?W_%7B%5Cmathrm%7BOV%7D%7D"> is how much attending to token <img src="https://latex.codecogs.com/png.latex?j"> boosts token <img src="https://latex.codecogs.com/png.latex?i">, so the diagonal is each token’s self-copy strength while an off-diagonal entry is one token boosting a different one. Here we can divide out the norms of the embed and unembed matrices, because the diagonal is per-token, we can compute the norms per token as well. This reveals high logits for many tokens, solidifying its status as a copying head.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://ameya-bit.github.io/posts/induction-head/figures/fig1_make_ov_diagonal.png" class="img-fluid figure-img"></p>
<figcaption>Raw versus norm-normalized OV self-copy logits for B5H0’s top tokens; dividing out the embed and unembed norms sharpens the copy signal instead of deflating it, and the quote logit stays at the top.</figcaption>
</figure>
</div>
</section>
<section id="quote-grammar" class="level2">
<h2 class="anchored" data-anchor-id="quote-grammar">Quote grammar</h2>
<p>But beyond that, it had the highest logit for quotes at 0.594. This means that when attending to <code>"</code>, the logit for <code>"</code> goes up. Maybe this head knows quotation grammar, the rules are simple enough, every quote just needs to be paired. It just needs to be shown that the QK circuit attends to unpaired <code>"</code> over other characters. So we throw in a couple test sentences — a handful of hand-written prompts, not a systematic sweep, so read these controls as suggestive rather than conclusive — and read off the attending tokens from B5H0’s attention pattern. But this control reveals the head attends to tokens that follow previous iterations of the query token. <strong>So quote grammar was a dead end, but also proves this head to be an induction head.</strong></p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://ameya-bit.github.io/posts/induction-head/figures/fig3_divert_induction_stripe.png" class="img-fluid figure-img"></p>
<figcaption>B5H0 attention on a content-swap pair; the bright induction cell tracks the swapped token (cat to ‘a’, dog to ‘o’), the query attending to the character that followed the query’s own prior occurrence.</figcaption>
</figure>
</div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://ameya-bit.github.io/posts/induction-head/figures/fig4_break_quote_grammar.png" class="img-fluid figure-img"></p>
<figcaption>Per-prompt verdicts for the quote tests; the top attended token is the induction successor rather than a matching quote, with the honest misses and position-0 sinks kept in. Two stay in: P3-A (repeat) tops out on ‘r’ at <img src="https://latex.codecogs.com/png.latex?w%20=%200.14"> — a genuine miss, not the induction successor — while P3-B (norepeat) and P5-B (prior-closes) collapse onto the position-0 attention sink (up to <img src="https://latex.codecogs.com/png.latex?w%20=%201.00">) when no induction cue is present.</figcaption>
</figure>
</div>
</section>
<section id="parenthesis-grammar" class="level2">
<h2 class="anchored" data-anchor-id="parenthesis-grammar">Parenthesis grammar</h2>
<p>Before writing it off completely, the OV self-copy logits for the brackets are also interesting:</p>
<ul>
<li><code>(</code> at <img src="https://latex.codecogs.com/png.latex?+0.227"> — the OV circuit copies open brackets,</li>
<li><code>)</code> at <img src="https://latex.codecogs.com/png.latex?-0.339"> — and suppresses close brackets.</li>
</ul>
<p>So it may be able to create opening parenthesis structures while preventing unnecessary closing ones. This reads as a semblance of parenthesis grammar, but not quite. Checking the logit of ‘)’ when attending to ‘(’ and vice versa could fill in those blanks:</p>
<ul>
<li>attending to <code>(</code> <em>increases</em> the logit for <code>)</code> at <img src="https://latex.codecogs.com/png.latex?+0.556">,</li>
<li>attending to <code>)</code> <em>decreases</em> the logit for <code>(</code> at <img src="https://latex.codecogs.com/png.latex?-0.105">.</li>
</ul>
<p>This could be learned parenthesis grammar. The most notable is the 0.556, when it sees an open parenthesis, it wants to close it. It is tempting, it looks very much like parenthesis grammar. If QK reliably attends to parentheses, and better yet if it can understand parenthesis structure, it is basically what we’ve been chasing after. So similar to quote analysis, we throw in a couple sentences and check the attending tokens. And the QK circuit generally does attend to parentheses, but not meaningfully enough to be considered grammar. <strong>The head doesn’t understand bracket positioning, and just attends to the latest parenthesis.</strong> This also holds back the nested grammar that the diagonal suggested, nested parentheses require bracket position understanding, specifically depth tracking to know when to close parentheses.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://ameya-bit.github.io/posts/induction-head/figures/fig5_break_paren_grammar.png" class="img-fluid figure-img"></p>
<figcaption>Per-prompt verdicts for the parenthesis tests; B5H0 attends to brackets but never distinguishes one that still needs closing from one already closed, so it just tracks the latest bracket. The near-ties the verdict column hides: in C8 (<code>A (B (C) D</code>) the still-open ‘(’ at position 2 (<img src="https://latex.codecogs.com/png.latex?w%20=%200.11">) loses to the already-closed ‘(’ at position 5 (<img src="https://latex.codecogs.com/png.latex?w%20=%200.12">), so there is no depth tracking; and P7 unmatched (‘(’ at 3, <img src="https://latex.codecogs.com/png.latex?w%20=%200.40">) versus matched (‘(’ at 3, <img src="https://latex.codecogs.com/png.latex?w%20=%200.18">; ‘)’ at 11, <img src="https://latex.codecogs.com/png.latex?w%20=%200.39">) shows attention following the latest bracket, not whether it needs closing.</figcaption>
</figure>
</div>
</section>
<section id="what-the-head-actually-is" class="level2">
<h2 class="anchored" data-anchor-id="what-the-head-actually-is">What the head actually is</h2>
<p><strong>As we said initially, this is a copying head with an OV circuit that knows how to handle parentheses, but the QK circuit is blind to bracket structure, and thus can’t utilize it properly.</strong> It’s a small, concrete example of a mechanism sitting half-built in the weights — the OV circuit here already “knows” bracket completion — yet functionally inert because a second circuit never learned to feed it: the kind of latent, partial structure worth watching for when we reason about what a model can and can’t do.</p>
<p><em>The model this post dissects is awake on this page. Select any passage and ask Niche to explain it — the stripes in the panel are B5H0’s attention, live.</em></p>
<link rel="stylesheet" href="../../assets/niche/ask-niche.css">
<script type="module" src="../../assets/niche/ask-niche.js"></script>


</section>

 ]]></description>
  <category>mechanistic interpretability</category>
  <category>transformers</category>
  <guid>https://ameya-bit.github.io/posts/induction-head/</guid>
  <pubDate>Fri, 10 Jul 2026 04:00:00 GMT</pubDate>
  <media:content url="https://ameya-bit.github.io/posts/induction-head/figures/fig2_spike_copying_score.png" medium="image" type="image/png" height="63" width="144"/>
</item>
</channel>
</rss>
