Language · representation · generation Rules 1950 · Statistics 1990 · Transformers 2017

Natural language
processing

Everything a model does with language begins by destroying it. Text is cut into pieces, the pieces are swapped for integers, the integers become vectors, and from then on the system is doing arithmetic. Meaning is whatever survives that translation.

The field is the study of that round trip: how to break language down so a machine can compute over it, and how to build something useful back out the other side.

The pipeline, in one line

text → tokens → ids → vectors → context → probabilities → text

Every system in this document is a variation on that chain. What changes between 1990 and now is almost entirely the middle.

Start where the model starts

Type anything. This is the first thing that happens to it — the text gets chopped into subword pieces from a fixed vocabulary. Common words survive whole; rare ones shatter. The model never sees your letters, only these.

A greedy longest-match tokenizer over a small hand-built vocabulary — the same mechanism as BPE, at roughly 1/100th the scale. Production vocabularies hold 50,000–200,000 learned pieces, so real splits are less aggressive than these. The behaviour is honest; the granularity is exaggerated.

Tokens
Characters
Chars per token
Whole words kept

Token count is the unit of nearly everything downstream: what you pay per API call, what fits in a context window, and how long generation takes. English runs about four characters per token. Most other languages run worse.

01Why it's hard

Language resists computation

Images are grids of numbers. Audio is a waveform. Text is a sequence of arbitrary symbols whose meaning depends on other symbols, on the speaker, on the world, and on things nobody wrote down. Five properties cause most of the difficulty.

Ambiguity, at every level

One word, many senses. One sentence, many parses. One pronoun, many referents. I saw the man with the telescope has two readings and no amount of grammar resolves which. Humans disambiguate with context and world knowledge, mostly unconsciously.

Discreteness

You cannot take a small step from "cat" to "dog". There is no gradient through the space of words, which is why the numbers-and-vectors detour exists at all — continuous space is where optimization works.

Compositionality with exceptions

Meaning is usually built from parts, until it isn't. Kick the bucket composes into nothing like its parts. Idiom, sarcasm, and implicature all break the rule the rest of the language follows.

An unbounded, unbalanced vocabulary

New words appear constantly, and word frequency follows a brutal power law — a few hundred words cover most of any text while the long tail runs forever. Whatever you train on, most of what you meet later will be rare.

It presumes the world

The trophy didn't fit in the suitcase because it was too big. Resolving it requires knowing something about trophies and suitcases. Language is written by people who assume you already know things.

Every one of these is a reason large pretrained models won. Reading enormous quantities of text is currently the only practical way to absorb the world knowledge and the long tail that language silently assumes.

Zipf's law, and why the tail never ends

Rank words by frequency and the nth most common appears roughly proportional to 1/n. The most frequent word is about twice as common as the second, three times the third, and onward. On log-log axes this is a straight line.

The practical consequence: about 150 words cover half of ordinary English, while roughly half of the distinct words in any large corpus appear exactly once. Vocabulary can never be complete, which is precisely the problem subword tokenization was invented to dissolve.

02Five eras

How the field got here

Worth knowing, because each era's tools are still in production somewhere, and because the current one inherits its vocabulary from all four before it.

1950s–1980s

Rules and symbols

Hand-written grammars, parsers, ontologies, expert systems. Linguists encoded knowledge directly. Precise where it worked, catastrophically brittle everywhere else — every exception needed its own rule, and language is mostly exceptions. Survives today in regex, grammar checkers, and rule layers wrapped around statistical systems.

1990s–2000s

Statistics and counting

Learn from corpora instead of legislating. N-gram language models, hidden Markov models for tagging, naive Bayes and SVMs over bag-of-words features, phrase-based statistical translation. Robust and interpretable, but blind to word similarity and unable to hold context beyond a few words.

2013–2017

Embeddings and recurrence

word2vec and GloVe give words dense vectors where similar words sit near each other — the first real notion of semantic distance. RNNs, LSTMs and GRUs process sequences with memory; sequence-to-sequence with attention makes neural translation work. Still fundamentally sequential, so still slow and still forgetful over long spans.

2017–2020

Transformers and pretraining

