A transformer never sees the string "resetting file permission". Before anything else,
a tokenizer — a separate, much simpler piece of software with a fixed vocabulary
(30,522 entries for MiniLM's, inherited from BERT) — chops the string into subword pieces and
looks each one up as an integer.
Each token id indexes a row in an embedding table — a 30,522 × 384 matrix of learned numbers, one 384-dimensional row per vocabulary entry. Because a transformer has no built-in sense of word order (unlike an RNN, which reads one token at a time), a second vector — the positional embedding, one per position 0, 1, 2, … (learned, BERT-style, not the sinusoids of the original Transformer) — is added on top, so "permission file" and "file permission" don't look identical to the model.
Every token in the input ends up as one such 384-number vector. The four pieces above, plus the [CLS] and [SEP] markers the tokenizer wraps every input in, make a 6×384 matrix — this is what actually enters the first transformer block.
This is the mechanism that the Transformer paper introduced in place of recurrence: every token's vector gets updated by looking at every other token in the sequence at once, weighted by how relevant each one is. Each token produces three projections of itself — a query (what am I looking for), a key (what do I offer), and a value (what do I actually contribute) — all three are just learned matrix multiplications of the same input vector.
Read it as: score every token's key against my query (QKT), scale it down
so the softmax doesn't saturate (/√d), turn the scores into weights that sum to 1
(softmax), then take a weighted average of everyone's value vectors. "Reset" ends up
attending heavily to "file" and "permission" — the learned Q/K projections are what make those tokens
matter for disambiguating what "reset" means here.
Why 12 heads instead of 1
A single attention pass can only learn one notion of "relevant." Running 12 of them in parallel — each with its own learned Q/K/V projections, on a 32-dimensional slice of the 384 — lets different heads specialize: one might track subject-verb agreement, another might link a pronoun back to its noun, another might just look at adjacent tokens. Their 12 outputs are concatenated back to 384 dimensions and passed through one more learned projection.
The full block, and stacking six of them
Multi-head attention is one half of a transformer block. The other half is a small feedforward network (384 → 1536 → 384, with a nonlinearity in between) applied to every token independently — attention mixes information across tokens, the feedforward layer processes each token's mixed result on its own. Both halves get a residual connection (add the input back to the output) and a layer normalization; the residual path is what makes it possible to stack these blocks deeply without training collapsing.
After 6 blocks, a 6-token query is still 6 separate 384-dim vectors — one per token, now richly contextualized. But the bi-encoder from the first field guide needs exactly one vector per query and one per document to take a dot product. Pooling is the step that collapses the many into the one, and it's the one step here that sentence-transformers added on top of BERT for retrieval — base BERT has a [CLS] pooler, but it was never trained to make that vector comparable across sentences.
Everything above — tokens, embeddings, attention, blocks, pooling — is shared machinery. The defining structural difference between an embedding model like MiniLM and a GPT-style chat model (Claude's internals aren't published; the comparison here is to the published GPT-style decoders) is which tokens are allowed to attend to which.
Masked language modeling. BERT saw sentences with 15% of
tokens masked out (mostly replaced by [MASK], a few swapped or left as-is) and learned to predict the missing word from both
directions of context. This is where it learned English — grammar, word sense, world facts —
from ~3.3 billion words of BooksCorpus + Wikipedia.
MiniLM learned to imitate a bigger model. A 12-layer, 384-wide student was trained to match the attention patterns of a BERT-base-sized teacher (Microsoft's UniLMv2, trained on a larger web-plus-books corpus of the same kind — the UniLMv2 paper reports 160 GB of Wikipedia, BookCorpus, OpenWebText, CC-News and Stories, though the card doesn't say which checkpoint was used) — most of the teacher's knowledge in a fraction of the size; still a full pass over the same Wikipedia + BookCorpus text (400k steps), but learning by imitation instead of masked-word prediction from scratch. The 6-layer variant used here was then made by keeping every other layer of that 12-layer student.
Contrastive training on ~1 billion sentence pairs (Reddit comments, Q&A pairs, captions) — mined from the open web, not written for this purpose. This is what turned a language model into an embedding model: the same InfoNCE loss from field guide §05, just at a scale of a billion pairs instead of 1,372.
The same loss again, on 1,372 pairs from one corpus. Not a new skill — a small nudge to an already-formed 384-dimensional space, aiming it at your specific vocabulary and documents.
Steps 1–3 above are where a model actually learns language and general-purpose meaning. Step 4 — the only one you've run — assumes all of that already exists and just steers it. Training a model from nothing directly on the deno-docs corpus means skipping straight to step 4 with no steps 1–3 underneath it: there's no pretrained space to steer, because nothing has taught the model what a sentence is yet.
(BooksCorpus + Wikipedia)
457-doc deno-docs corpus
That's roughly a 10,000× gap. It isn't just "less data, worse model" — below a certain scale (roughly 10–100 million words, by one careful study), a transformer trained from random initial weights learns grammar, word relationships, and general semantics far less reliably, and leans on surface patterns in the 330K words it saw. That's why every field-guide result so far started from a pretrained checkpoint and only fine-tuned: the pretraining is what makes the space worth steering, and no static 2,000-document corpus is anywhere near enough text to grow one from nothing.
Check your understanding
1. Why does a transformer operate on tokens instead of raw characters or whole words directly?
A fixed subword vocabulary is what lets the model handle words it never saw during training — it just breaks them into familiar pieces instead of failing outright.
2. What does self-attention let a token's representation do that a plain word embedding alone can't?
This is exactly why "bank" (river) and "bank" (money) end up with different vectors after attention, even though they start from the same embedding row.
3. Why do transformers use multiple attention heads instead of just one?
One head might end up tracking syntactic structure while another tracks topical similarity — splitting attention into heads lets several such patterns coexist per layer.
4. What does pooling do, and why does retrieval need it?
A 500-token document and a 5-token query need to land in the *same* fixed-size space before cosine similarity means anything — pooling is what makes that comparison possible.
5. Why would training a transformer from scratch on this project's ~330K-word corpus almost certainly fail to learn general language understanding?
This is exactly why every result in this series starts from a pretrained checkpoint and only fine-tunes — pretraining is what makes the space worth steering in the first place.