Thomas Piacentini
← Workshop

Cheat sheet

Math for Machine Learning

Original text · English

Gradients, probability, information, optimizers, decompositions and float safety. NumPy, SciPy and PyTorch.

Computational graph, forward and backward

acbackwardx1 = 2dy/dx1 = 3x2 = 3dy/dx2 = 2Multiplya = 6b = 1dy/db = 1Addc = 7reluy = 7Seeddy/dy = 1
Nodes and connections
NodeRoleKind
x1 = 2dy/dx1 = 3
x2 = 3dy/dx2 = 2
Multiplya = 6
b = 1dy/db = 1
Addc = 7
reluy = 7
Seeddy/dy = 1
FromToConnection
x1 = 2Multiply
x2 = 3Multiply
MultiplyAdda
b = 1Add
Addreluc
reluSeedbackward
Sources

Key formulas

Chain rule
\frac{dy}{dx} = f'(g(x)) \cdot g'(x)
Bayes
P(A \mid B) = \frac{P(B \mid A) \cdot P(A)}{P(B)}
Entropy
H(P) = -\sum_{x} p(x) \log(p(x))
Cross-entropy
H(P, Q) = -\sum_{x} p(x) \log(q(x))
KL divergence
D_{KL}(P \,\|\, Q) = H(P, Q) - H(P). Not symmetric.
Log-sum-exp
\log \sum_i e^{x_i} = \max(x) + \log \sum_i e^{x_i - \max(x)}
Cosine similarity
\frac{a \cdot b}{\lVert a \rVert_2 \, \lVert b \rVert_2}, from -1 to +1
SVD
A = U \Sigma V^T. Rank k: A_k = U_k \Sigma_k V_k^T
Sources

Update rules

Gradient descent
w = w - \text{lr} \cdot \text{gradient}
Momentum
v = \beta v + \text{gradient}, then w = w - \text{lr} \cdot v
Adam moments
m = \beta_1 m + (1 - \beta_1) g, v = \beta_2 v + (1 - \beta_2) g^2
Bias correction
\hat{m} = m / (1 - \beta_1^t), \hat{v} = v / (1 - \beta_2^t)
Adam step
w = w - \text{lr} \cdot \hat{m} / (\sqrt{\hat{v}} + \epsilon)
Cosine schedule
\text{lr}_{\min} + 0.5 (\text{lr}_{\max} - \text{lr}_{\min})(1 + \cos(\pi t / T))
Newton step
w_{\text{new}} = w_{\text{old}} - H^{-1} \cdot \text{gradient}
Temperature
p_i = e^{z_i / T} / \sum_j e^{z_j / T}
Sources

Tasks in NumPy

TaskCode
Dense layernp.maximum(0, weights @ inputs + bias)
Solve a square systemnp.linalg.solve(A, b)
Least squaresnp.linalg.lstsq(X, y, rcond=None)[0]
Thin SVDU, S, Vt = np.linalg.svd(A, full_matrices=False)
Rank k approximationU[:, :k] @ np.diag(S[:k]) @ Vt[:k, :]
Pseudoinverse solvenp.linalg.pinv(A) @ b
Row normsnp.linalg.norm(X, axis=1, keepdims=True)
Batched matmulnp.einsum("bij,bjk->bik", batch_A, batch_B)
Sources

Tasks in PyTorch and SciPy

TaskCode
AdamW for transformerstorch.optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)
Cosine scheduletorch.optim.lr_scheduler.CosineAnnealingLR(adam, T_max=100)
Clip by normtorch.nn.utils.clip_grad_norm_()
Check a backward passtorch.autograd.gradcheck()
Stable log of softmaxtorch.nn.functional.log_softmax()
Inverse CDF of N(0, 1)stats.norm(loc=0, scale=1).ppf(0.975)
PCA to 2DSklearnPCA(n_components=2).fit_transform(X)
t-SNE to 2DTSNE(n_components=2, perplexity=30, random_state=42)
Sources

Autograd in a few lines

