M0 · Prerequisites and setupM0.129 min read

Lesson 1 of 106 · Module 1 of 14 · Week 0

Threads:The infrastructure thread

Linear algebra for LLMs: dot product, cosine similarity, and NumPy shapes

The linear algebra an NCA-GENL candidate actually needs is three ideas: a tensor is a numeric array described by its shape, the dot product multiplies two vectors elementwise and sums the result, and cosine similarity is that dot product divided by both lengths so it measures direction rather than size. Everything later in the course — embeddings, attention, retrieval, memory estimates — is built out of those three, and nearly every error you will hit in a notebook is a shape mismatch rather than a maths mistake.

By the end you can

  1. 01State what a scalar, vector, matrix and tensor are, and read a shape tuple like (4, 128, 768) out loud as a sentence about data.
  2. 02Compute a dot product and a cosine similarity by hand, and say which one you want for a given retrieval task.
  3. 03Predict the output shape of a matrix multiplication before you run it, and name why a shape error happened.
  4. 04Recognise the three shape bugs that produce wrong answers instead of exceptions — the dangerous class.
01

What linear algebra for LLMs is

Linear algebra for LLMs is the arithmetic of rectangular number arrays. A language model is, mechanically, a long chain of matrix multiplications with a few nonlinear squashing functions between them. Nothing in that chain requires you to prove a theorem. What it requires is that you can look at a number array, say what its dimensions mean, and predict what happens when it is multiplied by another one.

The objects, in order of increasing dimension:

ObjectShapeReadingExample in an LLM
Scalar() — no dimensionsone numbera temperature setting, a loss value, a learning rate
Vector(d,) — one dimensiona list of d numbersone text embedding with d = 384 or 768 or 1536
Matrix(r, c) — two dimensionsr rows of c numbersa weight matrix; a corpus of r embeddings
Tensor (3D)(b, s, d)b items, each s steps long, each step a d-vectora batch of tokenised text moving through a transformer
Tensor (4D)(b, h, s, s)per item, per attention head, an s × s score gridattention scores inside one layer

"Tensor" is the general word. A scalar is a 0-D tensor, a vector is a 1-D tensor, a matrix is a 2-D tensor, and nobody in practice bothers with a special word past that. In PyTorch and NumPy you inspect the shape with .shape, and reading that tuple is genuinely half the skill.

Two operations matter above all others.

The dot product takes two vectors of equal length and returns one scalar:

text
a · b = a₁b₁ + a₂b₂ + a₃b₃ + … + a_d b_d

It is one multiplication per position and then one sum. That is all. Its meaning is agreement: it is large and positive when the two vectors point the same way and are both long, near zero when they are perpendicular, and negative when they point in opposing directions.

Cosine similarity takes the same two vectors and divides the dot product by both of their lengths:

text
cos(a, b) = (a · b) / (‖a‖ × ‖b‖)

where ‖a‖ (the norm, or Euclidean length) is sqrt(a₁² + a₂² + … + a_d²). Because you divided out both lengths, the result is bounded in [−1, +1] regardless of how long the vectors were. It measures direction only. This is why it is the default similarity function for text embeddings: a long document and a one-sentence summary of the same topic can have very different vector magnitudes and still be recognised as being about the same thing.

Matrix multiplication is the generalisation: it is just a grid of dot products. Multiplying an (m, k) matrix by a (k, n) matrix gives an (m, n) matrix, where entry (i, j) is the dot product of row i of the first with column j of the second. The inner dimensions must match — k against k — and that single rule is the source of most notebook errors you will ever see in this field.

That is the whole toolkit. The rest of this lesson makes it airtight, because the two concepts introduced here — tensor shapes (C03) and dot product / cosine similarity (C04) — carry more downstream dependency in this course than any other pair. Almost everything in modules 1 through 12 reduces to them. This lesson is deliberately kept tight rather than inflated to match that fan-out: the goal is that you never need to come back to it, not that it is long.

02

How the dot product, cosine similarity, and tensor shapes work

L1 — Intuition: a dot product is a vote count

