Part II built word vectors and Part III built models that use them, and both rest on an assumption nobody stated out loud, which is that every word gets exactly one vector, decided before any sentence exists.
Chapter 9 already showed the damage, since the bank of a river and the bank that holds money collapse into one point and that point is correct for neither sense. It is worth measuring rather than asserting.
Take a toy space on three axes for money, river and generic, then give the two senses the vectors a contextual model would produce.
A static embedding must pick one vector, and trained on a corpus carrying both senses equally it lands on their average, . Now ask all three for nearest neighbours.
| query | nearest neighbours |
|---|---|
| money sense | loan , deposit , vault |
| river sense | water , flood , erosion |
| static average | loan , flood , water , deposit |
The two sense vectors give clean, single-topic lists, while the average gives a list that mixes both and commits to neither.
Measure the geometry directly. The static average sits at cosine from each sense, which sounds close until you notice the two senses are only from each other. The static vector is therefore equally wrong in two directions rather than right in one.
The average is not a fixed compromise either, because it moves with whatever mixture the training corpus happened to contain.
| share of money sense | cosine to money | cosine to river |
|---|---|---|
| 50% | 0.7591 | 0.7591 |
| 70% | 0.9293 | 0.5068 |
| 90% | 0.9942 | 0.2577 |
| 99% | 1.0000 | 0.1623 |
At per cent the vector is almost entirely the money sense and the river sense has been erased.
That is the honest statement of what a static embedding holds. It does not represent a word but that word’s frequency-weighted mixture in one particular corpus. Chapter 9 made the same point with apple, and here it is as arithmetic.
The repair is stated in one sentence. Do not look the vector up but compute it, from the sentence the word is actually in. ELMo (Peters et al. 2018) was the model that made this practical, and its name is the method, Embeddings from Language Models.
Three pieces make it up, and each earns its place.
The input is character-based, so the bottom layer builds each word’s initial representation from its characters through a convolution. ELMo therefore has no vocabulary to fall off, and a word it has never seen still gets a sensible vector, which is the FastText argument of Chapter 9 applied at the input layer.
Above that sits a bidirectional language model, where two multi-layer LSTMs run over the sentence, one forward and one backward, the forward one predicting the next token and the backward one the previous. Both are ordinary language models in the sense of Chapter 10, trained by maximum likelihood on plain text.
The third piece is the layer-wise combination, and it is the part worth dwelling on.
A biLM with layers gives representations for each token, being the character layer plus one per LSTM layer, and ELMo does not pick one but combines them all:
where the are softmax-normalised weights and is a single scaling factor.
The detail that matters is which parameters are learned downstream, and the answer is only the and , with the biLM itself frozen. That is a handful of numbers per task, which is why ELMo was cheap enough to adopt everywhere within months.
The weights also turn out to be readable, because different tasks learn different profiles.
| task | , characters | , lower | , upper |
|---|---|---|---|
| part-of-speech tagging | 0.1369 | 0.6792 | 0.1839 |
| word sense disambiguation | 0.1179 | 0.1944 | 0.6877 |
| no preference | 0.3333 | 0.3333 | 0.3333 |
Tagging leans on the lower layer while sense disambiguation leans on the upper one, and that is the finding the ELMo paper is remembered for: lower layers carry more syntax and upper layers more meaning. Which one a task wants is something you read off the learned weights rather than decide in advance, and it is also the clearest evidence that depth in these models does something structured rather than merely adding capacity.
Deep stacks need their activations kept in range, and the lectures introduce the tool here because everything after uses it. Layer normalisation rescales each vector to zero mean and unit variance, then applies a learned scale and shift:
where and are the mean and standard deviation of itself.
The contrast with batch normalisation is the point. Batch norm computes its statistics across the batch, so its behaviour depends on what else is in the batch and on the batch size, whereas layer norm computes them within a single example. That makes layer norm independent of batch composition, which matters when examples have different lengths, and it also behaves identically at training and inference time. Sequence models have exactly that property, which is why layer norm is universal in transformers and batch norm is not.
ELMo established a pattern that outlived the architecture. Train a large model once on plain text using a self-supervised objective that needs no labels, then adapt it to each task with a small amount of labelled data.
The economics are the argument, since pretraining is expensive and happens once while adaptation is cheap and happens many times. For ELMo the adaptation was minimal, being just the weights of Equation (15.1) and one scalar, and later models fine-tune more without changing the shape of the bargain. Everything in Parts IV and V is a variation on it.
ELMo improved the state of the art on six tasks at once, and that breadth is unusual enough to be worth naming: question answering, textual entailment, sentiment analysis, named entity recognition, coreference resolution and semantic role labelling. One architecture change, six benchmarks and no task-specific engineering, which is what convinced the field more than any single number did.
The mechanism behind it is the one this chapter opened with, namely that a word’s representation now depends on its sentence, so bank in “the river bank” and bank in “the savings bank” are different vectors rather than one blurred average.
ELMo proved the principle and inherited a limitation. Its two LSTMs are the recurrent networks of Chapter 13, with Chapter 12’s two burdens intact, so they process one token at a time and carry everything through a fixed size state.
There is a subtler point too, which is that the forward and backward models are independent and only combined at the end. No layer of ELMo ever sees left and right context at once, and what it sees instead is two one-sided summaries stitched together.
Chapter 16 removed the recurrence and Chapter 18 puts the two together, giving a model that reads both directions in every layer at once.
Try it yourself.
code/worked_examples/contextual.pyproduces the tables in this chapter.--bankmeasures what averaging two senses costs and how it shifts with the corpus mixture,--elmoprints the three task profiles, and--maskpreviews the masking budget of Chapter 18.
Peters et al. (2018) is the ELMo paper, and its analysis of what each
layer holds is the part worth reading closely. Ba et al. (2016)
introduce layer normalisation. Jurafsky and Martin (2025) cover
contextual representations alongside the static ones, so the contrast is
easy to follow. Any of these models is three lines with
transformers, where AutoTokenizer and
AutoModel will fetch a pretrained checkpoint and hand you
the per-token vectors this chapter describes.
Measure the averaging. Using the two bank vectors of this chapter, compute the cosine of their average against each sense, and the cosine of the senses against each other. Explain why the first two numbers being equal is a problem rather than a reassurance.
Shift the corpus. Recompute the mixture table for shares of , and per cent. At what share does the cosine to the minority sense fall below ? State what that implies for a downstream task that needs the minority sense.
Read the layer weights. A task learns under Equation (15.1). What kind of task is it likely to be, and why? Now design a task you would expect to produce the opposite profile, and say what you would check to confirm it.
Layer norm against batch norm. Write out Equation (15.2) for a vector of five numbers and compute the result. Then explain, in two sentences, why batch normalisation would give a different answer for the same vector depending on the rest of the batch, and why that is fatal for variable-length sequences.
Characters at the input. ELMo builds word vectors from characters. Name two kinds of word this helps with, and one kind of word where it actively misleads. Chapter 9 discussed the same trade for FastText.
The stitching problem. ELMo’s forward and backward models are trained independently and combined only at the output. Construct a sentence whose correct reading requires left and right context simultaneously, and explain why a stitched pair of one-sided models can miss it.
Watch a word change. Load a pretrained encoder with
AutoTokenizer and AutoModel, embed the two
bank sentences of this chapter, and measure the cosine between
the two bank vectors and between two occurrences of a word that
is not ambiguous. Report both. Before you run it, write down which layer
you are taking the vectors from and why, because the answer changes with
depth and a number without that detail cannot be compared with anyone
else’s.
Each one reproduces the tables above. Open it in Colab, change an input and watch which numbers move.
contextual.pyWhat one vector per word costs
Averaging two senses into one vector, and the layer weights ELMo learns instead.
standard library only Run it in Colab Notebook SourceFrom Natural Language Processing: From Corpus Statistics to Grounded LLMs, by Ramaseshan Ramachandran.