Navigation
📐 Foundations· 15 min read

Linear Algebra for AI Infrastructure

Tensors, shapes, matrix multiplication, GEMM tiling, and the math that connects model architecture to hardware performance.

linear-algebratensorsgemmtilingloraarithmetic-intensity

AI infrastructure doesn’t require proving theorems daily, but it requires that when you see a formula, you can immediately answer three engineering questions: what shape are the tensors, how much compute and memory does it cost, and what can go wrong numerically?

This chapter builds that intuition for linear algebra — the mathematical foundation underlying every matrix multiply, every attention computation, and every GPU kernel optimization.


1. Three Questions for Every Formula

Take the language model output projection as an example:

Y=XW,X∈R(BS)×H,W∈RH×V\mathbf{Y} = \mathbf{X}\mathbf{W}, \qquad \mathbf{X} \in \mathbb{R}^{(BS) \times H},\quad \mathbf{W} \in \mathbb{R}^{H \times V}

Question 1 — Shape: Do the inner dimensions match? H=HH = H ✓. Output is (BS)×V(BS) \times V.

Question 2 — Cost: Each output element requires HH multiply-adds. Total: 2BSHV2BSHV FLOPs (counting one multiply + one add as 2 ops).

Question 3 — Risk: Large weights → large logits → numerical instability in softmax. Need to consider dtype, memory layout, tiling strategy, and numerical stability.

These three questions apply to every operation in the AI infrastructure stack.

Notation

SymbolMeaning
xxScalar
x\mathbf{x}Vector
X\mathbf{X}Matrix or higher-order tensor
B,S,H,VB, S, H, VBatch size, sequence length, hidden size, vocabulary size
Nh,Dh=H/NhN_h, D_h = H/N_hNumber of attention heads, dimension per head
⊙\odotElement-wise multiplication

2. Scalars, Vectors, Matrices, and Tensors

  • Scalar: a single number — e.g., learning rate η=10−4\eta = 10^{-4}
  • Vector: 1D array — e.g., a token’s hidden state x∈RH\mathbf{x} \in \mathbb{R}^{H}
  • Matrix: 2D array — e.g., linear layer weights W∈RH×4H\mathbf{W} \in \mathbb{R}^{H \times 4H}
  • Tensor: N-dimensional array — e.g., a batch of sequences X∈RB×S×H\mathbf{X} \in \mathbb{R}^{B \times S \times H}

In engineering, a “tensor” carries more than just shape:

data pointer + shape + stride + dtype + device + layout

Two tensors with the same shape may have different memory layouts. Two tensors with the same values may have different dtypes and different numerical error characteristics.

Shape, Indexing, and Stride

A (2,3)(2, 3) row-major matrix:

X=[123456]\mathbf{X} = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix}

Stored contiguously as [1, 2, 3, 4, 5, 6] with stride (3,1)(3, 1). Element XijX_{ij} is at offset 3i+j3i + j.

Transpose X⊤\mathbf{X}^\top has shape (3,2)(3, 2) and stride (1,3)(1, 3) — no data copy needed. But scanning along the last dimension is no longer contiguous in memory — this matters for GPU coalescing.

When you see view, reshape, transpose, or contiguous in PyTorch, always think about both the logical dimensions and the physical memory layout.

Broadcasting

Element-wise operations require matching shapes. Broadcasting allows dimensions of size 1 (or missing) to be logically expanded:

X∈RB×S×H,b∈RH⇒X+b∈RB×S×H\mathbf{X} \in \mathbb{R}^{B \times S \times H}, \quad \mathbf{b} \in \mathbb{R}^{H} \quad \Rightarrow \quad \mathbf{X} + \mathbf{b} \in \mathbb{R}^{B \times S \times H}

The bias b\mathbf{b} is reused across batch and sequence dimensions without copying.

Rules (align from the trailing dimension):

  1. Both sizes are equal, or
  2. One of them is 1, or
  3. One side has no dimension there

Danger: Wrong shapes may “accidentally broadcast” — code runs without error but computes the wrong thing. Always verify shapes explicitly.

Norms

Norms measure the “size” of a vector or matrix:

  • L1 norm: ∥x∥1=∑i∣xi∣\|\mathbf{x}\|_1 = \sum_i |x_i| — used in sparse regularization
  • L2 norm: ∥x∥2=∑ixi2\|\mathbf{x}\|_2 = \sqrt{\sum_i x_i^2} — Euclidean distance, used in gradient clipping
  • Frobenius norm: ∥X∥F=∑ijXij2\|\mathbf{X}\|_F = \sqrt{\sum_{ij} X_{ij}^2} — the matrix equivalent of L2
  • Max norm: ∥x∥∞=max⁡i∣xi∣\|\mathbf{x}\|_\infty = \max_i |x_i|

In AI infra, norms appear everywhere:

  • Gradient clipping: if ∥∇∥2>threshold\|\nabla\|_2 > \text{threshold}, scale down
  • Weight decay: adds λ∥W∥22\lambda \|\mathbf{W}\|_2^2 to loss, penalizing large weights
  • Layer normalization: divides by ∑xi2\sqrt{\sum x_i^2} (related to RMS norm)

3. Dot Product and Matrix Multiplication

Dot Product

x⊤y=∑i=1nxiyi\mathbf{x}^\top \mathbf{y} = \sum_{i=1}^{n} x_i y_i

Two intuitions:

  • Weighted sum: x\mathbf{x} is weights, y\mathbf{y} is values
  • Similarity: normalized dot product = cosine similarity. Larger means more aligned.

This is the core operation inside attention: query-key dot products measure how much each key “matches” the query.

Matrix Multiplication

Matrix multiply is a batch of dot products:

