Handbooks / Machine Learning Basics / Chapter 5
Neural Network Basics
7 pages · ~5 min✓ Reviewed
Builds on Decision Trees and Ensembles.
Perceptron and Layers: The Mental Model
1. The Perceptron
- output = activation(w·x + b)
- Weights scale inputs; bias shifts the decision threshold
- One perceptron = one linear boundary
- XOR is not linearly separable, so it fails
- Inputs x
- w·x + bweighted sum
- Activation
- Output
2. Dense Layer
- Many neurons, same input: y = f(W x + b)
- W is shaped (out, in)
- Params = in × out + out (weights + biases)
python
layer = nn.Linear(4, 3) # W: (3, 4), b: (3,) sum(p.numel() for p in layer.parameters()) # 4*3 + 3 = 15
call-site fragment
3. Why Stacking Needs Nonlinearity
- Linear layers only: W2(W1 x) = one linear map
- Each layer needs a nonlinear activation
- Nonlinearity is what lets a stack solve XOR
Depth needs activations
Without activations, N linear layers collapse into one linear layer.
- Why can one perceptron not solve XOR? It draws only one linear boundary.
- Params in Linear(784, 128)? 784 × 128 + 128 = 100,480
- Why do N linear layers collapse? A product of matrices is a single matrix.
Activations: ReLU, Sigmoid, Softmax
1. The three activations
| ReLU | Sigmoid | Softmax | |
|---|---|---|---|
| Formula | max(0, x) | 1/(1+e^-x) | e^xi / Σ e^xj |
| Output | 0 to ∞ | (0, 1) | probabilities, sum to 1 |
| Use | hidden layers (cheap default) | binary output | multi-class output |
| Catch | dying ReLU: negative input, zero gradient | saturates, gradients vanish | overflow without max shift |
2. Match output to task
| Task | Output | Loss |
|---|---|---|
| Binary | sigmoid | binary cross-entropy |
| Multi-class | softmax | categorical cross-entropy |
| Regression | none (linear) | MSE |
3. Stable softmax
- Subtract max(x) before
exp - Result is unchanged,
expnever overflows
python
import math def softmax(xs): m = max(xs) e = [math.exp(x - m) for x in xs] return [v / sum(e) for v in e]
definition only, call it with your logits
Remember
Hidden layers: ReLU. Output layer: sigmoid, softmax or nothing, chosen by the task.
Forward Pass and Backpropagation
1. Forward Pass
- Feed input layer by layer:
a = f(W a_prev + b) - Cache each layer's input
a_prevand pre-activationz - Backward pass reuses the cache instead of recomputing
2. Backpropagation
- Chain rule from loss to each weight:
dL/dW = dL/da · da/dz · dz/dW - Vanishing gradients: repeated factors below 1 shrink the signal
- Sigmoid derivative peaks at 0.25; ReLU (slope 1 for x > 0) eases it
| Quantity | Formula |
|---|---|
| Weight gradient | dW = δ · a_prevᵀ |
| Bias gradient | db = δ |
| Error passed back | δ_prev = Wᵀ δ ⊙ f'(z) |
3. Training Step
- Forward
- Loss
- Zero grads
- Backward
- Step
python
pred = model(x) loss = loss_fn(pred, y) optimizer.zero_grad() loss.backward() optimizer.step()
call-site fragment; model, x, y defined elsewhere
Zero the gradients
PyTorch accumulates gradients across batches. Skip zero_grad() and each step uses a sum of old and new gradients.
- Why cache z? Backward needs
f'(z)anda_prev. - Why does sigmoid vanish? Derivative is at most 0.25, so deep products shrink.
Loss Functions and Optimizers: SGD vs Adam
1. Loss and the Update
| Task | Loss | Formula |
|---|---|---|
| Regression | MSE | mean of (ŷ − y)² |
| Classification | Cross-entropy | −Σ y log(ŷ) |
- Gradient descent: w ← w − lr · ∂L/∂w
- Momentum keeps a velocity of past gradients
- Smooths noisy steps, speeds convergence
2. SGD vs Adam
| SGD + momentum | Adam | |
|---|---|---|
| Tracks | velocity | running mean m, variance v |
| Step size | one global lr | per-parameter |
| Tuning | lr and schedule | little |
| Result | often generalizes better | converges fast |
| Defaults | none | lr=1e-3, β1=0.9, β2=0.999 |
python
torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9) torch.optim.Adam(model.parameters(), lr=1e-3)
call-site fragment
3. Learning Rate
- Too high: diverges or oscillates
- Too low: crawls
Tune first
The learning rate is the first hyperparameter to tune.
Epochs, Batches and Dropout
1. Epochs, Batches, Order
- Epoch = one full pass over the training set
- Iteration = one batch update
- Iterations per epoch =
N / batch_size - Shuffle training data every epoch
- Never shuffle or augment the validation set
| Batch size | Behaviour |
|---|---|
| Full batch | stable, slow, memory heavy |
| Mini-batch | the usual compromise |
| Size 1 | noisy updates |
2. Dropout and Early Stopping
- Trainingzero fraction p, scale 1/(1−p)
- model.eval()dropout off
- Dropout is a regularizer
- Typical
p: 0.2–0.5 for dense layers - Early stopping: val loss rises while train loss falls
python
model.train() # dropout on ... model.eval() # dropout off with torch.no_grad(): preds = model(x_val)
call-site fragment
Forgot eval()?
Dropout stays on at inference, so predictions are noisy.
- Why shuffle each epoch? Stops order-dependent learning; gradients are less correlated, more representative.
- Why rescale by 1/(1−p)? Keeps expected activation equal in training and eval.
Neural Network Cheat Sheet
1. Layer and Loss Pairing
| Use | Activation | Loss |
|---|---|---|
| Hidden layers | ReLU | n/a |
| Regression | Linear | MSE |
| Binary output | Sigmoid | Binary cross-entropy |
| Multi-class output | Softmax | Categorical cross-entropy |
2. Training Loop
- Forward
- Loss
- zero_grad
- backward
- step
python
pred = model(x) loss = loss_fn(pred, y) opt.zero_grad() loss.backward() opt.step()
call-site fragment: model, x, y, opt defined elsewhere
3. Starting Points
| Setting | Start at |
|---|---|
| Optimizer | Adam, lr=1e-3 |
| Batch size | 32–128 |
| Dropout | 0.2–0.5 |
4. Debug Checklist
- Overfit one small batch first
- Loss NaN: lr too high, or bad softmax/log
- Train/val gap: more regularization
Order matters
Skip zero_grad and gradients accumulate across batches.
Check yourself
Three dense layers have no activation functions. Why is this no better than one layer?
- Each layer is linear: W x + b
- Composing linear maps gives one linear map
- A nonlinear activation such as ReLU between layers fixes it
A loop runs forward, loss, backward, step, but never zero_grad. What goes wrong?
- Gradients accumulate across batches (PyTorch)
- Each update uses old plus new gradients, so training is erratic
- Zero the gradients before backward
A dense layer has 4 inputs and 3 outputs. How many parameters?
- Weights: 4 × 3 = 12
- Biases: 3
- Total 15; W is shaped (3, 4)
The same input gives different predictions on each inference call. Likely cause?
- Dropout is still active
- Call
model.eval()to disable it - Then the full network runs, so output is stable