Attention replaces recurrence entirely, which makes training parallel across the sequence and therefore makes scale affordable. BERT establishes pretrain-then-fine-tune as the default recipe; GPT-2 shows that a plain next-token objective at scale produces surprisingly general capability.

2020–now

Scale, instruction, and assembly

Models grow until few-shot prompting substitutes for fine-tuning. Instruction tuning and preference optimization turn text predictors into things that follow requests. The engineering centre of gravity shifts from training models to assembling systems around them — retrieval, tools, structured output, evaluation harnesses.

The through-line: each era moved knowledge out of hand-built structure and into learned parameters, and each one bought that with more data and more compute. Nothing was replaced because it stopped working — it was replaced because something scaled better.
03Tokenization

Choosing the atoms

Before anything else, text has to be cut into units the model has a fixed vocabulary for. This choice is more consequential than it looks — it sets what the model can perceive, how much fits in context, and what it costs to run.

GranularityHow it worksTrade-off
CharacterEvery character is a tokenTiny vocabulary, nothing unknown, but sequences get very long and each unit carries almost no meaning
WordSplit on whitespace and punctuationMeaningful units, but the vocabulary is unbounded, misspellings become unknowns, and it fails on languages without spaces
SubwordFrequent sequences stay whole, rare ones split into piecesThe universal answer. Fixed vocabulary, no unknown token ever, sensible lengths

BPE

Start from characters, repeatedly merge the most frequent adjacent pair, stop at the target vocabulary size. Used by GPT models. Simple, fast, entirely frequency-driven.

WordPiece

Same idea, but merges are chosen to maximize training-corpus likelihood rather than raw count. BERT's tokenizer. Marks word-internal pieces explicitly.

SentencePiece / Unigram

Treats the raw byte stream as-is, so it needs no pre-splitting on whitespace and handles any script. Unigram prunes a large candidate vocabulary down probabilistically. The multilingual default.

The letter blindness. Models see token ids, not characters. Asking one to count the r's in a word whose pieces don't align with letters is asking it to report on something it cannot perceive — like asking someone to count brushstrokes from a photograph of a painting.
The multilingual tax. Vocabularies are learned from training corpora dominated by English. The same sentence in a lower-resource language can take two to five times as many tokens, which means it costs more, fits less in context, and is often modelled worse. A quiet, structural inequity.
Arithmetic and formatting suffer too. Numbers split inconsistently — 1234 might be one token or three, and differently again as 1,234. Digit-level arithmetic on inconsistent groupings is exactly as awkward as it sounds.
Practical rule: for English, roughly 4 characters or 0.75 words per token. A 200-page book is on the order of 100k tokens. Always measure rather than estimate when cost or context limits matter — tiktoken and HuggingFace's tokenizers both do it in one line.
04Normalization

The classical pipeline, and what's left of it

For twenty years, preprocessing was most of the work. Modern neural pipelines discard nearly all of it — but the steps remain correct and necessary for classical models, search systems, and any pipeline where you control the features.

StepWhat it doesStill worth doing?
Unicode normalizeNFC/NFKC so visually identical strings compare equalAlways. Silent, real bugs otherwise
Whitespace & controlStrip zero-width and control characters, collapse runs of spaceAlways. Invisible characters are a genuine attack surface
LowercasingCollapse caseClassical models yes; neural models no — case carries real signal
Stopword removalDrop "the", "of", "and"Bag-of-words and search yes; neural models never — function words carry the syntax
StemmingChop suffixes crudely: running → runSearch and retrieval only. Fast, lossy, produces non-words
LemmatizationMap to dictionary form using POS: better → goodLinguistic analysis, some classical pipelines. Slower, correct
Sentence splittingFind real sentence boundariesYes — still needed for chunking documents for retrieval
DeduplicationRemove near-duplicate documentsCritically yes at training scale; also prevents train/test leakage
The one that catches everyone: aggressive cleaning destroys signal. Stripping punctuation removes sentence structure. Lowercasing merges Apple and apple. Removing stopwords deletes negation — and a sentiment model that can't see the word "not" is worse than useless. Clean the minimum required, and hold out a test set to prove each step helps.
05Representation