Cij=∑k=1KAikBkjC_{ij} = \sum_{k=1}^{K} A_{ik} B_{kj}

For A∈RM×K\mathbf{A} \in \mathbb{R}^{M \times K} and B∈RK×N\mathbf{B} \in \mathbb{R}^{K \times N}:

  • Output shape: (M,N)(M, N)
  • FLOPs: 2MKN2MKN (each of MNMN elements requires KK multiply-adds)
  • Memory reads: MK+KNMK + KN elements
  • Memory writes: MNMN elements

Batched Matrix Multiplication

In transformers, matmuls are batched over multiple heads and batch dimensions:

C[b,h]=A[b,h]×B[b,h]\mathbf{C}[b, h] = \mathbf{A}[b, h] \times \mathbf{B}[b, h]

Shape: (B,Nh,S,Dh)×(B,Nh,Dh,S)→(B,Nh,S,S)(B, N_h, S, D_h) \times (B, N_h, D_h, S) \rightarrow (B, N_h, S, S)

This is exactly the attention score computation: QK⊤\mathbf{Q}\mathbf{K}^\top.


4. GEMM Tiling: Why It Matters for GPU Kernels

General Matrix Multiply (GEMM) is the most performance-critical operation in deep learning. Understanding tiling explains why GPU kernels are fast — and when they’re not.

Block Decomposition

GEMM Tiling

Split matrices into tiles along MM, NN, and the reduction dimension KK:

C11=A11B11+A12B21\mathbf{C}_{11} = \mathbf{A}_{11}\mathbf{B}_{11} + \mathbf{A}_{12}\mathbf{B}_{21}

Each output tile accumulates partial products along KK. The GPU kernel:

  1. Loads a tile of A\mathbf{A} and B\mathbf{B} into shared memory
  2. Computes partial output using registers (high reuse)
  3. Iterates along KK, accumulating
  4. Writes the final output tile back to HBM

This changes data movement order, not the mathematical result.

Arithmetic Intensity of GEMM

For a (M,K)×(K,N)(M, K) \times (K, N) multiply:

FLOPs=2MKN,Bytes=2(MK+KN+MN) (FP16)\text{FLOPs} = 2MKN, \qquad \text{Bytes} = 2(MK + KN + MN) \text{ (FP16)} Arithmetic Intensity=2MKN2(MK+KN+MN)\text{Arithmetic Intensity} = \frac{2MKN}{2(MK + KN + MN)}

For square matrices (M=N=K=nM = N = K = n):

AI≈2n36n2=n3\text{AI} \approx \frac{2n^3}{6n^2} = \frac{n}{3}

A 4096×4096 GEMM has AI ≈ 1365 — well above the H100’s ops:byte ratio of 295. Large GEMMs are compute-bound. But small GEMMs (like per-token decode with M=1M = 1) have AI ≈ 1 — severely memory-bound.

This is why LLM decode is slow: each token generates a GEMM with M=1M = 1, which can never saturate GPU compute.

Tile Size Tradeoffs

Larger tilesSmaller tiles
✅ Higher data reuse → higher arithmetic intensity✅ Less shared memory per tile → more tiles per SM
✅ Fewer trips to HBM✅ Better occupancy
❌ More shared memory → lower occupancy❌ More HBM trips
❌ Tail blocks waste compute if dimensions aren’t divisible✅ Less waste on irregular shapes

Optimal tile size depends on the GPU’s shared memory capacity, register count, and the specific matrix dimensions. This is what autotuners like cuBLAS and Triton’s compiler optimize.


5. SVD and Low-Rank Approximation (LoRA Connection)

Any matrix W∈Rm×n\mathbf{W} \in \mathbb{R}^{m \times n} can be decomposed:

W=UΣV⊤\mathbf{W} = \mathbf{U} \boldsymbol{\Sigma} \mathbf{V}^\top

Where U\mathbf{U} and V\mathbf{V} are orthogonal matrices and Σ\boldsymbol{\Sigma} is diagonal with singular values σ1≥σ2≥⋯\sigma_1 \geq \sigma_2 \geq \cdots.

Keeping only the top rr singular values gives the best rank-rr approximation:

W≈UrΣrVr⊤\mathbf{W} \approx \mathbf{U}_r \boldsymbol{\Sigma}_r \mathbf{V}_r^\top

Why this matters for AI infra: LoRA (Low-Rank Adaptation) freezes the pretrained weight W0\mathbf{W}_0 and adds a low-rank update:

W=W0+BA,B∈Rm×r,A∈Rr×n\mathbf{W} = \mathbf{W}_0 + \mathbf{B}\mathbf{A}, \qquad \mathbf{B} \in \mathbb{R}^{m \times r}, \quad \mathbf{A} \in \mathbb{R}^{r \times n}

LoRA Decomposition

Instead of fine-tuning mnmn parameters, you train only r(m+n)r(m + n) parameters. With r=16r = 16 and m=n=4096m = n = 4096, that’s a 128× parameter reduction.

This directly impacts infrastructure: LoRA adapters are small enough to hot-swap in serving, store hundreds per GPU, and fine-tune on a single consumer GPU.


Self-Check

  • Given two tensor shapes, determine if matrix multiplication is valid and predict the output shape
  • Calculate the FLOPs for a given matrix multiplication
  • Explain why large GEMMs are compute-bound but small GEMMs (M=1M=1) are memory-bound
  • Explain stride and why transpose doesn’t copy data
  • Identify broadcasting bugs: given two shapes, predict if they broadcast and what the result shape is
  • Explain why LoRA reduces trainable parameters and its infrastructure implications
  • Calculate arithmetic intensity for a GEMM and compare to the GPU’s ops:byte ratio

References