Imagine each dimension of a vector is a yes/no-ish opinion about some invisible feature: "is this text about finance", "is it formal", "is it a question". A positive number is yes, negative is no, and the size is confidence. Now put two such opinion lists side by side and multiply them position by position. Where both agree — both positive or both negative — the product is positive. Where they disagree, the product is negative. The dot product sums those agreements and disagreements into a single score.

That gives the intuition for all three regimes:

  • Both texts strongly agree on many features → large positive dot product.
  • They talk about unrelated features → products cancel out → dot product near zero.
  • They take opposite positions on the same features → negative dot product.

Cosine similarity adds one correction to that vote count. A vector where every entry is doubled has exactly the same opinions, held twice as loudly. Its dot product with anything doubles too, which would make "loud" texts look more similar to everything. Dividing by the lengths cancels the loudness and leaves the opinions. Hence: the dot product measures agreement and magnitude together; cosine similarity measures agreement alone.

Tensor shapes are the bookkeeping that keeps these vectors organised. When you process 4 pieces of text at once, each 128 tokens long, and each token is represented by 768 numbers, you have 4 × 128 × 768 numbers in one box, and the shape tuple (4, 128, 768) is how you remember which axis is which.

L2 — Mechanism: the shape triple and the matmul rule

Almost every intermediate value inside a transformer has the shape (batch, sequence, hidden):

AxisCommon nameWhat varies along itTypical size
0batchindependent examples processed together1 to a few dozen
1sequencetoken positions within one exampleup to the context window
2hidden (or d_model, or embedding dim)the learned features describing one token384 · 768 · 1024 · 4096

Three facts about this triple pay off repeatedly:

  1. The batch axis is independent. Nothing in a forward pass mixes example 0 with example 3. Batching exists purely to keep the hardware busy. That is why batch size changes memory and speed but not results (up to floating-point noise).
  2. The sequence axis is where interaction happens. Attention is precisely the operation that mixes information across the sequence axis. Every other layer in a transformer treats each position independently.
  3. The hidden axis is where meaning lives. A single token's d numbers are its representation at that layer. When you take "the embedding" of a piece of text, you are collapsing the sequence axis to produce one d-vector: shape (s, d) becomes shape (d,).

Now the matmul rule. For 2-D matrices:

text
(m, k) @ (k, n)  →  (m, n)          legal: inner dims match
(m, k) @ (n, k)  →  ERROR           inner dims k and n disagree
(m, k) @ (k, n) @ (n, p) → (m, p)   chains fine

For higher-dimensional tensors, the last two axes are treated as the matrix and everything before them is a batch of such matrices, broadcast if necessary:

text
(4, 128, 768) @ (768, 3072)         →  (4, 128, 3072)
(4, 12, 128, 64) @ (4, 12, 64, 128) →  (4, 12, 128, 128)

That second line is the shape of attention scores: for each of 4 examples and each of 12 heads, a 128 × 128 grid saying how much each token attends to each other token. You will meet it properly in module 1; here the point is only that it is a batched matmul and its shape is predictable from the rule.

Cosine similarity at scale is also a matmul. If you L2-normalise every vector first — divide each by its own norm so its length becomes exactly 1 — then the dot product is the cosine similarity, because you are dividing by 1 × 1. So a whole similarity search collapses to:

text
normalise query   → shape (1, d)
normalise corpus  → shape (N, d)
scores = query @ corpus.T   → shape (1, N)
rank   = argsort(-scores)

This is why production retrieval systems store normalised vectors: it converts an expensive-looking similarity metric into a single matrix multiplication, which is exactly the operation GPUs are built to do. That connection is the reason this lesson comes before M0.2.

L3 — The mechanics that actually bite: transpose, reshape, broadcasting, and axes

Three transformations move data between shapes, and confusing them is the most common source of silently wrong results.

OperationWhat it doesShape effectDoes it move data?
transpose / .T / swapaxesreorders axes; element at (i, j) moves to (j, i)(m, n)(n, m)reinterprets, but changes which number is where
reshape / viewkeeps elements in memory order, re-cuts them into a new shape(4, 128, 768)(512, 768)no reordering; total element count must be unchanged
broadcastingstretches a size-1 or missing axis to match(N, d) with (d,) → both treated as (N, d)conceptually repeats, no copy

