BXUP Track progress & test yourself — free
War Room · Field diagnosis · ~4 min read
WAR ROOM · FIELD DIAGNOSIS

WR-140 · The positions nobody added

Symptom

A Transformer trains without any error, the loss falls, and the model scores well on the usual validation set. Then it fails on anything where word order carries the meaning. "Transfer from Ramesh to Sunita" and "transfer from Sunita to Ramesh" get the same answer. "Delivered before the deadline" and "the deadline before delivered" get the same answer. On a task built so that order alone decides the label, module 2.8's model without positions read 0.503 on held-back rows and 0.543 on its own training rows, while an identical model with positions read 1.000 and 1.000. The training number is the tell that gets ignored: 0.543 is not overfitting, it is a model that never learned anything, because the information was never in its input. Nothing errors, and shuffling the words of an input produces a bit-identical output.

Context

Any attention-based model where positions were forgotten, dropped or silently disabled. Module 2.8's tiny GPT with positions=False, a classifier built on a bare nn.MultiheadAttention, a pooling encoder over embeddings, a reranker stacked on 3.4's vectors. The most common birth is the quiet one: the position tensor was created and then never added, so the line pos = self.pos(...) exists and the line x = x + pos does not. A second birth is a shape mismatch that got "fixed" by deleting the addition. A third is a refactor to a longer input, where the position table was sized for the old block length and the new code silently slices or skips it. A fourth is real and worth respecting: on bag-like tasks such as topic tagging, order genuinely does not matter much, so the model looks fine on the validation set the team happens to own, and the fault only appears on negation, direction, roles and sequence-of-events questions. Linked modules: 2.8, 2.7 (order carries meaning), 1.5 (scores by slice), 3.4.

Diagnosis

Attention computes a weighted sum over positions, and a weighted sum does not care about order. Feed the same token vectors in a shuffled order and every output row moves with its token and is otherwise unchanged. This is not an approximation, it is exact: module 2.8 measured the largest gap between run(X)[perm] and run(X[perm]) at 5.96e-08, which is float32 rounding, and adding positions moved that gap to 0.264. So the diagnosis is a two-line test rather than an argument. Write assert_order_blind(layer, x): run the layer on x, run it on x[perm], unshuffle the second result, and return the largest absolute difference. A gap under 1e-6 means the layer cannot tell one order from another. Run it on the whole model, not only on one attention layer, because a convolution or a recurrent layer elsewhere in the stack may be quietly carrying the order for you. Confirm with a second, task-level check: build a small set of input pairs that hold the same words in two orders with opposite correct answers, and score the model on it. A model without positions scores near chance on that set no matter how good its headline number is.

The fix

Add positions and re-run the test. The cheapest correct option is a learned table, nn.Embedding(block_length, d_model), added to the token embedding before the first block — that is what module 2.8's tiny GPT uses. The classic alternative is the fixed sinusoidal encoding, which needs no parameters and extends past the training length; a good sinusoidal table has three properties you should print and check, namely every row different, no row repeating inside the block, and neighbouring rows more similar than distant ones. Modern decoder-only models mostly use rotary position embeddings applied inside attention instead, so if you are copying a recent architecture, check where the position information enters before assuming it is missing. Whichever you pick, make the addition explicit and assert its shape on the line where it happens. Then turn the diagnosis into a permanent unit test: assert_order_blind on the full model must return more than a threshold, and the build fails if it does not. Add the paired-input set to your evaluation table as a standing slice, beside overall accuracy, the way 1.5 made per-class recall standing. Expect the fix to be dramatic when order matters and invisible when it does not — the same 4,513 parameters went from 0.503 to 1.000 on the order task and would not have moved on a bag-of-words task.

Prevention

Make the permutation test part of the template you start every attention project from, so it exists before the model does. Keep one paired-input evaluation slice per project — same words, two orders, opposite labels — and refuse to ship without a number on it. Read training accuracy as evidence, not decoration: a model stuck near chance on data it has seen four thousand times is missing an input, not overfitting, and that single reading separates the two most common misdiagnoses in this module. When you change block length, embedding width or anything about the input pipeline, re-run the permutation test rather than assuming it still passes. In review, ask one question of any attention model: where do positions enter, and which test proves it.

In an interview

Q: "Your model treats 'A before B' and 'B before A' identically. Where do you look?" Strong answer: say in one sentence that attention is a weighted sum and therefore permutation-equivariant by construction, so order has to be added to the input. Then give the test rather than the theory — shuffle the input, unshuffle the output, measure the gap, and expect float noise if positions are missing. Quote the two numbers that make it concrete: a gap around 5.96e-08 without positions against 0.264 with them, and 0.503 against 1.000 on a task where order is the only signal. Finish with the detail that shows experience: training accuracy near chance is the fingerprint of a missing input, which is a different disease from overfitting and has a different cure.

This is the free reading view. Open BXUP to track your progress, run the hands-on labs, and prove it with original, exam-pattern assessments.
© Anvi Innovate · BXUP — Be Exponentially Upskilled · BXUP is an independent learning platform, not affiliated with or endorsed by AWS, Microsoft, Google, NVIDIA, IBM, Salesforce, Databricks, Oracle or Anthropic. All trademarks belong to their respective owners. · bxup.in