Linear Algebra for ML
Vectors, transforms, eigenvalues, SVD and Ax = b solvers. From-scratch Python and NumPy from the lessons.
- Concepts and terms
- Tasks and commands
- Annotated code
- Diagrams
- Defaults and numbers
- Troubleshooting
- Questions and tips
SVD: rotate, scale, rotate#
From Lesson 01.11
Gaussian elimination with partial pivoting#
Tasks in NumPy#
| Task | Code |
|---|---|
| Dot product and length | np.dot(a, b), np.linalg.norm(a) |
| Matrix multiply | A @ B |
| Element-wise multiply | A * B |
| Rank | np.linalg.matrix_rank(A) |
| Eigenvalues and eigenvectors | np.linalg.eig(A) |
| Thin SVD | np.linalg.svd(A, |
| Least squares | np.linalg.lstsq(A, |
| QR, check Q | np.allclose(Q @ Q.T, |
From Lesson 01.01, Lesson 01.02, Lesson 01.03, Lesson 01.11, Lesson 01.17
Truncate, compress and invert with SVD#
U, S, Vt = np.linalg.svd(A, full_matrices=False)S sorted in decreasing orderA_k = U[:, :k] @ np.diag(S[:k]) @ Vt[:k, :]best rank-k approximationcompressed_size = k * (rows + cols + 1)storage for rank kA_pinv = Vt.T @ np.diag(1.0 / S) @ U.Tpseudoinverse, nonzero S onlyx_svd = A_pinv @ bleast-squares solutionx_pinv = np.linalg.pinv(A) @ bsame result from NumPyU, S, V = svd_from_scratch(A)power iteration and deflationA_pinv = pseudoinverse_via_svd(A, tol=1e-10)1/s only for s above tolSolve Ax = b from scratch#
x = gaussian_elimination(A, b)partial pivoting, O(n^3)P, L, U = lu_decompose(A)PA = LU, pay O(n^3) one timex = lu_solve(P, L, U, b)O(n^2) for each new bL = cholesky(A)A = L L^T, symmetric positive definite onlyx = cholesky_solve(L, b)forward, then back substitutionw_ols = least_squares_normal(X, y)solves A^T A x = A^T bw_ridge = ridge_regression(X, y, lam=1.0)adds lam * np.eye(n)x, iters = conjugate_gradient(A, b)SPD, at most n iterationskappa = condition_number(A)S[0] / S[-1], inf if singularTransformation matrices#
| Command | What it does |
|---|---|
rotation_2d(theta) | [[c, -s], [s, c]]. Keeps distances. det 1 |
scaling_2d(sx, | [[sx, 0], [0, sy]]. det is sx * sy |
shearing_2d(kx, | [[1, kx], [ky, 1]]. Rectangles become parallelograms |
reflection_y() | [[-1, 0], [0, 1]]. Flips orientation. det -1 |
reflection_x() | [[1, 0], [0, -1]]. det -1 |
mat_mul(S, | Rotate first, then scale. Order matters |
eigenvalues_2x2(matrix) | Roots of the characteristic equation. Complex if discriminant < 0 |
eigenvector_2x2(matrix, | Unit eigenvector for one eigenvalue |
Pick a solver#
| Command | What it does |
|---|---|
| Gaussian elimination | Square, nonsingular A. O(n^3). One solve |
| LU decomposition | Many solves with the same A. O(n^2) for each solve |
| QR decomposition | Least squares with m >= n. Numerically stable |
| Cholesky | Symmetric positive definite A. Twice as fast as LU |
| Normal equations | Overdetermined, small n. Linear regression |
| SVD / pseudoinverse | Rank-deficient A. Minimum-norm solution |
| Conjugate gradient | Large sparse SPD A. Iterative |
From Lesson 01.17
Key formulas#
- Shapes
- (m x n) @ (n x p) = (m x p). The inner dimensions must match.
- Cosine
- \cos\theta = \frac{a \cdot b}{\lvert a\rvert \lvert b\rvert}. 1 is the same direction, 0 is orthogonal.
- Projection
- \text{proj}_b a = \frac{a \cdot b}{b \cdot b} b. The residual is perpendicular to b.
- Eigen
- Av = \lambda v. Eigenvalues are roots of \det(A - \lambda I) = 0.
- 2x2 eigenvalues
- \lambda^2 - (a+d)\lambda + (ad - bc) = 0.
- SVD
- A = U \Sigma V^T and A v_i = \sigma_i u_i. Rank is the count of nonzero \sigma_i.
- Normal equations
- A^T A x = A^T b. Ridge adds \lambda I to A^T A.
- Condition number
- \kappa = \sigma_{\max} / \sigma_{\min}.
From Lesson 01.01, Lesson 01.02, Lesson 01.03, Lesson 01.11, Lesson 01.17
Numbers and defaults#
| Setting | Default | Note |
|---|---|---|
Zero test in rank() | 1e-10 | Smaller entries count as zero |
| Pivot test in elimination | 1e-12 | Smaller pivot raises ValueError |
power_iteration num_iters | 200 | Stops early at tol=1e-10 |
conjugate_gradient tol | 1e-10 | max_iter defaults to n |
| Safe condition number | < 100 | The solution is accurate |
| Meaningless for float64 | 10^{16} | The matrix is effectively singular |
| Image at rank k=50 | 14.6% | Of the 800 x 600 values |
| LoRA rank | 16 | 131K parameters, not 16M |
From Lesson 01.01, 01.01 code/vectors.py, Lesson 01.11, 01.11 code/svd.py, Lesson 01.17, 01.17 code/linear_systems.py
Troubleshooting#
| Symptom | Cause | Fix |
|---|---|---|
| Shape mismatch error | Inner dimensions differ | Write each shape before you multiply |
inverse_2x2 raises ValueError | Determinant is 0 | Use the pseudoinverse |
| "Matrix is not positive definite" | A is not SPD | Add lambda I, or use LU |
| Weights swing on small input changes | Collinear features, rank deficient | Drop features or add regularization |
| Answer loses digits | kappa near 10^k loses k digits | Regularize, or use QR or SVD |
np.linalg.eig(A.T @ A) is imprecise | It squares the condition number | Use np.linalg.svd(A) |
| Composition gives the wrong point | B @ A applies A first | Multiply in reverse order of application |
| Gram-Schmidt dots are not exactly 0 | Floating point | Compare with a tolerance such as 1e-9 |
From Lesson 01.01, Lesson 01.02, Lesson 01.03, Lesson 01.11, Lesson 01.17
Questions#
- Why factor with LU?
- The O(n^3) cost is paid one time. Each new b costs O(n^2).
- When does Cholesky work?
- A is symmetric positive definite. X^T X + \lambda I is SPD for \lambda > 0.
- What does the determinant tell you?
- The area scale. 0 crushes a dimension. -1 flips orientation.
- Why is truncated SVD the best rank k?
- Eckart-Young. The spectral error is \sigma_{k+1}.
- What do eigenvalues say about stability?
- Magnitude above 1 explodes. Below 1 vanishes.
From Lesson 01.03, Lesson 01.11, Lesson 01.17
Tips#
- PCA is SVD on centered data. The components are the right singular vectors V.
- Explained variance for each component is sigma_i^2 / (n-1).
- Look for a clear gap in the singular values. Keep the values above it to denoise.
- Ridge improves the condition number to (\sigma_{\max} + \lambda) / (\sigma_{\min} + \lambda).
- The pseudoinverse gives the solution with the smallest norm when many solutions exist.
- Orthogonal initialization uses QR to make orthonormal weight columns.
From Lesson 01.01, Lesson 01.11, Lesson 01.17