x = torch.tensor(2.0, requires_grad=True)record operations on x
y = x ** 2 + 3 * x + 1builds the graph
y.backward()reverse mode pass
print(x.grad)7.0 = 2*x + 3
def __mul__(self, other):
out = Value(self.data * other.data, (self, other), '*')
def _backward():
self.grad += other.data * out.gradlocal grad times upstream
other.grad += self.data * out.grad+= sums over all uses
out._backward = _backward
return out
self.grad = 1.0seed dy/dy = 1
for v in reversed(topo):output to inputs
v._backward()chain rule at each node
Sources

Stable softmax and cross-entropy

def softmax_stable(logits):
max_logit = max(logits)subtract the max first
exps = [math.exp(z - max_logit) for z in logits]largest term is 1
total = sum(exps)
return [e / total for e in exps]
def cross_entropy_stable(true_class, logits):
max_logit = max(logits)
shifted = [z - max_logit for z in logits]
log_sum_exp = math.log(sum(math.exp(s) for s in shifted))
log_prob = shifted[true_class] - log_sum_expstay in log space
return -log_prob
Sources

PCA with SVD

  1. Center subtract the mean from each feature.
  2. Covariance C = \frac{1}{n-1} X^T X for centered X.
  3. Decompose call np.linalg.svd(A) on the data. Avoid eig of A^T A.
  4. Components the right singular vectors V are the principal components.
  5. Variance component i explains \sigma_i^2 / (n-1).
  6. Choose k keep components up to 90 to 95% cumulative variance.
  7. Project keep the top k directions and drop the rest.
Sources

Defaults and numbers

SettingDefaultNote
Adam lr0.001start here for most problems
Adam beta20.999beta1 is 0.9
Adam epsilon1e-8avoids division by zero
SGD momentum lr0.01with momentum 0.9
Gradient check h1e-51e-5 to 1e-7 is typical
Transformer max_norm1.00.5 for RL, 5.0 for simpler nets
Dynamic loss scale start65536halve on inf, double after N clean steps
Top-p0.9with temperature 0.7 for general use
Sources

Troubleshooting

SymptomCauseFix
Loss is NaN after a few epochssoftmax overflow or lr too highstable softmax, lower lr, clip gradients
Loss stuck at log(num_classes)near uniform outputscheck labels, loss function, dead ReLUs
Accuracy 1 to 3% low with float16gradient underflowdynamic loss scaling or bfloat16
Gradient norm 0.0 in some layersdead ReLU or float16 underflowLeakyReLU or GELU, gradient scaling
Results differ across GPUsfloat addition is not associativetorch.use_deterministic_algorithms(True)
0.1 + 0.2 == 0.3 is False0.1 is not exact in binarymath.isclose() or a tolerance
Solution changes a lot for small input changeslarge condition numberadd \lambda I or drop collinear features
One unseen word zeroes Naive BayesMLE gives probability zeroLaplace smoothing, add 1 to counts
Sources

Questions

Why reverse mode?
Many inputs and one loss. One backward pass gives all gradients.
Why cross-entropy?
Minimizing it maximizes the likelihood of the data.
Why bfloat16 for training?
It has the float32 range, so values above 65,504 do not overflow.
Why SVD and not the eigenvectors of A.T @ A?
That product squares the condition number.
Why the reparameterization trick?
z = \mu + \sigma \epsilon lets gradients flow through \mu and \sigma.
Sources

Tips

  • Check shapes: (m x n) @ (n x p) = (m x p).
  • Sum log probabilities. Do not multiply many small probabilities.
  • Never compare floats with ==.
  • Check gradients when you write a new layer or loss.
  • Perplexity is the exponential of cross-entropy in nats.
  • In a gradient check, a relative error below 1e-5 is acceptable.