From counting words to placing them in space

Tokens are integers, and integers are meaningless — id 4,502 is not "greater" than id 12. Everything depends on what you turn those ids into.

Sparse — count-based

one-hot
A vector as long as the vocabulary, all zeros but one. Every pair of words is equally distant. No notion of similarity whatsoever.
bag of words
Count each vocabulary word in the document. Loses all order — "dog bites man" and "man bites dog" are identical.
n-grams
Count short sequences instead of single words, recovering a little local order at the cost of a much larger feature space.
TF-IDF
Weight each count by how rare the word is across the corpus, so common words stop dominating. Still the backbone of classical search.

Sparse methods remain genuinely competitive for text classification on modest data, and BM25 — TF-IDF's refined descendant — is still a strong retrieval baseline that hybrid search systems deliberately keep.

Dense — learned

word2vec
Predict a word from its neighbours, or the reverse. The learned weights become vectors where similar words cluster. 2013's breakthrough.
GloVe
Factorize a global co-occurrence matrix instead. Different route, comparable destination.
fastText
Build word vectors from character n-grams, so unseen and misspelled words still get a sensible representation.
contextual
ELMo, BERT and everything since: the vector for a word depends on the sentence it's in. "Bank" by a river and "bank" holding money finally get different representations.
The static-to-contextual jump is the single most important representational change in the field's history. One word, one vector was always a compromise; polysemy is everywhere.

Geometry that means something

In a well-trained embedding space, direction carries meaning. The offset from king to queen runs roughly parallel to the offset from man to woman, which is why vector arithmetic on words produces the famous analogies. Related words cluster; unrelated ones don't.

Similarity is measured by the cosine of the angle between vectors rather than the distance between them, because length tends to track word frequency rather than meaning.

The bias is in the geometry. These spaces are learned from human text, so they encode human associations — including the ones tied to gender, race and occupation. The analogies that make embeddings look magical and the ones that make them harmful come from exactly the same mechanism.
06Language models

Predict the next token. That's the whole objective.

A language model assigns probabilities to sequences. Factor a sequence by the chain rule and the task becomes: given everything so far, what comes next? Every generative system in this document is that one operation, run repeatedly.

P(w1wn) = ∏i P(wi | w1wi−1)

The n-gram approximation truncates that history to the last few words, then estimates the probabilities by counting. It is the oldest working language model, and building one takes about fifteen lines. The model below is real — it counts over a corpus embedded in this page and samples from what it finds.

Order Temperature 1.0
Trained live on a 380-word corpus · counts, not neural weights

What you should notice

  • Local fluency, global incoherence. Every three-word window looks like English. The paragraph goes nowhere. That gap is the entire motivation for neural language models.
  • Trigram is more fluent and more plagiaristic. With longer context there are fewer options, so it increasingly recites the corpus verbatim. More context with fixed data means memorization.
  • Temperature is the confidence dial. Low values always take the likeliest continuation and loop; high values flatten the distribution into noise. The same control sits on every model you use today.
  • Unseen context is fatal. A count-based model assigns probability zero to anything it never observed — the sparsity problem that smoothing techniques spent two decades patching.

Perplexity

PP = exp(1n ∑ ln P(wi | context))

The standard intrinsic metric: the exponentiated average negative log-likelihood per token. Read it as how many options the model was effectively choosing between at each step. Lower is better; a perplexity of 20 means the model was about as uncertain as if picking uniformly among 20 words.

Only comparable within a fixed tokenizer and dataset. Different vocabularies change the denominator, so cross-model perplexity comparisons are usually meaningless. And low perplexity does not imply usefulness — it measures prediction, not truth, helpfulness, or safety.
07Sequences

From recurrence to attention

Counting can't generalize across similar contexts, so the field moved to neural networks that read sequences. The path from there to the transformer took about four years and one decisive idea.

Recurrent networks

Read one token at a time, carrying a hidden state forward. In principle the state summarizes everything seen so far. In practice, gradients vanish across long spans and early information fades.

LSTM and GRU add gates that decide what to keep, forget and expose, which genuinely extended usable memory to hundreds of tokens and powered a decade of production systems.

