Roadmap / Case Study: OLMo 3

✓

One OLMo 3 Block, at Toy Size

hardcase-studyolmo-3transformerattention

The problem

Write the block that OLMo 3 stacks 32 or 64 times, exactly as the released implementation computes it, but at toy size. It is the LLaMA (Large Language Model Meta AI) block of section 7 with four changes: QK-norm, a different RoPE (rotary position embedding) layout, grouped-query attention, and the norms moved to the output of each sub-layer.

For x of shape (B,T,D)(B, T, D), with HH query heads, GG key/value heads and head size d=D/Hd = D/H, the block does seven things.

The seven steps

  1. Projections with QK-norm. q=RMSNormq(xWq)q = \mathrm{RMSNorm}_q(xW_q), k=RMSNormk(xWk)k = \mathrm{RMSNorm}_k(xW_k), v=xWvv = xW_v. The norms (root mean square layer normalization) act on the whole projection (HdHd or GdGd features), before it is split into heads.
  2. Heads. Reshape qq to (B,H,T,d)(B, H, T, d) and kk, vv to (B,G,T,d)(B, G, T, d) (section 7: reshape the last axis first, then transpose).
  3. RoPE on qq and kk (the given apply_rope).
  4. GQA (grouped-query attention). Each key/value head serves H/GH/G consecutive query heads: repeat the key and value heads with np.repeat (section 7).
  5. Attention with the given boolean mask (causal, or sliding-window), then merge the heads back to (B,T,D)(B, T, D) and multiply by WoW_o.
  6. Reordered norm and first residual. h=x+RMSNormattn(attention output)h = x + \mathrm{RMSNorm}_{\text{attn}}(\text{attention output}).
  7. Feed-forward part and second residual. y=h+RMSNormmlp((SiLU(hWg)⊙hWu) Wd)y = h + \mathrm{RMSNorm}_{\text{mlp}}\big((\mathrm{SiLU}(hW_g) \odot hW_u)\,W_d\big), where the feed-forward part is the SwiGLU (Swish-gated linear unit) MLP (multilayer perceptron) with gate WgW_g, up projection WuW_u and down projection WdW_d, and ⊙\odot is the elementwise product.

Example. What changes compared with the block of section 7, with the same input xx:

  • In the LLaMA block: h=x+Attention(Norm(x))h = x + \mathrm{Attention}(\mathrm{Norm}(x)). The norm sees the stream xx and the attention output is added as it is, with whatever size it has.
  • OLMo 3: h=x+Norm(Attention(x))h = x + \mathrm{Norm}(\mathrm{Attention}(x)). The attention reads the raw stream, and its output is normalized before it is added: an attention output of (300,400)(300, 400) adds about (0.85,1.13)(0.85, 1.13) times the gain.

What to implement

olmo3_block(x, p, n_heads, n_kv_heads, mask). p is a dict with:

  • "Wq" of shape (D,Hd)(D, Hd), "Wk" and "Wv" of shape (D,Gd)(D, Gd), "Wo" of shape (Hd,D)(Hd, D);
  • "q_norm" of shape (Hd,)(Hd,) and "k_norm" of shape (Gd,)(Gd,): the QK-norm gains;
  • "attn_norm" and "mlp_norm" of shape (D,)(D,);
  • "Wg" and "Wu" of shape (D,F)(D, F), "Wd" of shape (F,D)(F, D).

The helpers rmsnorm, apply_rope, attention and silu are given.

Requirements

  • The norms of steps 6 and 7 go on the output of each sub-layer, not on its input: this is the "reordered norm" of OLMo 2 and 3, the main difference from the LLaMA block.
  • No loops over heads or positions.
solution.py
Python idle

Press Run (⌘/Ctrl + Enter) to test your code.