AI & Machine Learning Cheatsheet

Neural Networks

Use this AI & Machine Learning reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

What is a Neural Network?

A neural network is a parameterized function composed of many simple transformations, organized in layers. It can approximate any continuous function given sufficient width or depth (Universal Approximation Theorem).

The key insight: stack many linear transformations (matrix multiplications) interspersed with nonlinear activations. The nonlinearities allow the network to learn arbitrarily complex mappings.

The Neuron (Perceptron)

A single neuron computes:

z = Σⱼ wⱼxⱼ + b = wx + b

a = σ(z)

where σ is a nonlinear activation function. Without σ, a stack of linear layers collapses to a single linear layer — the whole network is as expressive as one matrix multiplication.

Activation Functions

ActivationFormulaRangeVanishing GradCommon Use
Sigmoid1/(1+e⁻ˣ)(0,1)Yes, saturatesBinary output
Tanh(eˣ−e⁻ˣ)/(eˣ+e⁻ˣ)(−1,1)Yes, saturatesRNN hidden states
ReLUmax(0, x)[0,∞)Partial (dead neurons)Deep nets (default)
Leaky ReLUmax(αx, x), α small(−∞,∞)NoAvoid dead neurons
ELUx if x>0 else α(eˣ−1)(−α,∞)NoSmooth alternative
GELUx·Φ(x)(−0.17,∞)NoTransformers, BERT
Swishx·σ(x)(−0.28,∞)NoEfficientNet
Softmaxexp(xₖ)/Σ exp(xⱼ)(0,1), sums to 1Multiclass output

ReLU is the most common hidden-layer activation. Its gradient is 1 when x > 0 and 0 otherwise — avoids vanishing gradient, but "dead neurons" (never activated) can occur with bad initialization or high learning rate.

import torch
import torch.nn as nn
import torch.nn.functional as F

# As modules
relu  = nn.ReLU()
gelu  = nn.GELU()
# As functions
x_relu = F.relu(x)
x_gelu = F.gelu(x)

Fully Connected (Dense) Layer

The most fundamental building block:

y = σ(Wx + b)

  • W ∈ ℝ^(out×in): weight matrix
  • b ∈ ℝ^out: bias vector
  • Parameters = out × in + out
linear = nn.Linear(in_features=784, out_features=256, bias=True)
# Parameter count: 784*256 + 256 = 200,960

Multilayer Perceptron (MLP)

Stack of fully connected layers with activations:

x → [Linear → BatchNorm → Activation → Dropout] × L → Linear → output

class MLP(nn.Module):
    def __init__(self, input_dim, hidden_dims, output_dim, dropout=0.3):
        super().__init__()
        dims = [input_dim] + hidden_dims + [output_dim]
        layers = []
        for i in range(len(dims) - 1):
            layers.append(nn.Linear(dims[i], dims[i+1]))
            if i < len(dims) - 2:   # no BN/activation on last layer
                layers.append(nn.BatchNorm1d(dims[i+1]))
                layers.append(nn.GELU())
                layers.append(nn.Dropout(dropout))
        self.net = nn.Sequential(*layers)

    def forward(self, x):
        return self.net(x)

model = MLP(input_dim=128, hidden_dims=[256, 256], output_dim=10)

Backpropagation in Detail

Given a loss L, backprop computes gradients using the chain rule:

∂L/∂wᵢⱼ = ∂L/∂aₗ · ∂aₗ/∂zₗ · ∂zₗ/∂wᵢⱼ

For each layer l (going backward): 1. Receive ∂L/∂aₗ from the layer above 2. Compute ∂L/∂zₗ = ∂L/∂aₗ ⊙ σ'(zₗ) 3. Compute ∂L/∂Wₗ = ∂L/∂zₗ · aₗ₋₁ᵀ and ∂L/∂bₗ = ∂L/∂zₗ 4. Pass ∂L/∂aₗ₋₁ = Wₗᵀ · ∂L/∂zₗ to the previous layer

Modern frameworks (PyTorch, JAX, TensorFlow) do this automatically via automatic differentiation.

Loss Functions

ProblemLossFormula
Binary classificationBinary cross-entropy−[y log p + (1−y) log(1−p)]
MulticlassCategorical cross-entropy−Σₖ yₖ log pₖ
RegressionMSE(y − ŷ)²
Regression (robust)MAE|y − ŷ|
Regression (robust+smooth)HuberMSE if |r|<δ, else MAE
Object detectionFocal loss−(1−pₜ)^γ log pₜ — down-weights easy negatives
EmbeddingsContrastive / TripletPulls similar pairs together
# Classification
loss_fn = nn.CrossEntropyLoss()   # expects logits (before softmax)
loss = loss_fn(logits, y_true)    # y_true: class indices