Seq2seq pairs an encoder with a decoder for translation and summarization — but forcing an entire input sentence through one fixed-size vector was a hard bottleneck.

Attention

Instead of one summary vector, let the decoder look back at every input position and weight them by relevance at each step. Translation quality jumped immediately and the alignments turned out to be interpretable.

Then the removal. In 2017 the recurrence was deleted and only attention was kept. Because nothing depends on the previous step's output, the whole sequence processes in parallel — which is what made training on internet-scale corpora economically possible.

The win was as much about hardware as linguistics. Attention is a stack of matrix multiplications, and matrix multiplications are what GPUs are for.

Self-attention, structurally

Each token is projected three ways. Its query asks what it needs; every token's key advertises what it offers; the dot product of query against key scores the match. Softmax turns those scores into weights that sum to one, and the output is the weighted blend of every token's value.

Multi-head runs several of these in parallel with separate projections, so different heads can specialize — some track syntax, some track coreference. Positional encoding is added because attention alone is order-blind: without it, a sentence and its shuffle are identical inputs.

08Transformers

The block, and the three shapes it comes in

One block · stacked 12 to 100+ times

What each part does

attention
Mixes information between tokens. The only place positions talk to each other.
feed-forward
Transforms each position independently. Holds most of the parameters, and appears to store much of the factual knowledge.
residual
Adds the input back to the output, so gradients reach the bottom of a very deep stack.
layer norm
Rescales activations to keep training stable.
positions
Injects order — learned, sinusoidal, or rotary (RoPE), which is now the common choice.
The quadratic cost. Every token attends to every other, so compute and memory grow with the square of sequence length. Doubling context roughly quadruples the work. Flash attention, sliding windows, and various approximations all exist to soften this, and it remains the central constraint on context length.

Three architectures, three jobs

Encoder-only

BERT, RoBERTa, DeBERTa. Every token sees every other in both directions. Trained by masking words and predicting them. Produces rich representations, cannot generate. Best for classification, tagging, extraction, retrieval embeddings — and still smaller, faster and cheaper than a generative model for those jobs.

Decoder-only

GPT, Llama, Claude, Mistral. Each token sees only what came before — the triangular mask. Trained purely to predict the next token. Generates text, and at scale turns out to handle nearly every task if you phrase it as text continuation. The dominant shape today.

Encoder–decoder

T5, BART, mT5. Bidirectional encoder reads the input; causal decoder writes the output while attending back to it. The natural fit for transformation tasks with a clear input and output — translation, summarization, structured rewriting.

09Training

Pretrain, then align

Modern language models are built in stages. The first is enormous and generic; everything after it is comparatively small and shapes behaviour rather than knowledge.

StageWhat happensScale
PretrainingNext-token prediction (or masked prediction) over a very large text corpus. Where language competence and world knowledge come fromTrillions of tokens; the overwhelming majority of total compute
Supervised fine-tuningTrain on curated instruction–response pairs so the model answers rather than merely continuesThousands to millions of examples
Preference tuningRLHF, DPO and relatives. Humans rank outputs; the model is pushed toward the preferred ones. Shapes helpfulness, tone and refusal behaviourTens of thousands of comparisons
Task fine-tuningAdapt to one narrow domain or format with your own labelled dataHundreds to thousands of examples
PEFT / LoRAFreeze the base model, train small low-rank adapters. Nearly all the benefit at a fraction of the memory and storageOften under 1% of parameters
Scaling laws describe how loss falls predictably with model size, data and compute — and the Chinchilla result showed most large models of that era were badly undertrained for their size. Data quality and quantity mattered more than parameter count, which redirected the whole field.
Fine-tuning is usually not the answer. The reflex to fine-tune should be resisted until prompting and retrieval have been exhausted. Fine-tuning teaches format and style reliably; it is a poor and expensive way to install facts, and it dates the moment your data changes.
10Tasks

The standard problem set

