AI Cheat Sheet Nº 03NumPy np & PyTorch torch, F = torch.nn.functional

Neural Net Training

  1. 1Activations
  2. 2Loss functions
  3. 3Optimizers
  4. 4Metrics

Activation functions

Formula · derivativeNumPyPyTorch
Sigmoidσ(x) = 1 / (1 + e−x)
σ′ = σ(1 − σ)
1/(1+np.exp(-x))torch.sigmoid(x)
Tanh(ex − e−x) / (ex + e−x)
tanh′ = 1 − tanh²
np.tanh(x)torch.tanh(x)
ReLUmax(0, x)
ReLU′ = 1 if x > 0 else 0
np.maximum(0, x)F.relu(x)
Leaky ReLUx if x > 0 else αx, α ≈ 0.01np.where(x>0, x, a*x)F.leaky_relu(x)
GELUx·Φ(x) ≈ ½x(1 + tanh[√(2/π)(x + 0.0447x³)]).5*x*(1+np.tanh(.7979
*(x+.0447*x**3)))
F.gelu(x)
SiLU / Swishx·σ(x), used in Llamax/(1+np.exp(-x))F.silu(x)
Softmaxexi / Σj exj
subtract max(x) for stability
e = np.exp(x-x.max())
e / e.sum()
F.softmax(x, dim=-1)

Loss functions

Formula (mean over n)NumPyPyTorch
MSE (L2)1/n Σ (y − ŷ)²np.mean((y-p)**2)F.mse_loss(p, y)
MAE (L1)1/n Σ |y − ŷ|, robust to outliersnp.mean(np.abs(y-p))F.l1_loss(p, y)
Huber½e² if |e| ≤ δ else δ(|e| − ½δ)a = np.abs(y-p)
np.mean(np.where(a<=d,
.5*a**2, d*(a-.5*d)))
F.huber_loss(p, y)
Binary CE−[y log p + (1 − y) log(1 − p)]
p = σ(z); ∂L/∂z = p − y
-np.mean(y*np.log(p)
+(1-y)*np.log(1-p))
F.binary_cross_
entropy_with_
logits(z, y)
Cross-entropy−log softmax(z)y = −zy + log Σj ezj
∂L/∂z = softmax(z) − onehot(y)
-np.log(P[range(n),y]
).mean()
F.cross_entropy(z, y)
KL div.Σ p log(p / q), distillationnp.sum(p*np.log(p/q))F.kl_div(q.log(), p,
reduction=
"batchmean")

PyTorch's cross_entropy and BCE…with_logits take raw logits (no softmax / sigmoid first): they're fused and numerically stable.

Training checklist

Normalize inputszero mean, unit variance (train stats only)
Check initial loss≈ ln K for K balanced classes; NaN → lower lr, clip grads
Overfit one batchloss → 0, else there's a bug
train() / eval()toggle dropout & BatchNorm
Train ↓ val ↑overfit: dropout, decay, more data, early stop

Autograd & gradients

Chain rule∂L/∂x = ∂L/∂y · ∂y/∂x, layer by layerloss.backward(); w.grad
Grad checkf′(x) ≈ (f(x + h) − f(x − h)) / 2h, h ≈ 1e-5torch.autograd.gradcheck(f, x)
No gradstop tracking (eval, frozen parts)torch.no_grad(), x.detach()

Optimizers

Update rule (g = ∇θL, η = learning rate)torch.optim
SGDθ ← θ − η·gSGD(params, lr=0.1)
Momentumv ← μv + g; θ ← θ − η·vSGD(..., momentum=0.9)
RMSProps ← ρs + (1 − ρ)g²; θ ← θ − η·g / (√s + ε)RMSprop(..., alpha=0.99)
Adamm ← β₁m + (1 − β₁)g; v ← β₂v + (1 − β₂)g²
m̂ = m / (1 − β₁t), v̂ = v / (1 − β₂t); θ ← θ − η·m̂ / (√v̂ + ε)
Adam(..., lr=1e-3,
betas=(0.9, 0.999))
AdamWAdam + decoupled decay θ ← θ − ηλθAdamW(..., weight_decay=0.01)
def adamw_step(w, g, m, v, t, lr=1e-3, b1=0.9, b2=0.999,
               eps=1e-8, wd=0.01):            # NumPy, t starts at 1
    m = b1 * m + (1 - b1) * g                 # 1st moment (mean)
    v = b2 * v + (1 - b2) * g ** 2            # 2nd moment (variance)
    m_hat, v_hat = m / (1 - b1 ** t), v / (1 - b2 ** t)  # bias fix
    w = w - lr * (m_hat / (np.sqrt(v_hat) + eps) + wd * w)
    return w, m, v

Learning-rate schedules (torch.optim.lr_scheduler)