Sources
Original source
---
id: math-for-ml
title: Math for Machine Learning
code: MM
subtitle: Gradients, probability, information, optimizers, decompositions and float safety. NumPy, SciPy and PyTorch.
hue: 260
sources: phases/01-math-foundations/02-vectors-matrices-operations, phases/01-math-foundations/04-calculus-for-ml, phases/01-math-foundations/05-chain-rule-and-autodiff, phases/01-math-foundations/06-probability-and-distributions, phases/01-math-foundations/07-bayes-theorem, phases/01-math-foundations/08-optimization, phases/01-math-foundations/09-information-theory, phases/01-math-foundations/10-dimensionality-reduction, phases/01-math-foundations/11-singular-value-decomposition, phases/01-math-foundations/12-tensor-operations, phases/01-math-foundations/13-numerical-stability, phases/01-math-foundations/14-norms-and-distances, phases/01-math-foundations/16-sampling-methods, phases/01-math-foundations/17-linear-systems
source_hash: 9cf5b9af88d8d2f2
---

## Computational graph, forward and backward
type: architecture
from: phases/01-math-foundations/05-chain-rule-and-autodiff/docs/en.md

```arch
node | x1 | 1,1 | x1 = 2 | dy/dx1 = 3
node | x2 | 1,2 | x2 = 3 | dy/dx2 = 2
node | mul | 2,1 | Multiply | a = 6
node | b | 2,2 | b = 1 | dy/db = 1
node | add | 3,1 | Add | c = 7
node | relu | 4,1 | relu | y = 7
node | seed | 4,2 | Seed | dy/dy = 1
edge | x1 | mul |
edge | x2 | mul |
edge | mul | add | a
edge | b | add |
edge | add | relu | c
edge | relu | seed | backward
```

## Key formulas
type: concepts
from: phases/01-math-foundations/05-chain-rule-and-autodiff/docs/en.md, phases/01-math-foundations/07-bayes-theorem/docs/en.md, phases/01-math-foundations/09-information-theory/docs/en.md, phases/01-math-foundations/13-numerical-stability/docs/en.md, phases/01-math-foundations/14-norms-and-distances/docs/en.md, phases/01-math-foundations/11-singular-value-decomposition/docs/en.md

- **Chain rule**: $\frac{dy}{dx} = f'(g(x)) \cdot g'(x)$
- **Bayes**: $P(A \mid B) = \frac{P(B \mid A) \cdot P(A)}{P(B)}$
- **Entropy**: $H(P) = -\sum_{x} p(x) \log(p(x))$
- **Cross-entropy**: $H(P, Q) = -\sum_{x} p(x) \log(q(x))$
- **KL divergence**: $D_{KL}(P \,\|\, Q) = H(P, Q) - H(P)$. Not symmetric.
- **Log-sum-exp**: $\log \sum_i e^{x_i} = \max(x) + \log \sum_i e^{x_i - \max(x)}$
- **Cosine similarity**: $\frac{a \cdot b}{\lVert a \rVert_2 \, \lVert b \rVert_2}$, from -1 to +1
- **SVD**: $A = U \Sigma V^T$. Rank $k$: $A_k = U_k \Sigma_k V_k^T$

## Update rules
type: concepts
from: phases/01-math-foundations/08-optimization/docs/en.md, phases/01-math-foundations/04-calculus-for-ml/docs/en.md, phases/01-math-foundations/16-sampling-methods/docs/en.md

- **Gradient descent**: $w = w - \text{lr} \cdot \text{gradient}$
- **Momentum**: $v = \beta v + \text{gradient}$, then $w = w - \text{lr} \cdot v$
- **Adam moments**: $m = \beta_1 m + (1 - \beta_1) g$, $v = \beta_2 v + (1 - \beta_2) g^2$
- **Bias correction**: $\hat{m} = m / (1 - \beta_1^t)$, $\hat{v} = v / (1 - \beta_2^t)$
- **Adam step**: $w = w - \text{lr} \cdot \hat{m} / (\sqrt{\hat{v}} + \epsilon)$
- **Cosine schedule**: $\text{lr}_{\min} + 0.5 (\text{lr}_{\max} - \text{lr}_{\min})(1 + \cos(\pi t / T))$
- **Newton step**: $w_{\text{new}} = w_{\text{old}} - H^{-1} \cdot \text{gradient}$
- **Temperature**: $p_i = e^{z_i / T} / \sum_j e^{z_j / T}$

