Skip to main content
Fanout
Singular Value Decomposition (SVD)
Curriculum overview

Math Fundamentals · lesson 13/15

Singular Value Decomposition (SVD)

The singular value decomposition factors any matrix into two rotations and a scaling. It tells you which directions a matrix stretches, by how much, and it gives the best low-rank approximation of that matrix for free. Compression, PCA, and LoRA all rest on it.

The idea

Every real matrix ARm×nA \in \mathbb{R}^{m \times n} can be written

A=UΣVA = U \Sigma V^\top

where UU is m×mm \times m with orthonormal columns (left singular vectors), VV is n×nn \times n with orthonormal columns (right singular vectors), and Σ\Sigma is m×nm \times n with non-negative entries σ1σ20\sigma_1 \geq \sigma_2 \geq \dots \geq 0 on the diagonal.

The reading: VV^\top rotates the input into a basis where the action of AA is axis-aligned, Σ\Sigma scales along those axes, and UU rotates back out. Three consequences:

  • Rank equals the number of nonzero singular values.
  • Energy along component ii is σi2\sigma_i^2, and the fraction retained by the first kk components is ikσi2/iσi2\sum_{i \leq k} \sigma_i^2 / \sum_i \sigma_i^2.
  • Eckart–Young — the best rank-kk approximation in both the Frobenius and spectral norms is Ak=ikσiuiviA_k = \sum_{i \leq k} \sigma_i u_i v_i^\top, made by truncating the decomposition. The Frobenius error is i>kσi2\sqrt{\sum_{i > k} \sigma_i^2}.

LoRA applies exactly this idea to a weight update: it assumes ΔW\Delta W is approximately low rank and learns two thin factors instead of the full matrix.

Worked example

Take the symmetric matrix A=(3113)A = \begin{pmatrix} 3 & 1 \\ 1 & 3 \end{pmatrix}. Its singular values are 44 and 22, with singular directions u1=(1,1)/2u_1 = (1,1)/\sqrt{2} and u2=(1,1)/2u_2 = (1,-1)/\sqrt{2}. Expanding term by term:

A=4u1u1+2u2u2=(2222)+(1111)=(3113)A = 4 u_1 u_1^\top + 2 u_2 u_2^\top = \begin{pmatrix} 2 & 2 \\ 2 & 2 \end{pmatrix} + \begin{pmatrix} 1 & -1 \\ -1 & 1 \end{pmatrix} = \begin{pmatrix} 3 & 1 \\ 1 & 3 \end{pmatrix}

The energy split is 42=164^2 = 16 and 22=42^2 = 4, totaling 20, so the rank-1 term captures 16/20=80%16/20 = 80\% of the energy. The best rank-1 approximation is the first term, with Frobenius error 4=2\sqrt{4} = 2. A rank-1 matrix cannot represent a general 2×22 \times 2 matrix, so the missing 20% is exactly the information the second direction carried.

In code

import numpy as np

A = np.array([[3.0, 1.0], [1.0, 3.0]])
U, s, Vt = np.linalg.svd(A)
print(s)                       # [4. 2.]
print(U @ np.diag(s) @ Vt)     # [[3. 1.] [1. 3.]] reconstruction

A1 = s[0] * np.outer(U[:, 0], Vt[0])
print(np.linalg.norm(A - A1))  # 2.0, best rank-1 Frobenius error

np.linalg.svd returns VV^\top rather than VV, and the singular values as a 1-D array in descending order.

Check yourself

  1. What does a singular value of zero imply about the matrix, and about solving Ax=bAx = b?
  2. State the Eckart–Young result in your own words.
  3. Why does truncating the smallest singular values compress an image or a weight matrix with limited loss?

Key takeaways

  • SVD factors any matrix into orthogonal directions and non-negative scales.
  • Rank is the count of nonzero singular values; energy is the sum of their squares.
  • Truncated SVD is the provably best low-rank approximation, which is why it powers compression, PCA, and low-rank adapters.