← back to JabberLM

JabberLM — A Hands-On Guide

This guide walks you through the whole app: a full training run, a full inference + inspection session, what every tab shows, and what every parameter does. It assumes no prior transformer knowledge — just curiosity. Follow along in the app as you read.


1. The big picture

JabberLM is a tiny decoder-only transformer (the same family as GPT) that runs entirely in your browser. It learns to predict the next character of a text, one character at a time.

It opens with a model already trained for you. On first visit the app loads a bundled pre-trained "three-skill" model (see below) so you can generate text and look inside it straight away, with no waiting. Use the Poem / Sort / Solve example chips in the Inference panel to try each skill. You can also build and train your own from scratch on the left, and flip back to the built-in one any time with Load built-in model.

It is character-level: the vocabulary is just the distinct characters in your text (~20–80 of them), so every "token" is a single readable character. That is what makes the internals legible — when you look at an attention matrix, the rows and columns are actual letters.

The built-in model does three things — and the contrast is the whole point. It's one tiny network (~90K parameters, the default preset) trained at once on poems, algebra, and sorting:

Memorisation, hallucination, generalisation — in one model you can open up. It was trained in about 30 minutes of plain single-threaded JavaScript on a laptop (no GPU).

The screen has three parts:

Both panels share one model. Train on the left, then inspect that same model on the right.

Tip: the how to use button in the top-right gives a 5-step quick version of this guide, and ✨ Guide me runs an interactive tour.

The rest of the site

This guide is about the playground (the main page). Four more pages go wider — links are in the header:


2. A standard training run

  1. Pick a text. In the sidebar's Training text section, choose a sample (or paste your own):

    • Jabber Poems — Jabberwocky + ~100 more in the same style; the model learns the style and generalises (this is the "language model" flavour).
    • Sorting — examples like sort 6 9 2 => 2 6 9. The model learns a real, generalising procedure, with a visible grokking jump.
    • Equations — worked single-variable algebra (7x + 2 = 16 => …). A tiny model learns the format but never the arithmetic — the hallucination lesson.
    • Custom (all three combined, editable) — seeds the box with poems + sorting + equations so you can train one model on a multi-section corpus (or replace it with your own text).

    The line under the box shows the character count and how many unique characters there are — that unique count becomes the vocabulary size.

  2. Pick a size. In Architecture, click a preset: tiny (fast, a bit dim) or default (a good balance — the size the built-in model uses). Both are small enough to train live in a minute or two; the active preset is highlighted. (Presets just set the architecture numbers for you — you can still edit them by hand. Big models are shown via the pre-baked bundled models, not live training.)

  3. Press ▶ Play. The first press builds a fresh model for your text + architecture and starts training. Watch four things:

    • Loss curve — cross-entropy loss. Lower = better next-character predictions. It should fall steeply at first, then flatten. This is the single best "is it learning?" signal.
    • Live sample — every so often the model writes a short sample from scratch. Early on it's random noise; within a minute it drifts toward text like your corpus.
    • Per-parameter gradient norm — amber bars showing which weights are changing most this step. Big early, shrinking as training settles.
    • Weights heatmap — pick any weight matrix from the dropdown and watch its values shift as it learns (red = positive, blue = negative; hover any cell for the exact number).
    • Grokking view (Sorting only) — when the dataset is Sorting, a second chart appears: accuracy on held-out lists the model never trained on, plus the 9 digit embeddings projected to 2-D. Watch the accuracy sit low, then jump — that's grokking.
  4. Steer it live. While it runs, change the learning rate or batch size in the sidebar and watch the loss react immediately — no restart needed.

  5. ⏸ Pause when the loss has flattened and the sample looks decent.

Held-out validation & overfitting (optional)

By default the loss is measured on the same text the model trains on, so it always keeps falling — the model can simply memorise the text. To see whether it's actually generalising, turn on a held-out split: in the sidebar set held-out % (e.g. 20). That reserves part of the text as validation data the model never trains on, and every validate every steps the app measures loss on it (forward only — it never affects the weights).

The split is representative: instead of holding out one tail chunk, the app cuts the corpus into ~20 blocks and reserves every M-th block, so the held-out sample is spread across all sections of a multi-section corpus (poems and sorting and equations), not just the end. Training windows are kept strictly inside the training blocks, so there's no leakage.