## Tasks in NumPy
type: task-table
from: phases/01-math-foundations/02-vectors-matrices-operations/docs/en.md, phases/01-math-foundations/11-singular-value-decomposition/docs/en.md, phases/01-math-foundations/17-linear-systems/docs/en.md, phases/01-math-foundations/14-norms-and-distances/docs/en.md, phases/01-math-foundations/12-tensor-operations/docs/en.md

| Task | Code |
|---|---|
| Dense layer | `np.maximum(0, weights @ inputs + bias)` |
| Solve a square system | `np.linalg.solve(A, b)` |
| Least squares | `np.linalg.lstsq(X, y, rcond=None)[0]` |
| Thin SVD | `U, S, Vt = np.linalg.svd(A, full_matrices=False)` |
| Rank k approximation | `U[:, :k] @ np.diag(S[:k]) @ Vt[:k, :]` |
| Pseudoinverse solve | `np.linalg.pinv(A) @ b` |
| Row norms | `np.linalg.norm(X, axis=1, keepdims=True)` |
| Batched matmul | `np.einsum("bij,bjk->bik", batch_A, batch_B)` |

## Tasks in PyTorch and SciPy
type: task-table
from: phases/01-math-foundations/08-optimization/docs/en.md, phases/01-math-foundations/13-numerical-stability/docs/en.md, phases/01-math-foundations/16-sampling-methods/docs/en.md, phases/01-math-foundations/10-dimensionality-reduction/docs/en.md

| Task | Code |
|---|---|
| AdamW for transformers | `torch.optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)` |
| Cosine schedule | `torch.optim.lr_scheduler.CosineAnnealingLR(adam, T_max=100)` |
| Clip by norm | `torch.nn.utils.clip_grad_norm_()` |
| Check a backward pass | `torch.autograd.gradcheck()` |
| Stable log of softmax | `torch.nn.functional.log_softmax()` |
| Inverse CDF of N(0, 1) | `stats.norm(loc=0, scale=1).ppf(0.975)` |
| PCA to 2D | `SklearnPCA(n_components=2).fit_transform(X)` |
| t-SNE to 2D | `TSNE(n_components=2, perplexity=30, random_state=42)` |

## Autograd in a few lines
type: annotated-code
lang: python
from: phases/01-math-foundations/05-chain-rule-and-autodiff/docs/en.md

```python
x = torch.tensor(2.0, requires_grad=True)  # record operations on x
y = x ** 2 + 3 * x + 1                     # builds the graph
y.backward()                               # reverse mode pass
print(x.grad)                              # 7.0 = 2*x + 3
def __mul__(self, other):
    out = Value(self.data * other.data, (self, other), '*')
    def _backward():
        self.grad += other.data * out.grad  # local grad times upstream
        other.grad += self.data * out.grad  # += sums over all uses
    out._backward = _backward
    return out
self.grad = 1.0                            # seed dy/dy = 1
for v in reversed(topo):                   # output to inputs
    v._backward()                          # chain rule at each node
```

## Stable softmax and cross-entropy
type: annotated-code
lang: python
from: phases/01-math-foundations/13-numerical-stability/docs/en.md

```python
def softmax_stable(logits):
    max_logit = max(logits)                           # subtract the max first
    exps = [math.exp(z - max_logit) for z in logits]  # largest term is 1
    total = sum(exps)
    return [e / total for e in exps]
def cross_entropy_stable(true_class, logits):
    max_logit = max(logits)
    shifted = [z - max_logit for z in logits]
    log_sum_exp = math.log(sum(math.exp(s) for s in shifted))
    log_prob = shifted[true_class] - log_sum_exp     # stay in log space
    return -log_prob
```

## PCA with SVD
type: flow
from: phases/01-math-foundations/10-dimensionality-reduction/docs/en.md, phases/01-math-foundations/11-singular-value-decomposition/docs/en.md

1. **Center**: subtract the mean from each feature.
2. **Covariance**: $C = \frac{1}{n-1} X^T X$ for centered X.
3. **Decompose**: call `np.linalg.svd(A)` on the data. Avoid eig of $A^T A$.
4. **Components**: the right singular vectors V are the principal components.
5. **Variance**: component i explains $\sigma_i^2 / (n-1)$.
6. **Choose k**: keep components up to 90 to 95% cumulative variance.
7. **Project**: keep the top k directions and drop the rest.