StepLRη · γ⌊epoch / s⌋StepLR(opt, 30, gamma=0.1)
Cosineηmin + ½(ηmax − ηmin)(1 + cos(πt / T))CosineAnnealingLR(opt, T_max=T)
Warmuplinear ramp ~0 → η over first stepsLinearLR(opt, 0.01, total_iters=500)
OneCyclewarm up to max_lr, then annealOneCycleLR(opt, max_lr, total_steps=N)
On plateau× factor when the val metric stallsReduceLROnPlateau(opt, patience=5)

Metrics

FormulaNumPyPyTorch
Accuracy(TP + TN) / Nnp.mean(pred == y)(pred==y).float()
.mean()
PrecisionTP / (TP + FP), predicted + that are rightp1, y1 = pred==1, y==1
tp = (p1 & y1).sum()
fp = (p1 & ~y1).sum()
fn = (~p1 & y1).sum()
P, R = tp/(tp+fp), tp/(tp+fn)
f1 = 2*P*R / (P + R)
torchmetrics.
F1Score(task=
"multiclass",
num_classes=K)
RecallTP / (TP + FN), real + that are found
F12PR / (P + R), for imbalanced data
ConfusionC[i, j] = #(true i, predicted j)C=np.zeros((K,K),int)
np.add.at(C,(y,pred),1)
torchmetrics.
ConfusionMatrix
ROC-AUCarea under the TPR-vs-FPR curveroc_auc_score(y, s) (sklearn)torchmetrics.
AUROC
R²1 − Σ(y − ŷ)² / Σ(y − ȳ)²1 - ((y-p)**2).sum()
/ ((y-y.mean())**2)
.sum()
torchmetrics.
R2Score
Perplexityexp(mean cross-entropy)np.exp(ce_loss)torch.exp(loss)

Init, norm & regularization

He / KaimingW ~ N(0, 2 / nin), for ReLU netsnn.init.kaiming_normal_(w)
XavierVar = 2 / (nin + nout), tanh / sigmoidnn.init.xavier_uniform_(w)
BatchNormγ(x − μB) / √(σ²B + ε) + β, stats over batchnn.BatchNorm1d(n)
LayerNormsame, stats over features of each samplenn.LayerNorm(n)
Dropoutzero with prob p, scale rest by 1 / (1 − p)nn.Dropout(p=0.1)
Weight decayL + λ‖w‖², or θ ← θ − ηλθ (decoupled)AdamW(weight_decay=0.01)

MLP from scratch (NumPy)

Backprop is the chain rule for a dense layer Z = XW + b: dW = Xᵀ·dZ, db = Σ dZ, dX = dZ·Wᵀ.

import numpy as np
def softmax(z):
    e = np.exp(z - z.max(1, keepdims=True))     # stable
    return e / e.sum(1, keepdims=True)

rng = np.random.default_rng(0)                  # X: [N, D], y: [N]
W1 = rng.normal(0, np.sqrt(2 / D), (D, H)); b1 = np.zeros(H)
W2 = rng.normal(0, np.sqrt(2 / H), (H, K)); b2 = np.zeros(K)
for epoch in range(200):
    Z1 = X @ W1 + b1; A1 = np.maximum(0, Z1)    # ReLU
    P = softmax(A1 @ W2 + b2)
    loss = -np.log(P[np.arange(N), y]).mean()
    dZ2 = P.copy(); dZ2[np.arange(N), y] -= 1   # dL/dz
    dZ2 /= N                                    # softmax-onehot
    dW2, db2 = A1.T @ dZ2, dZ2.sum(0)
    dZ1 = (dZ2 @ W2.T) * (Z1 > 0)               # ReLU'
    dW1, db1 = X.T @ dZ1, dZ1.sum(0)
    for p, g in [(W1, dW1), (b1, db1), (W2, dW2), (b2, db2)]:
        p -= lr * g                             # SGD step

Same in PyTorch

model = nn.Sequential(nn.Linear(D, H), nn.ReLU(),
                      nn.Dropout(0.1), nn.Linear(H, K)).to(dev)
loss_fn = nn.CrossEntropyLoss()
opt = torch.optim.AdamW(model.parameters(), lr=1e-3)
sched = torch.optim.lr_scheduler.OneCycleLR(
    opt, max_lr=1e-3, total_steps=E * len(train_dl))
for epoch in range(E):
    model.train()                       # dropout / BN on
    for xb, yb in train_dl:
        xb, yb = xb.to(dev), yb.to(dev)
        loss = loss_fn(model(xb), yb)   # logits in
        opt.zero_grad()                 # grads accumulate!
        loss.backward()                 # autograd = backprop
        nn.utils.clip_grad_norm_(model.parameters(), 1.0)
        opt.step(); sched.step()
    model.eval(); correct = 0
    with torch.no_grad():
        for xb, yb in val_dl:
            pred = model(xb.to(dev)).argmax(1)
            correct += (pred == yb.to(dev)).sum().item()
    acc = correct / len(val_dl.dataset)