# Regression
loss_fn = nn.MSELoss()
loss_fn = nn.SmoothL1Loss(beta=1.0)  # Huber loss

Network Depth vs. Width

DimensionEffect
More width (hidden units)Smoother decision boundaries; diminishing returns
More depth (layers)Hierarchical feature composition; more expressive; harder to train

Deep networks can represent certain functions exponentially more efficiently than shallow ones. But depth introduces training challenges (vanishing gradients, optimization difficulty).

Residual Connections (Skip Connections)

The key innovation that enabled training very deep networks (ResNet, 2015):

y = F(x, {Wᵢ}) + x

The skip connection adds the input directly to the block's output. Gradients flow through the shortcut path — this virtually eliminates vanishing gradients and allows training of 100+ layer networks.

class ResidualBlock(nn.Module):
    def __init__(self, dim):
        super().__init__()
        self.block = nn.Sequential(
            nn.Linear(dim, dim), nn.GELU(),
            nn.Linear(dim, dim)
        )
        self.norm = nn.LayerNorm(dim)

    def forward(self, x):
        return self.norm(x + self.block(x))   # pre-norm or post-norm variant

Normalization Layers

MethodNormalizes overWhen to Use
Batch Norm (BN)Batch dimensionCNNs, MLP (batch_size ≥ 32)
Layer Norm (LN)Feature dimensionTransformers, RNNs (any batch size)
Instance NormSpatial dimensions per sampleStyle transfer
Group NormGroups of channelsSmall batches, object detection
RMS NormFeature dim, no mean subtractionModern LLMs (Llama, etc.)

Regularization in Neural Networks

TechniqueHowWhen
L2 weight decayλ Σθ² penaltyAlways; use AdamW
DropoutZero neurons with prob pFC layers, Transformer
DropblockZero contiguous blocksCNNs
Label smoothingReplace hard targets with soft: 0 → ε/K, 1 → 1−εClassification
MixupTrain on convex combinations of (x₁,y₁) and (x₂,y₂)CV, tabular
Stochastic depthRandomly drop entire layersVery deep nets (ViT)
# Label smoothing
loss_fn = nn.CrossEntropyLoss(label_smoothing=0.1)

# Mixup (simplified)
lam = np.random.beta(0.4, 0.4)
mixed_x = lam * x1 + (1 - lam) * x2
mixed_y = lam * y1 + (1 - lam) * y2

Building and Training a Network in PyTorch

import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset

# Data
X, y = torch.randn(1000, 64), torch.randint(0, 10, (1000,))
dataset = TensorDataset(X, y)
loader  = DataLoader(dataset, batch_size=64, shuffle=True)

# Model
model = MLP(64, [128, 128], 10)
device = "cuda" if torch.cuda.is_available() else "cpu"
model = model.to(device)

# Loss and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=20)

# Training loop
for epoch in range(20):
    model.train()
    total_loss = 0
    for xb, yb in loader:
        xb, yb = xb.to(device), yb.to(device)
        optimizer.zero_grad()
        logits = model(xb)
        loss = criterion(logits, yb)
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
        optimizer.step()
        total_loss += loss.item()
    scheduler.step()
    print(f"Epoch {epoch+1}: loss={total_loss/len(loader):.4f}")

# Inference
model.eval()
with torch.no_grad():
    preds = model(X_test.to(device)).argmax(dim=1)

Parameter Count and Memory

For a model with parameters θ: - Storage (FP32): 4 bytes per parameter → 1B parameters = 4 GB - Training memory ≈ 4× weights (weights + gradients + Adam states × 2) - Inference memory ≈ 1–2× weights

def count_params(model):
    total   = sum(p.numel() for p in model.parameters())
    trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
    print(f"Total: {total:,}  |  Trainable: {trainable:,}")

count_params(model)

Universal Approximation Theorem

A neural network with at least one hidden layer with a non-polynomial activation function and sufficient width can approximate any continuous function on a compact subset of ℝⁿ to arbitrary precision.

Key caveats: - Says nothing about how many neurons are needed (could be exponential) - Says nothing about whether gradient descent finds the approximation - Expressiveness ≠ learnability

Depth helps: deep networks can represent certain functions with exponentially fewer neurons than shallow networks.

Common Neural Network Architectures

ArchitectureInput TypeKey MechanismUse Case
MLPTabular vectorsFully connected layersGeneral tabular data
CNNGrid (images)Shared filters + poolingComputer vision
RNN / LSTMSequencesRecurrent hidden stateTime series (classical)
TransformerSequencesSelf-attentionNLP, vision, multimodal
GNNGraphsMessage passingSocial networks, molecules
AutoencoderAnyBottleneck compressionEmbeddings, anomaly detection
GANNoise → imageGenerator vs. discriminatorImage synthesis
DiffusionNoise → imageDenoising score matchingSOTA image/video generation