## Defaults and numbers
type: defaults
from: phases/01-math-foundations/08-optimization/docs/en.md, phases/01-math-foundations/13-numerical-stability/docs/en.md, phases/01-math-foundations/16-sampling-methods/docs/en.md

| Setting | Default | Note |
|---|---|---|
| Adam lr | 0.001 | start here for most problems |
| Adam beta2 | 0.999 | beta1 is 0.9 |
| Adam epsilon | 1e-8 | avoids division by zero |
| SGD momentum lr | 0.01 | with momentum 0.9 |
| Gradient check h | 1e-5 | 1e-5 to 1e-7 is typical |
| Transformer max_norm | 1.0 | 0.5 for RL, 5.0 for simpler nets |
| Dynamic loss scale start | 65536 | halve on inf, double after N clean steps |
| Top-p | 0.9 | with temperature 0.7 for general use |

## Troubleshooting
type: troubleshooting
from: phases/01-math-foundations/13-numerical-stability/docs/en.md, phases/01-math-foundations/17-linear-systems/docs/en.md, phases/01-math-foundations/07-bayes-theorem/docs/en.md, phases/01-math-foundations/08-optimization/docs/en.md

| Symptom | Cause | Fix |
|---|---|---|
| Loss is NaN after a few epochs | softmax overflow or lr too high | stable softmax, lower lr, clip gradients |
| Loss stuck at log(num_classes) | near uniform outputs | check labels, loss function, dead ReLUs |
| Accuracy 1 to 3% low with float16 | gradient underflow | dynamic loss scaling or bfloat16 |
| Gradient norm 0.0 in some layers | dead ReLU or float16 underflow | LeakyReLU or GELU, gradient scaling |
| Results differ across GPUs | float addition is not associative | `torch.use_deterministic_algorithms(True)` |
| `0.1 + 0.2 == 0.3` is False | 0.1 is not exact in binary | `math.isclose()` or a tolerance |
| Solution changes a lot for small input changes | large condition number | add $\lambda I$ or drop collinear features |
| One unseen word zeroes Naive Bayes | MLE gives probability zero | Laplace smoothing, add 1 to counts |

## Questions
type: qa
from: phases/01-math-foundations/05-chain-rule-and-autodiff/docs/en.md, phases/01-math-foundations/09-information-theory/docs/en.md, phases/01-math-foundations/13-numerical-stability/docs/en.md, phases/01-math-foundations/11-singular-value-decomposition/docs/en.md, phases/01-math-foundations/16-sampling-methods/docs/en.md

- **Why reverse mode?** Many inputs and one loss. One backward pass gives all gradients.
- **Why cross-entropy?** Minimizing it maximizes the likelihood of the data.
- **Why bfloat16 for training?** It has the float32 range, so values above 65,504 do not overflow.
- **Why SVD and not the eigenvectors of A.T @ A?** That product squares the condition number.
- **Why the reparameterization trick?** $z = \mu + \sigma \epsilon$ lets gradients flow through $\mu$ and $\sigma$.

## Tips
type: tips
from: phases/01-math-foundations/02-vectors-matrices-operations/docs/en.md, phases/01-math-foundations/13-numerical-stability/docs/en.md, phases/01-math-foundations/07-bayes-theorem/docs/en.md, phases/01-math-foundations/09-information-theory/docs/en.md, phases/01-math-foundations/08-optimization/docs/en.md

- Check shapes: `(m x n) @ (n x p) = (m x p)`.
- Sum log probabilities. Do not multiply many small probabilities.
- Never compare floats with `==`.
- Check gradients when you write a new layer or loss.
- Perplexity is the exponential of cross-entropy in nats.
- In a gradient check, a relative error below 1e-5 is acceptable.
Code and artifacts 1
What you take away

Saved in your notebook on this device.

Sources and limits

Reading checkpoints are self-reported. Test results are recorded separately and apply to the executed cases.

AI Engineering from Scratch · 3f9715c · MIT

Download this file ↓