Now the loss chart shows two lines: train (emerald) and val (amber). Both start from the same point — validation is measured once at step 0 (before any training), so the lines share a baseline (~`ln(vocab)`, the loss of random guessing) and you watch them diverge. Watch for the classic overfitting signature: train loss keeps falling while validation loss flattens and then starts to rise. That gap is the model memorising training-specific detail that doesn't transfer — the single most important thing a held-out set reveals; real pipelines stop (early stopping) right around where the val curve bottoms out.

  1. Save it. In the model row: Save keeps it in your browser; JSON Save downloads a file you can reload later with JSON Load. (Use single-Step for one batch at a time; ↺ Rebuild throws the model away and starts over with fresh random weights.)

Step Through — watch one forward pass and backprop

Press ⇄ Step Through to pause training and open a guided, click-by-click tour of a single learning step on a short input. Use Next / Back (or the ← → / space keys) to walk through it:

Every number shown is the model's real value/gradient for that input (hover any cell to read it). To keep it legible it follows one head and one weight per layer rather than all of them — enough to see the whole pass end-to-end.


3. A standard inference + inspection

Now use the trained model (right panel).

  1. Type a prompt (e.g. 'Twas brillig, or sort 6 9 2 => ) and press Run. This feeds the prompt through the model, fills the inspector, and writes the first predicted character — so the output already grows past what you typed. The first time, the Step and Generate ×20 buttons pulse to show you what to do next.

  2. Press ⏭ Step (1 token) to generate one more character. The model samples the next character and appends it; the inspector updates to show exactly how it decided. Step again and again to watch it write. Generate ×20 does 20 steps at once (the output box auto-scrolls so you always see the newest text). ↺ Reset clears everything.

    • Run = start from the prompt + first letter. Step = continue one character. Reset = clear. Editing the prompt box also starts a fresh session.
  3. Open the tabs to look inside. Every heatmap is hover-to-read — move your mouse over any cell to see its exact value and which characters it relates to.

What each tab shows

(The LoRA tab appears only while fine-tuning — see §6.)


4. Every parameter, and what it does

Training text

Architecture (changing any of these needs a Rebuild + retrain)

Features (live — no rebuild)

Training (live)

Sampling (live, Inference panel)

Save / Load


5. Experiments to try


6. Fine-tuning with LoRA

Big models are rarely retrained from scratch — they're fine-tuned: a small set of extra weights is trained on new data while the original model stays frozen. LoRA (Low-Rank Adaptation) is the most common way to do this, and JabberLM lets you watch it happen on the built-in model.

The idea. For a frozen weight matrix W, LoRA learns a low-rank update ΔW = A·B (where A is in×r and B is r×out, with the rank r small — e.g. 8). The model uses W + (α/r)·A·B. Only A and B train; W never moves. B starts at zero, so ΔW starts at zero and the model begins exactly as it was — then fine-tuning grows the overlay.

Do it:

  1. Make sure a model is loaded (the built-in one is fine). In the Training panel's Fine-tune (LoRA) card, pick a built-in pack — Summon the Snark (teaches one distinctive refrain) or Go nautical (drifts toward sea-words) — or paste your own short text.
  2. Optionally set rank (size of the overlay), alpha (its strength), and which weights to adapt (attn and/or mlp). Press ✦ Start fine-tuning. The card shows how few weights are now trainable (a few thousand out of the model's ~90,000) — the whole point of LoRA.
  3. Press ▶ Play. Only the adapters move; the base is frozen. Watch the loss fall.
  4. In the Inference panel, type a prompt and Run. Toggle the LoRA overlay checkbox:
    • On → the model uses base + adapter (after a little training on Summon the Snark, it keeps producing "the Snark").
    • Off → the original base model (the Snark is gone). Same weights underneath — you're just adding or removing the overlay.
  5. Open the LoRA inspector tab to see the adapter itself: the A and B matrices and the product ΔW = A·B for each adapted weight. Right after Start, ΔW is blank (because B=0); as you train, it fills in — that coloured ΔW is everything the fine-tune learned.

Notes: fine-tuning uses the base model's vocabulary, so any characters in your text that the model has never seen are skipped. Auto-save is paused while fine-tuning — use JSON Save to keep an adapted model (it stores the base and the adapter; JSON Load brings both back).