Embedding Models: Architecture, Pooling & Selection › Normalization and Post-Processing

Michael BrenndoerferJanuary 24, 20264 min read
Language AI HandbookAll chapters
Part 44 of 67Retrieval-Augmented Generation
Chapter 337Embedding Models: Architecture, Pooling & Selection › Normalization and Post-Processing
Reading section 8 of 12 · Normalization and Post-Processing · 4 minSection 8 of 12 · 4 min

Book contents

Section 8 of 12 · 4 min read

Embedding Models: Architecture, Pooling & Selection › Normalization and Post-ProcessingOne section · Sections in this chapter8 / 12 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

After pooling, most embedding models apply one final transformation before returning the output vector: L2 normalization. This step projects the embedding onto the surface of a unit hypersphere. This keeps every vector has exactly the same Euclidean length of 1, regardless of the input text. The formula for this normalization divides the raw embedding by its Euclidean length:

e^=e∥e∥2\hat{\mathbf{e}} = \frac{\mathbf{e}}{\|\mathbf{e}\|_2}

where:

  • e^\hat{\mathbf{e}}: the L2-normalized embedding vector, which has unit length
  • e\mathbf{e}: the raw embedding vector output by the pooling layer
  • ∥e∥2\|\mathbf{e}\|_2: the L2 norm (Euclidean length) of vector e\mathbf{e}, computed as ∑jej2\sqrt{\sum_j e_j^2}

To see why this matters, recall that cosine similarity between two vectors measures the cosine of the angle between them. The formula for cosine similarity is:

cos⁡(a,b)=a⋅b∥a∥2∥b∥2\cos(\mathbf{a}, \mathbf{b}) = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\|_2 \|\mathbf{b}\|_2}

where the denominator normalizes for the lengths of both vectors. Without normalization, two embedding vectors might differ in length for reasons unrelated to semantic content. Two texts of very different lengths might produce embeddings of very different magnitudes simply because the mean over more tokens amplifies or dilutes activations in certain ways. These length differences would contaminate similarity computations by conflating directional similarity (which reflects semantic relatedness) with magnitude differences (which do not).

By normalizing all vectors to unit length, we eliminate magnitude as a factor. When ∥e^∥2=1\|\hat{\mathbf{e}}\|_2 = 1 for all embeddings, the cosine similarity formula simplifies to a plain dot product:

cos⁡(e^a,e^b)=e^a⋅e^b\cos(\hat{\mathbf{e}}_a, \hat{\mathbf{e}}_b) = \hat{\mathbf{e}}_a \cdot \hat{\mathbf{e}}_b

where:

  • e^a,e^b\hat{\mathbf{e}}_a, \hat{\mathbf{e}}_b: the normalized embedding vectors for two texts aa and bb
  • ⋅\cdot: the dot product operation

This equivalence holds because when both norms are exactly 1, the denominator of the cosine similarity formula becomes 1×1=11 \times 1 = 1, leaving just the numerator (the dot product). This simplification is computationally valuable because dot products are faster to compute than cosine similarity (no normalization step at search time), and are well-supported by vector index implementations like FAISS. Once you normalize embeddings at encoding time, you can use the simpler and faster dot product throughout your retrieval pipeline without any loss of accuracy.

Out[16]:
Visualization
Diagram of a unit circle with two raw embedding vectors and their L2-normalized projections, illustrating that normalization equalizes vector lengths while preserving direction.
Geometric interpretation of L2 normalization projecting two-dimensional vectors onto the unit circle. Raw embedding vectors (faded arrows) have different magnitudes but the same directions as their normalized counterparts (solid arrows), which lie exactly on the unit circle. This transformation ensures that cosine similarity depends solely on the angle between vectors, removing the influence of vector magnitude on similarity scores.

Some models include a learned linear projection layer after pooling, mapping the hidden dimension to a different output dimension. For example, some models might project from 768 hidden dimensions down to 256 output dimensions to produce more compact embeddings suitable for memory-constrained deployments. These projection layers are learned during training, so the model learns which linear combinations of hidden dimensions are most informative for the target embedding size. Unlike Matryoshka training, a fixed projection layer commits you to a single output size at inference time: you cannot truncate the projected vector at an intermediate length and expect the result to be useful.