Reshaping (4, 128, 768) to (512, 768) is safe and common — it flattens batch and sequence into one long list of token vectors. Reshaping (m, n) to (n, m) is not the same as transposing it, and this trips people constantly: reshape reads elements in order and refills them, so rows and columns get interleaved into nonsense. Transpose actually swaps the indices.

Broadcasting is the genuinely dangerous one, because it turns a bug into a bigger array rather than an exception:

text
a.shape == (1000,)       # 1000 similarity scores
b.shape == (1000, 1)     # the same scores, as a column
a - b                    # → shape (1000, 1000). No error. 1M numbers.

NumPy aligns shapes from the right, pads missing axes with 1, and stretches any axis of size 1. (1000,) pads to (1, 1000); against (1000, 1) both stretch, and you get a million-element outer difference where you wanted a thousand-element elementwise one. You will not get a traceback. You will get a plausible-looking mean and a wrong conclusion. Adding keepdims=True to reductions, and asserting shapes early, are the defences.

Finally, axis conventions in reductions. sum(axis=0) collapses the axis you name; it does not "sum along rows" in any way you should trust your intuition about. For a (N, d) array:

  • arr.sum(axis=0) → shape (d,): one total per feature, across all N items.
  • arr.sum(axis=1) → shape (N,): one total per item, across all features.
  • arr.sum() → shape (): one number.

The rule that never fails: the axis you pass is the axis that disappears. When you compute a norm for L2 normalisation over a (N, d) array, you want the length of each row, so you reduce over the feature axis — axis=1 — and you want keepdims=True so the result has shape (N, 1) and broadcasts cleanly back against (N, d).

03

Dot product vs cosine similarity vs Euclidean distance vs dot product on normalised vectors

This is the comparison to have cold. All four are ways of scoring how related two vectors are, and the exam-relevant skill is picking the right one and knowing what each ignores.

MetricFormulaRangeSensitive to magnitude?Higher meansTypical use
Dot product (inner product)Σ aᵢbᵢunboundedYesmore similar and/or longer vectorsrecommender scores where "popularity" is baked into vector length; the raw operation inside every layer
Cosine similaritya·b / (‖a‖‖b‖)[−1, +1]Nomore similar in directiontext embedding search, semantic similarity, deduplication — the default
Cosine distance1 − cos(a, b)[0, 2]Noless similarlibraries that want a distance (smaller = closer) rather than a similarity
Euclidean (L2) distancesqrt(Σ (aᵢ−bᵢ)²)[0, ∞)Yesless similarclustering in a space where absolute position means something; k-means
Dot product on L2-normalised vectorsΣ âᵢb̂ᵢ[−1, +1]No (already removed)more similar in directionproduction vector search — mathematically identical to cosine, cheaper to compute

Three consequences worth memorising:

  • Cosine and normalised dot product are the same number. If a vector database offers "inner product" and "cosine" as separate index metrics, and your vectors are already normalised, they will return the same ranking. Choosing "inner product" on unnormalised vectors, however, silently changes your ranking to favour long vectors.
  • Cosine and Euclidean give the same ranking on normalised vectors too — but only the ranking, not the score. For unit vectors, L2² = 2 − 2·cos, so larger cosine always means smaller distance. On unnormalised vectors they can disagree completely.
  • Sign matters. Cosine can be negative. Many embedding models in practice produce mostly-positive similarities in a narrow band (say 0.6 to 0.95 for related text), which is why a raw threshold like "0.8 means relevant" is model-specific and untransferable. Confusing this band for a calibrated probability is a mistake we will name again when we evaluate retrieval.

There is one more confusable that belongs here because it is a naming trap rather than a maths one:

