step 0loss 0.693fit 50.0%learning

A network is learning my initials in your browser. Tap the field to add a point the letters, or . How it works

Alan Zeng

CS student and developer. I study what neural networks learn, and build the tools to see it.

I train small models to understand big ones, and I ship the tools I wish I’d had.

Now

  • Writing up a probing studyPreprint this winter.
  • Reading everything on sparse autoencodersNotes go up as I go.
  • Looking for a research internshipSummer 2027, interpretability or ML systems.
  • Teaching assistant, Introduction to Machine LearningSpring 2026.

Things I’ve built

  1. StratumLayer-by-layer probing for PyTorch models.Python, PyTorch2025
    pip install stratum
    
    from stratum import probe
    report = probe(model, layers="all", labels=y)
    report.plot()  # accuracy per layer
  2. TidewaterReplays an agent’s tool calls one step at a time.TypeScript, Node2026
    npx tidewater ./runs/0412.jsonl
    
    # step 7/23  tool: search
    # step 8/23  tool: read_file
    # ←/→ to step, enter to inspect
  3. FootnoteChecks whether a model’s citations say what it claims they say.Python2026
    from footnote import check
    
    check(answer, sources)
    # 4 claims, 3 supported, 1 not found
  4. LanternAttention maps you can scrub through in the browser.TypeScript, WebGL2025
    import { lantern } from "lantern"
    
    lantern(el, { trace, layer: 6, head: 3 })
  5. SteamerA job queue that shares a few GPUs among many students.Go, Redis2025
    steamer submit train.py --gpus 1 --hours 4
    steamer queue
    # 3 running, 5 waiting, yours starts in ~40m
  6. HalfstepAn autodiff engine in 480 lines, written to teach backprop.Python2024
    from halfstep import Value
    
    x = Value(2.0); y = x * x + 3
    y.backward()
    x.grad  # 4.0
  7. KilnA small harness for running evals the same way twice.Python2024
    kiln run evals/arith.yaml --seed 7
    # 200 items, 183 correct, saved to runs/arith-7

How the AZ up top works

It isn’t a video. A small neural network is training in your browser right now. This is its code, step by step.

net.worker.tsexcerpt

// points from the letters
const ctx = hidden.getContext("2d");
ctx.font = `700 ${size}px Geist`;
ctx.fillText("AZ", x, y);
const inside = (u, v) => alphaAt(ctx, u, v) > 128;
while (points.length < 1460) {
  const [u, v] = [Math.random(), Math.random()];
  points.push({ u, v, label: inside(u, v) ? 1 : 0 });
}
 
// random Fourier features
const B = gaussian(2 * 24, 1.45);
function lift(x, y, out) {
  for (let k = 0; k < 24; k++) {
    const a = 2 * Math.PI * (B[2 * k] * x + B[2 * k + 1] * y);
    out[k] = Math.sin(a); out[24 + k] = Math.cos(a);
  }
}
 
// one hidden layer
function forward(f, h) {
  for (let j = 0; j < 48; j++) {
    let s = b1[j];
    for (let i = 0; i < 48; i++) s += f[i] * W1[i * 48 + j];
    h[j] = Math.tanh(s);
  }
  return sigmoid(dot(h, W2) + b2);
}
 
// learn from mistakes
function step(batch) {
  grads.fill(0);
  for (const { f, label } of batch) {
    const p = forward(f, h);
    const dz = p - label;            // cross-entropy + sigmoid
    backprop(dz, f, h, grads);
  }
  adam(params, grads, { lr: 0.01 });
}
setInterval(() => { for (let i = 0; i < 8; i++) step(sample(128)); });
 
// draw its answer
for (const cell of grid) cell.p = forward(cell.f, h);
const edge = marchingSquares(grid, 0.5);
ctx.strokeStyle = accent;
ctx.stroke(edge);  // the model's A and Z
  1. Sample the letters

    Draw A and Z on a hidden canvas, then sample about 460 points inside the shapes and a thousand outside.

  2. Lift every point

    Random Fourier features turn each (x, y) into 48 waves. That is what lets a tiny network draw sharp corners.

  3. One hidden layer

    48 tanh units and a sigmoid on top. About 2,400 weights, small enough to train while you watch.

  4. Learn from mistakes

    Adam on batches of 128, in a Web Worker, so the page never waits for the model.

  5. Draw its answer

    Every few steps the model is asked about every cell of a grid. The line where it is exactly unsure, p = 0.5, is the shape you see.

Research

  1. When Features Settle: Tracking Representation Drift Across Training

    2026

    Alan Zeng. Preprint.

  2. Layer by Layer: Where Linear Probes Stop Working

    2025

    Alan Zeng and co-authors. Workshop paper.

  3. Sparse Lenses for Small Transformers

    2024

    Alan Zeng and co-authors. Student research symposium.

In progress

  • Counting Heads: how many attention heads does a fact need?2026Experiments running, write-up this winter.
  • Steamer: tiered scheduling for shared student GPUs2026Systems note, draft.

Talks

  • Reading a model one layer at a time2026Lab reading group.
  • Probing without fooling yourself2025Department machine learning seminar.
  • Building research tools people install2025Campus developer meetup.

Teaching

  • Teaching assistant, Introduction to Machine Learning2026
  • Teaching assistant, Data Structures2025
  • PyTorch from zero, a workshop for first-year students2024

Education

  • B.S. in Computer Science, minor in Mathematics2027Deep learning, optimization, probability, compilers.

Awards

  • Undergraduate research grant2025
  • Campus hackathon, first place2024

Writing

Write to me about research, internships, or a tool you need.

Or press ⌘K anywhere on this page.