TaskInput → outputTypical approach today
ClassificationDocument → labelFine-tuned encoder, or an LLM prompt when labels are scarce
SentimentText → polarity or aspect scoresSame. Aspect-level is much harder than document-level
NERText → typed spansToken classification with an encoder; spaCy for speed at volume
POS / parsingText → tags or a syntax treeLargely solved for major languages; mostly a linguistic-analysis tool now
CoreferenceText → which mentions refer to the same thingStill genuinely hard; needs world knowledge
Question answeringQuestion (+ context) → answerExtractive from a passage, or generative with retrieval
SummarizationLong text → short textGenerative. Abstractive is fluent and prone to inventing details
TranslationText → text, another languageEncoder–decoder or a large multilingual LLM
RetrievalQuery → ranked documentsHybrid: BM25 plus dense embeddings, then a cross-encoder rerank
GenerationPrompt → textDecoder-only LLM with sampling controls
Structured extractionText → JSON or table rowsConstrained decoding or schema-enforced LLM output. Very common in production
A live tension worth naming: a fine-tuned encoder with a few thousand labels will often beat a large model prompted zero-shot on a narrow classification task — and costs orders of magnitude less to serve. "Use an LLM" is a default, not an analysis. Establish the small-model baseline before you commit.
11What gets built

The patterns in production right now

Prompting

Zero-shot, few-shot examples, explicit reasoning steps, role framing, output-format specification. Cheap to iterate, hard to make reliable — treat prompts as versioned artifacts with a regression suite, not as text you edit in a text box.

Structured output

Force responses into a schema so downstream code can consume them. Constrained decoding, function/tool schemas, JSON mode. The single highest-leverage technique for putting a language model inside a real system.

Tool use and agents

Give the model functions it can call — search, calculators, databases, APIs — and let it decide when. Powerful and fragile; error compounds across steps, so bound the loop and log every call.

Retrieval-augmented generation

Embed your documents into a vector store. At query time, embed the question, fetch the nearest chunks, paste them into the prompt, and ask the model to answer from them.

It grounds answers in sources you control, updates without retraining, and gives citations. Retrieval quality is the whole game — most disappointing RAG systems are retrieval failures wearing a generation costume. Chunking strategy, hybrid search and reranking matter far more than which model writes the final paragraph.

12Evaluation

The hardest part of the field

Classification has clean metrics. Generation does not — there are many acceptable outputs and no reference list of them, which makes automatic scoring approximate at best.

MetricMeasuresWhere it misleads
Accuracy / F1Classification correctnessFine — just watch class imbalance
Exact matchExtractive QAPunishes correct answers phrased differently
BLEUN-gram overlap with a reference translationRewards surface similarity. A perfect paraphrase can score badly
ROUGEOverlap with a reference summarySame flaw. Correlates weakly with human judgement of quality
BERTScoreEmbedding similarity to a referenceBetter on paraphrase; inherits the encoder's own blind spots
PerplexityPrediction qualityNot comparable across tokenizers, and unrelated to truthfulness
LLM-as-judgeA model scoring another model's outputScalable and increasingly standard, but biased toward length, fluency, and its own family's style
Human evaluationWhat you actually care aboutSlow, costly, needs real annotation guidelines and inter-rater checks. Still the ground truth
Benchmark contamination. Public test sets end up in training corpora. A headline score on a well-known benchmark may partly measure memorization. Trust your own held-out data over any leaderboard.
Build a task-specific eval set early. A hundred hand-checked examples that reflect your real distribution — including the failure cases you have already seen — will guide decisions better than any published benchmark. It is boring work and it is the difference between engineering and guessing.
13Failure modes

What goes wrong, and why it's structural

Hallucination. The objective rewards plausible continuations, not true ones. Fluency and accuracy are separate axes, and the model has no internal flag distinguishing recall from invention. Mitigate with retrieval, citations, and asking for uncertainty — not by instructing it not to.
Bias. Training data is human text, so social patterns in that text are learned along with the grammar. It surfaces in embeddings, classifications and generations alike. Audit on your actual population; it is not removable by filtering a word list.
Prompt injection. Instructions and data share one channel, so text retrieved from a document or web page can hijack the system. Currently the central unsolved security problem in LLM applications — treat all retrieved content as untrusted input.
Memorization and leakage. Models can reproduce training data verbatim, which is simultaneously a privacy exposure, a copyright question, and a reason to deduplicate corpora carefully.
Language inequity. Performance drops sharply outside high-resource languages, and tokenization taxes them on top. If your users aren't monolingual English speakers, evaluate in their languages specifically.
Silent drift. Language moves. New slang, new products, new events. A model frozen at a training cutoff degrades gradually and without warning — nothing errors, the answers just get quietly staler.
14Toolkit