TermWhat it isWhat it is not
dot productthe operation Σ aᵢbᵢ on two vectorsa matrix multiplication
matrix multiplication (matmul, @)a grid of dot products between rows and columnselementwise multiplication
elementwise / Hadamard product (*)cᵢⱼ = aᵢⱼ × bᵢⱼ, same shape in, same shape outa dot product; it does not sum
np.dotdot product for 1-D inputs, matmul for 2-D inputs — behaviour depends on shapea single well-defined operation

The last row is a real hazard: np.dot doing two different things depending on input rank is exactly the kind of thing that turns a shape bug into a wrong number. Preferring the explicit @ operator for matmul and np.sum(a * b) or np.inner for a genuine dot product is the habit that avoids it.

04

Worked example: cosine similarity computed by hand, three ways

Real arithmetic, done step by step, with 5-dimensional vectors so it fits on a page. Real embeddings have 384 to 4,096 dimensions; the arithmetic is identical, only longer.

Take three vectors. Imagine they are 5-dimensional embeddings of three short documents.

text
a = [ 2,  0,  1,  3,  1]     "GPU memory limits for LLM training"
b = [ 1,  1,  0,  2,  2]     "how much VRAM does fine-tuning need"
c = [-1,  2,  0, -1,  0]     "seasonal fruit recipes"

Step 1 — dot products. Multiply position by position, then sum.

text
a · b = (2×1) + (0×1) + (1×0) + (3×2) + (1×2)
      =   2   +   0   +   0   +   6   +   2   = 10

a · c = (2×−1) + (0×2) + (1×0) + (3×−1) + (1×0)
      =   −2   +   0   +   0   +   −3   +   0  = −5

Step 2 — norms. Square every entry, sum, take the square root.

text
‖a‖ = sqrt(2² + 0² + 1² + 3² + 1²) = sqrt(4 + 0 + 1 + 9 + 1) = sqrt(15) ≈ 3.873
‖b‖ = sqrt(1² + 1² + 0² + 2² + 2²) = sqrt(1 + 1 + 0 + 4 + 4) = sqrt(10) ≈ 3.162
‖c‖ = sqrt(1² + 2² + 0² + 1² + 0²) = sqrt(1 + 4 + 0 + 1 + 0) = sqrt(6)  ≈ 2.449

Step 3 — divide.

text
cos(a, b) = 10 / (3.873 × 3.162) = 10 / 12.247 =  0.816
cos(a, c) = −5 / (3.873 × 2.449) = −5 /  9.487 = −0.527

So a and b — the two documents about GPU memory — score 0.816, strongly similar in direction. a and c score −0.527: not merely unrelated but pointing away. That negative value is the part people forget exists.

Step 4 — the same answer via normalisation, to prove the equivalence. Divide each vector by its own norm to get unit vectors, then just take the dot product.

text
â = a / 3.873 = [0.516, 0.000, 0.258, 0.775, 0.258]
b̂ = b / 3.162 = [0.316, 0.316, 0.000, 0.632, 0.632]

â · b̂ = (0.516×0.316) + (0×0.316) + (0.258×0) + (0.775×0.632) + (0.258×0.632)
       =    0.163      +     0     +     0     +    0.490      +    0.163
       =    0.816

Same number, 0.816, to three decimals. This is the identity that makes production vector search cheap: normalise once at index time, and every query afterwards is a plain dot product. Note also that ‖â‖ should now be 1 — check it: sqrt(0.516² + 0 + 0.258² + 0.775² + 0.258²) = sqrt(0.266 + 0.067 + 0.601 + 0.067) = sqrt(1.001) ≈ 1.000, the 0.001 being rounding in the three-decimal intermediates. Carrying rounding forward and then stating the residual is a habit M0.4 will formalise.

Step 5 — where Euclidean distance would have disagreed. Now double b, giving b' = [2, 2, 0, 4, 4]. Same direction, twice the length — the same document, "said louder".

text
cos(a, b') = (a · b') / (‖a‖ ‖b'‖) = 20 / (3.873 × 6.325) = 20 / 24.49 = 0.816   ← unchanged
a · b'     = 20                                                                  ← doubled
L2(a, b)   = sqrt(1 + 1 + 1 + 1 + 1) = sqrt(5) ≈ 2.236
L2(a, b')  = sqrt(0 + 4 + 1 + 1 + 9) = sqrt(15) ≈ 3.873                          ← got "further away"

Cosine says the relationship is identical, because it is. The raw dot product says b' is twice as relevant. Euclidean distance says b' is less relevant than b, even though it is the same document scaled. If your corpus contains a mix of short and long texts — and every real corpus does — that difference decides whether your retrieval works. It is the single most practical reason cosine is the default for text.

05

Shape decision table: predicting output shapes and choosing a metric

Two decision tables. The first is for shapes: given what you have and what you want, which operation gets you there.

You haveYou wantOperationResulting shape
(N, d) corpus, (d,) querysimilarity to every documentcorpus @ query(N,)
(N, d) corpus, (M, d) queriesfull similarity matrixqueries @ corpus.T(M, N)
(b, s, d) token statesone vector per example (mean pooling).mean(axis=1)(b, d)
(b, s, d) token statesa flat list of token vectors.reshape(-1, d)(b·s, d)
(N, d) vectorsunit-length versionsarr / norm(arr, axis=1, keepdims=True)(N, d)
(b, s, d) states, (d, f) weightsone dense layer appliedstates @ weights(b, s, f)
(N,) scoresthe top 5 indicesargsort(-scores)[:5](5,)
(d,) vectora column for broadcastingarr[:, None](d, 1)

The second is the metric choice, framed as when to reach for each and when not to.

SituationReach forDo not reach forWhy
Semantic search over documents of varying lengthcosine (or normalised dot)raw dot productlength would leak into ranking
Vectors are already L2-normalised by the modeldot productcosine, redundantlyidentical result, fewer operations
Deduplicating near-identical passagescosine, with a high thresholdEuclideanscale-free, and a threshold transfers across doc lengths
Clustering points where absolute position is meaningful (not text embeddings)Euclideancosinecosine throws away the information you care about
Recommendation where item popularity is encoded as vector magnitudedot productcosineyou want magnitude in the score
Comparing outputs of two different embedding modelsnone of themall of themthe spaces are unrelated; the number is meaningless
Reporting "how confident is this match" to a usera calibrated threshold you measured on your own dataa similarity score presented as a probabilitysimilarity bands are model-specific

That last row is the one that matters most in an applied setting, and it is worth stating plainly: a cosine similarity is not a probability. It has no calibrated meaning across models, across domains, or even across query types within one model. What you can legitimately do is rank with it, and choose an operating threshold by measuring your own labelled examples. That measurement is what 01-08 will have you build.

Both tables are worth copying into whatever notes you keep. Shape prediction is the skill that turns a two-hour debugging session into a ten-second check, and metric choice is the kind of decision-rule question this exam favours.

06

Why dot product, cosine similarity, and tensor shapes matter for the NCA-GENL exam

The exam is an associate-level, 50–60 question multiple-choice paper sat in 60 minutes, and published candidate reports converge on the finding that it tests high-level identity and when-to-use judgement rather than derivations — extensive attention math was reported as overkill and largely absent. That calibration is [FIELD] evidence, not official, but it points the same way as the official job-role framing, which describes an associate who contributes to LLM systems under supervision of senior professionals. So you will not be asked to derive softmax gradients. You will be asked which similarity metric belongs on an embedding search, or which axis a batch dimension is.

What this lesson buys you, concretely, is that a large fraction of later material stops being new information and becomes an application of something you already computed by hand:

Later lessonWhat it reduces to
01-03 Tensor shapes in transformersthis lesson's (batch, sequence, hidden) triple, applied to a real architecture
01-04 Vectors, dot products, and cosine similaritythe full course treatment of C04; this lesson is its prerequisite arithmetic
01-02 LLM parameters and where knowledge livesweight matrices, whose sizes you can now read off a shape
01-05 Loss functions and cross-entropya dot product between a one-hot target and a log-probability vector
01-07 Train, validation and test splitsno linear algebra, but the shape discipline that stops a leak
Module 1's embeddings lessonscosine similarity over a (N, d) corpus matrix, exactly as computed above
Module 1's vector-database lessonsapproximate nearest neighbour, which is "the same ranking, computed without touching all N rows"
Module 1's self-attention materiala batched matmul producing (b, h, s, s) scores, then a weighted sum
Module 12's KV-cache and serving materialmemory arithmetic over tensors whose shapes you can predict

The official objectives this module serves are 1.6 and 1.10 — familiarity with the capabilities of Python numerical and NLP packages including NumPy, and using those packages to implement traditional ML analyses — plus 4.6, the Software Development domain's identical NumPy clause. NumPy appears by name in the official objective text of both the 30%-weighted Core ML domain and the 24%-weighted Software Development domain. That is not incidental: shape literacy in NumPy is explicitly examinable surface area, and it is the surface area this lesson covers.

There is a second, subtler exam payoff. Several of the exam's most-reported confusable pairs are distinguishable by their linear algebra rather than by their marketing:

  • Sparse vs dense retrieval — sparse scores lexical overlap on a vocabulary-sized mostly-zero vector; dense scores cosine on a few-hundred-dimensional filled vector. Same operation, radically different vector.
  • WordNet vs word2vec — a hand-curated lexical ontology versus learned dense vectors you can take a dot product of. If you can take a cosine similarity of it, it is word2vec-family.
  • Static vs contextual embeddings — one vector per vocabulary entry versus one vector per token occurrence, which is a shape difference: (V, d) lookup table versus (s, d) per-sequence output.

You do not need to memorise those now. You need the vocabulary that makes them one-line distinctions when you meet them.

07

Common mistakes with tensor shapes and cosine similarity

Eight named errors. The first four raise exceptions and cost you minutes; the last four return plausible numbers and cost you a wrong conclusion, which is why they are the dangerous half.

MistakeSymptomCauseFix
Inner-dimension mismatchmatmul: mat1 and mat2 shapes cannot be multiplied (4x768 and 512x768)you multiplied (m,k) @ (n,k) without transposing the secondtranspose: a @ b.T; check that the two ks are the same number before you run it
Missing batch axiserror naming a 2-D tensor where 3-D was expected, or a silently wrong single resultyou passed one example with shape (s, d) to code expecting (b, s, d)add the axis: arr[None, ...] or arr.unsqueeze(0)
Reshape instead of transposeno error; downstream similarities are near-randomreshape(n, m) re-cuts memory in order rather than swapping indicesuse .T / transpose / swapaxes when you mean to reorder axes
Element-count mismatch on reshapecannot reshape array of size 393216 into shape (512,512)the product of the new shape does not equal the number of elementscompute the product first, or use -1 for exactly one inferred axis
Accidental broadcastingan unexpectedly huge array, a memory spike, or a mean that looks "roughly right"(N,) combined with (N,1) stretches to (N,N) instead of aligningkeep keepdims=True on reductions; assert the shape you expect immediately after every reduction
Forgetting to normalise before a dot productranking quietly favours long documents; short precise passages never surfaceyou used raw inner product where you meant cosineL2-normalise at index time and at query time, and assert abs(norm - 1) < 1e-5
Reducing over the wrong axisnorms all identical, or a (d,) result where you wanted (N,)axis=0 collapses items; axis=1 collapses featuresremember: the axis you pass is the axis that disappears; print the result's shape
Comparing vectors from two different modelssimilarities cluster meaninglessly near one valuetwo embedding spaces have no shared geometry, even at the same dimensionpin one embedding model per index; re-embed everything when you change it

Two of these deserve a sentence more.

Accidental broadcasting is the error that most rewards paranoia. A defensive one-liner after any reduction — assert scores.shape == (n_docs,), scores.shape — costs nothing and catches the entire class. Professional numerical code is dense with shape assertions for exactly this reason; they are documentation that fails loudly.

Comparing vectors across models is the one that survives into production and does real damage, because nothing errors. If you re-embed half a corpus with a newer model and leave the other half alone, your index becomes two disconnected geometries and retrieval quality collapses in a way that looks like a data problem rather than a versioning problem. The discipline of pinning and versioning an embedding model exists because of this failure mode, and this lesson is where its cause becomes visible.

Do I need to know matrix calculus for the NCA-GENL exam?

No. You need to know that gradients exist, that backpropagation computes them, and that gradient descent steps the weights against them — all of which 01-06 covers at identification depth and explicitly not at implementation depth. Nothing on an associate-level, 60-minute multiple-choice paper can reasonably ask you to differentiate a matrix product, and candidate reports [FIELD] describe deep attention math as absent. Learn to read shapes fluently and spend the time you save on tool identity and decision rules, where the questions actually live.

What is the difference between the dot product and cosine similarity?

Cosine similarity is the dot product divided by the lengths of both vectors. The dot product answers "how much do these two agree, taking their magnitudes into account"; cosine similarity answers "how much do these two agree in direction, ignoring magnitude entirely". Because of that division, cosine is bounded to [−1, +1] and the raw dot product is not. If you L2-normalise your vectors first — make every length exactly 1 — the two become the same number, which is why vector databases can offer "inner product" and "cosine" as interchangeable index metrics on normalised data and as very different metrics on unnormalised data.

Why is cosine similarity used for text embeddings instead of Euclidean distance?

Because document length leaks into vector magnitude, and you almost never want length to affect topical relevance. Worked out in section 4: doubling a vector leaves cosine similarity unchanged at 0.816 while raw dot product doubles and Euclidean distance grows from about 2.24 to about 3.87 — the same document scaled becomes "further away". A corpus mixing one-line questions with ten-page documents would rank badly under a magnitude-sensitive metric. Cosine strips magnitude out, so a short summary and the long document it summarises can score as related. On already-normalised vectors, cosine and Euclidean produce the same ranking — but only then.

What does the shape (batch, sequence, hidden) mean in a transformer?

It means: batch independent pieces of text being processed together, each represented as sequence token positions, each position represented by hidden learned numbers. So (4, 128, 768) is four texts, 128 tokens each, 768 features per token — 393,216 numbers. The batch axis never interacts across examples; it exists to keep hardware busy. The sequence axis is the only axis attention mixes across. The hidden axis is where a token's meaning is represented. Knowing which axis is which is how you know what an operation did.

Do I need a GPU to work through the linear algebra in this course?

No — not for this lesson and not for the arithmetic that follows. Every computation here is a handful of multiplications on five-element vectors, and even a full similarity search over tens of thousands of embeddings is comfortable on a laptop CPU with NumPy. What a GPU changes is the scale at which these same operations stay fast, which is precisely the subject of the next lesson. The reason M0.2 exists at all is that the first lab in this course is not about hardware, yet it will fail on hardware grounds if you have never seen what a GPU does.

How much NumPy do I actually need for NCA-GENL?

Enough to construct an array, inspect .shape, index and slice it, multiply with @ and *, reduce with sum/mean/argmax/argsort while naming the axis, reshape and transpose deliberately, and compute a norm. That list is roughly a dozen functions. NumPy is named explicitly in official objectives 1.6, 1.10 and 4.6, so its capabilities are examinable; nothing suggests you will be asked about obscure API surface. The exam-relevant skill is recognising which NumPy operation a described task needs, not recalling keyword arguments.

Glossary recap: the terms this lesson introduced

TermDefinition
ScalarA single number; a tensor with shape ().
VectorA 1-D array of numbers, shape (d,). One embedding is a vector.
MatrixA 2-D array, shape (rows, cols). A weight matrix or a stack of embeddings.
TensorThe general term for an n-dimensional numeric array. Scalars, vectors and matrices are all tensors.
ShapeThe tuple of dimension sizes describing a tensor, e.g. (4, 128, 768). The single most useful thing to print when debugging.
Dimension / axisOne entry in the shape tuple. axis=1 refers to the second one, counting from zero.
Hidden size (d_model)The number of features representing one token at a given layer — the last axis of (batch, sequence, hidden).
BatchA group of independent examples processed together. Affects speed and memory, not results.
Sequence lengthThe number of token positions in one example. The axis attention mixes across.
Dot product / inner productΣ aᵢbᵢ — elementwise multiply, then sum, giving one scalar. Magnitude-sensitive.
Norm (L2 norm, ‖a‖)The Euclidean length of a vector, sqrt(Σ aᵢ²).
L2 normalisationDividing a vector by its own norm so its length becomes 1. Makes dot product equal cosine similarity.
Unit vectorA vector whose norm is exactly 1.
Cosine similaritya·b / (‖a‖‖b‖), in [−1, +1]. Direction only. The default for text embedding comparison.
Cosine distance1 − cos(a, b), in [0, 2]. A distance, so smaller is closer.
Euclidean (L2) distancesqrt(Σ (aᵢ−bᵢ)²). Magnitude-sensitive; the right choice when absolute position means something.
Matrix multiplication (matmul, @)A grid of dot products. (m,k) @ (k,n) → (m,n); the inner dimensions must agree.
Elementwise (Hadamard) product (*)cᵢⱼ = aᵢⱼ × bᵢⱼ. Same shape in, same shape out, no summation.
TransposeReordering axes so element (i,j) becomes (j,i). (m,n) → (n,m).
ReshapeRe-cutting the same elements, in memory order, into a new shape with the same total count. Not a transpose.
BroadcastingNumPy's rule for stretching size-1 or missing axes so two shapes align. The commonest source of silently-wrong results.
keepdimsThe reduction argument that preserves the collapsed axis at size 1, so the result still broadcasts correctly.
Argsort / argmaxReturning the indices that would sort or maximise, rather than the values. How a ranked retrieval result is produced.

Key takeaways on linear algebra for LLMs

  1. A shape is a sentence about your data. (4, 128, 768) says "four examples, 128 tokens each, 768 features per token". If you cannot say that sentence, you cannot debug the code.
  2. The dot product is one multiplication per position and one sum. That is the whole operation, and it is the atom every layer of a transformer is built from.
  3. Cosine similarity is the dot product with both magnitudes divided out, bounded to [−1, +1], measuring direction only. It is the default for text because document length must not decide topical relevance.
  4. Normalise once and the two become identical. L2-normalising at index time turns semantic search into a single matrix multiplication — which is why this arithmetic is also a hardware story.
  5. Matmul's only rule is that inner dimensions match, and for higher-rank tensors the last two axes are the matrix while the rest is a batch. That rule alone predicts most output shapes you will need.
  6. The axis you pass is the axis that disappears. Everything else about reductions follows from that.
  7. Broadcasting failures do not raise exceptions. (N,) against (N,1) gives you (N,N) and a plausible wrong answer. Assert your shapes; keepdims=True is cheap insurance.
  8. A similarity score is not a probability. Ranking with it is legitimate; treating 0.8 as "80% relevant" is not, and the threshold you settle on has to be measured on your own data.
  9. Vectors from two different embedding models are not comparable. No error will tell you. This is the root of the embedding-model version-pinning discipline you will meet again in the RAG modules.
  10. This lesson is deliberately short for its importance. Tensor shapes (C03) and dot product / cosine similarity (C04) have the two highest dependency counts in the entire course, but the way to honour that is airtightness, not length. If you can do section 4's arithmetic on paper and predict section 5's shapes without running anything, you are done here.

Next: what a GPU does and why it decides what you can run

You can now say what a matrix multiplication is. What you do not know yet is why the same multiplication takes an hour on your laptop and a minute on rented hardware, why a model that loads fine one moment throws an out-of-memory error the next, and what the numbers in "24 GB of VRAM" actually have to be spent on. That is not trivia — it is the constraint that decides which experiments you are allowed to run at all, and the first hands-on lab in this course assumes you already understand it even though the lab is not about hardware.

Next: M0.2 How GPUs work and what happens during a training run — parallelism, memory as the binding constraint, the four things that occupy VRAM during training, and a deliberately provoked out-of-memory error so that when you meet a real one you recognise it in seconds instead of hours.