What to reach for

Classical & linguistic

  • spaCy — fast production pipelines, NER, POS
  • NLTK — teaching, linguistic resources
  • scikit-learn — TF-IDF and classical classifiers
  • gensim — word2vec, topic models

Neural

  • transformers — models and pipelines
  • tokenizers / tiktoken — the real thing, fast
  • datasets — loading and streaming corpora
  • sentence-transformers — embeddings for retrieval
  • peft — LoRA and adapters

Systems

  • Vector stores — FAISS, Qdrant, pgvector
  • rank_bm25 — sparse retrieval baseline
  • Orchestration — LangChain, LlamaIndex, or plain code
  • Serving — vLLM, TGI
  • Eval — your own harness, first
# 1 — look at what the tokenizer actually did. do this before anything else.
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("bert-base-uncased")
ids = tok("Tokenization decides what the model can see.")["input_ids"]
print(tok.convert_ids_to_tokens(ids))

# 2 — the strong classical baseline. fit this before you reach for a GPU.
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline

baseline = make_pipeline(
    TfidfVectorizer(ngram_range=(1, 2), min_df=2, sublinear_tf=True),
    LogisticRegression(max_iter=1000, class_weight="balanced"),
).fit(train_texts, train_labels)

# 3 — dense embeddings + cosine similarity: the core of every retrieval system
from sentence_transformers import SentenceTransformer
import numpy as np

enc = SentenceTransformer("all-MiniLM-L6-v2")
docs = ["the gripper closed on the part", "pasta boils in salted water"]
D = enc.encode(docs, normalize_embeddings=True)
q  = enc.encode(["robot arm picked up the component"], normalize_embeddings=True)
print(np.argsort(-(D @ q.T).ravel()))   # normalized ⇒ dot product IS cosine

# 4 — generation, with the two knobs that matter
from transformers import pipeline
gen = pipeline("text-generation", model="gpt2")
gen("The robot moved through the corridor",
    max_new_tokens=40, temperature=0.8, top_p=0.9, do_sample=True)
15Learning path

An order that works

StepDo thisYou'll know it when
1Tokenize a paragraph with three different tokenizers and diff the outputYou can predict which words will split before you run it
2Build TF-IDF + logistic regression on a real classification setYou have a number that later work has to beat
3Implement an n-gram language model and sample from itYou can articulate exactly what it can't do and why
4Train word2vec on a modest corpus; inspect neighbours and analogiesYou can find both a delightful analogy and a biased one
5Fine-tune a small BERT for classificationYou know whether it beat step 2, and by how much
6Implement single-head self-attention in NumPy from the equationsQ, K and V stop being letters and become operations
7Build a RAG pipeline over your own documentsYou've debugged a bad answer down to a retrieval failure
8Write an eval set of 100 examples for a task you care aboutYou can tell whether a prompt change helped or hurt
9Fine-tune with LoRA, and compare against prompting honestlyYou can say when fine-tuning is worth it — and usually conclude it isn't

The one-paragraph summary

NLP turns text into numbers, computes over them, and turns numbers back into text. Text is split into subword tokens from a fixed vocabulary, which determines what the model can perceive and what it costs to run. Tokens become vectors — once static and count-based, now contextual and learned — where geometric closeness stands in for semantic similarity. The dominant objective is next-token prediction, which at sufficient scale produces general language competence as a side effect, and the transformer is the architecture that made that scale affordable by replacing sequential recurrence with parallel attention. Systems are built by pretraining broadly, aligning with instruction and preference data, and then assembling retrieval, tools and structured output around the result. The persistent difficulties are not architectural: they are evaluation, hallucination, bias, injection, and the fact that language quietly assumes a world the model has only ever read about.