Unit 9, lesson 64

Training Neural Networks

How a training loop with mini-batches fits a neural network, why weight initialization and vanishing or exploding gradients matter, and how momentum, the Adam optimizer and batch normalization work in training and evaluation.

  • Video 64
  • Training and Evaluating Networks

A correct gradient is only one ingredient of training. The data have to be split and shuffled, the weights need starting values, an optimizer turns gradients into updates, and progress has to be judged on data the updates never saw. This lesson follows a small constructed experiment, a two-feature classifier trained with two learning rates, and uses it to define the training loop. It then explains how initialization and depth decide whether gradients stay usable, how momentum and Adam use past gradients, and why batch normalization behaves differently in training and in evaluation.

Key terms

Training loop

Definition A training loop fits the parameters θ\boldsymbol{\theta} of a model to a training set of nn examples by repeating epochs, where an epoch is one pass through the training data. In each epoch it does the following.

  1. Shuffle the order of the training examples and split it into mini-batches.
  2. For each mini-batch of mm examples, run the forward pass, compute the mean loss over the batch, clear any stored gradients, run the backward pass, and let the optimizer update every parameter with the gradients from this same forward pass.
  3. After the epoch, compute the loss on the full training set and on the validation set with the model in evaluation mode and without any update.
  4. When the validation loss is the best so far, save a copy of the parameters as a checkpoint, with the epoch number and, if training may resume, the optimizer state.

Validation examples never enter a gradient, and the test set is not used inside the loop. For a binary label yy in {0,1}\{0, 1\} and a logit zz, the loss of one example computed directly from the logit is

ℓ(z,y)=ln⁡(1+ez)−yz,\ell(z, y) = \ln\bigl(1 + e^{z}\bigr) - yz ,

which equals the binary cross-entropy −yln⁡σ(z)−(1−y)ln⁡(1−σ(z))-y\ln\sigma(z) - (1 - y)\ln\bigl(1 - \sigma(z)\bigr). The derivative of the batch mean with respect to the logit of example ii is (σ(zi)−yi)/m\bigl(\sigma(z_i) - y_i\bigr)/m. Evaluating ln⁡(1+ez)\ln(1 + e^{z}) in a numerically stable way avoids taking the logarithm of a probability that has rounded to 00 or 11.

In plain words The loop is the experiment written as code, and each line has one job. Many failed runs come from a line doing the wrong job, such as gradients left over from the previous batch, a loss summed where the learning rate assumes a mean, or validation run in training mode. A learning-rate schedule, if used, belongs to the loop as well and must say whether it advances per update or per epoch. A fixed random seed makes the shuffles and the initialization repeatable on the same software, but other hardware or library versions can still change the floating-point results.

Example In a constructed problem two features are drawn uniformly from [−1,1][-1, 1], and the label is 11 when x1x2≥0x_1 x_2 \ge 0, that is, in the first and third quadrants including the axes. No straight line separates the classes. Separate random draws give 9696 training and 4848 validation examples. The network has 22 inputs, 88 hidden tanh⁡\tanh units and 11 logit, both runs start from the same initialization, and plain mini-batch gradient descent with batches of 1616 makes 66 updates per epoch for 250250 epochs, with a constant learning rate of 0.030.03 or 33. With the examples of a batch stored as the rows of a 16×216 \times 2 array, the hidden array is 16×816 \times 8, the logits form a vector of length 1616, and every gradient array has the shape of its parameter. The validation results were

RunEpochValidation lossCorrect of 48
Both rates, before training00.712924
Rate 0.032500.654934
Rate 3, best checkpoint910.364143
Rate 3, last epoch2500.420542

Predicting 0.50.5 for everyone gives a validation loss of ln⁡2≈0.6931\ln 2 \approx 0.6931, and predicting class 11 for everyone gets 2626 of 4848 right, so the slow run made only modest progress in 15001500 updates. The fast run did much better, but its validation loss fluctuated, for example 0.52100.5210 at epoch 100100, and its last state is worse than the checkpoint from epoch 9191, which is the model kept. This is one seed on one small constructed problem, so it does not show that large learning rates are better in general. The checkpoint was chosen for its validation loss, so 0.36410.3641 is an optimistic estimate of its loss on new data, and an untouched test set gives the honest final number.

Weight initialization

Definition Weight initialization is the rule that sets the parameters before the first update. It has two jobs. The first is to break symmetry. If two hidden units of a layer start with the same incoming weights, the same bias and the same outgoing weights, they compute the same value on every input and receive the same gradients, so gradient descent, momentum and Adam keep them identical forever. Random initial weights break this symmetry, and biases can then start at 00. The second job is to set the scale. Suppose a preactivation is z=∑j=1ninwjxjz = \sum_{j=1}^{n_{\text{in}}} w_j x_j with weights drawn independently of each other and of the inputs, each with mean 00 and variance s2s^2. Then, over the random draw,

Var⁡(z)=s2∑j=1ninE[xj2].\operatorname{Var}(z) = s^2 \sum_{j=1}^{n_{\text{in}}} E\bigl[x_j^2\bigr] .

The choice s2=1/nins^2 = 1/n_{\text{in}} keeps Var⁡(z)\operatorname{Var}(z) equal to the average of the E[xj2]E[x_j^2]. Glorot initialization, also called Xavier initialization, uses s2=2/(nin+nout)s^2 = 2/(n_{\text{in}} + n_{\text{out}}) and was derived for activations such as tanh⁡\tanh that are close to linear near 00. He initialization uses s2=2/nins^2 = 2/n_{\text{in}} for ReLU layers. The factor 22 makes up for ReLU setting the negative half of a preactivation that is symmetric around 00 to zero, which halves its mean square.

In plain words Units that start identical stay copies of each other. Weights that start too large push tanh⁡\tanh and sigmoid units into their flat regions, where the derivative is nearly 00, and weights that start too small shrink the signal layer after layer. Scale rules aim to keep typical preactivations and gradients at similar sizes in every layer. They are sensible defaults, not optimal values.

Example The experiment drew first-layer weights with standard deviation 1/21/\sqrt{2}, for two inputs, and output weights with standard deviation 1/81/\sqrt{8}, for eight hidden units, with all biases 00. Features uniform on [−1,1][-1, 1] have E[xj2]=1/3E[x_j^2] = 1/3, so averaged over the random draw each first-layer preactivation starts with variance 2⋅12⋅13=132 \cdot \tfrac12 \cdot \tfrac13 = \tfrac13. If instead every weight and bias starts at 00, every hidden value is tanh⁡(0)=0\tanh(0) = 0. The output weights then get the gradient H⊤δ=0H^{\top}\boldsymbol{\delta} = \mathbf{0}, where HH holds the hidden values and δ\boldsymbol{\delta} the derivatives of the loss with respect to the logits, and the first-layer gradients are multiples of the output weights, which are 00. Only the output bias ever changes, so the network remains a constant predictor at every learning rate. Rerun this way at rate 33, the experiment ends with a validation loss of about 0.69270.6927, essentially that of predicting 0.50.5 for everyone.

Vanishing and exploding gradients

Definition Consider hidden layers h(k)=ϕ(W(k)h(k−1)+b(k))\mathbf{h}^{(k)} = \phi\bigl(W^{(k)}\mathbf{h}^{(k-1)} + \mathbf{b}^{(k)}\bigr) for k=1,…,Mk = 1, \dots, M, and write Jk=diag⁡(ϕ′(z(k)))W(k)J_k = \operatorname{diag}\bigl(\phi'(\mathbf{z}^{(k)})\bigr)W^{(k)} for the Jacobian of layer kk with respect to its input. The chain rule gives, for l<Ml < M,

hˉ(l)=Jl+1⊤Jl+2⊤⋯JM⊤ hˉ(M),\bar{\mathbf{h}}^{(l)} = J_{l+1}^{\top} J_{l+2}^{\top} \cdots J_{M}^{\top}\, \bar{\mathbf{h}}^{(M)},

so the gradient reaching an early layer is a product of many factors, and in the spectral norm

∥hˉ(l)∥2≤(∏k=l+1M∥Jk∥2)⋅∥hˉ(M)∥2.\begin{aligned} \bigl\lVert \bar{\mathbf{h}}^{(l)} \bigr\rVert_2 &\le \Bigl( \prod_{k=l+1}^{M} \lVert J_k \rVert_2 \Bigr) \\[0.4em] &\quad \cdot \bigl\lVert \bar{\mathbf{h}}^{(M)} \bigr\rVert_2 . \end{aligned}

A vanishing gradient is one whose size shrinks roughly geometrically toward the early layers, so their parameters barely change. An exploding gradient grows roughly geometrically and produces huge or nonfinite updates. If ∣ϕ′∣≤1\lvert \phi' \rvert \le 1, as for tanh⁡\tanh, and every ∥W(k)∥2≤ρ<1\lVert W^{(k)} \rVert_2 \le \rho < 1, the bound falls at least like ρM−l\rho^{M-l}, and for the sigmoid ∣ϕ′∣≤1/4\lvert \phi' \rvert \le 1/4. No norm bound forces an explosion, but factors larger than 11 along the directions the gradient actually takes make one happen. Gradient clipping by norm with a threshold τ>0\tau > 0 replaces g\mathbf{g} by gmin⁡(1,τ/∥g∥2)\mathbf{g}\min\bigl(1, \tau/\lVert \mathbf{g} \rVert_2\bigr), which limits the length of a step and keeps its direction.

In plain words Each layer multiplies the backward signal by its own factor. Many factors a little below 11 starve the early layers of signal, and many factors above 11 blow it up. Watching the gradient norm of each layer and checking for nonfinite values often shows the problem earlier than the loss does. Scale-aware initialization, ReLU-type activations, normalization layers and smaller learning rates all help. Clipping tames an explosion but cannot restore a gradient that has vanished, and it does not repair a wrong loss.

Example A chain of ten scalar factors equal to 0.50.5 multiplies a gradient by (1/2)10=1/1024≈0.000977(1/2)^{10} = 1/1024 \approx 0.000977, and ten factors equal to 22 multiply it by 10241024. The derivative 1−tanh⁡2(z)1 - \tanh^2(z) is 11 at z=0z = 0, about 0.420.42 at z=1z = 1 and about 0.000180.00018 at z=5z = 5, so a saturated tanh⁡\tanh unit passes back less than 0.02%0.02\% of the gradient it receives. In a chain of ten sigmoid units joined by weights equal to 11, the gradient is multiplied by at most (1/4)10≈9.5×10−7(1/4)^{10} \approx 9.5 \times 10^{-7}. Clipping the gradient (30,40)(30, 40), whose norm is 5050, at τ=5\tau = 5 gives (3,4)(3, 4).

Momentum

Definition Gradient descent with momentum keeps a running average m\mathbf{m} of past gradients. With a momentum constant β\beta in [0,1)[0, 1), a learning rate η>0\eta > 0 and m0=0\mathbf{m}_0 = \mathbf{0}, step tt computes the mini-batch gradient gt\mathbf{g}_t at θt−1\boldsymbol{\theta}_{t-1} and sets

mt=β mt−1+(1−β) gt,θt=θt−1−η mt.\begin{aligned} \mathbf{m}_t &= \beta\,\mathbf{m}_{t-1} + (1 - \beta)\,\mathbf{g}_t, \\[0.4em] \boldsymbol{\theta}_t &= \boldsymbol{\theta}_{t-1} - \eta\,\mathbf{m}_t . \end{aligned}

With β=0\beta = 0 this is plain stochastic gradient descent. Unrolling gives mt=(1−β)∑k=1tβt−kgk\mathbf{m}_t = (1 - \beta)\sum_{k=1}^{t}\beta^{t-k}\mathbf{g}_k, a weighted sum of past gradients whose weights decay geometrically. Many libraries use instead ut=β ut−1+gt\mathbf{u}_t = \beta\,\mathbf{u}_{t-1} + \mathbf{g}_t and θt=θt−1−η′ut\boldsymbol{\theta}_t = \boldsymbol{\theta}_{t-1} - \eta'\mathbf{u}_t. Since mt=(1−β)ut\mathbf{m}_t = (1 - \beta)\mathbf{u}_t, the two produce the same iterates when η′=(1−β)η\eta' = (1 - \beta)\eta, so a learning rate means something only together with its convention. The vector m\mathbf{m} is part of the state of the run.

In plain words Momentum keeps a running direction. Gradients that keep pointing the same way build up, and gradients that flip sign from step to step largely cancel. In a long narrow valley this damps the zigzag across the valley and keeps progress along it. The memory can also carry the parameters past a minimum, so β\beta and η\eta are tuned together on validation data.

Example With β=0.9\beta = 0.9 and a constant gradient 11, the running average is 0.10.1, 0.190.19, 0.2710.271 and in general 1−0.9t1 - 0.9^t, which approaches 11. With gradients alternating 1,−1,1,…1, -1, 1, \dots it is 0.10.1, −0.01-0.01, 0.0910.091, −0.0181-0.0181 and settles into swinging between about ±(1−β)/(1+β)≈±0.0526\pm(1 - \beta)/(1 + \beta) \approx \pm 0.0526. The consistent signal passes through at full size and the oscillating one shrinks by a factor of 1919. Under the library convention a constant gradient 11 builds ut\mathbf{u}_t up toward 1/(1−β)=101/(1 - \beta) = 10, which is why the two conventions need different learning rates.

Adam optimizer

Definition Adam has a learning rate η>0\eta > 0, decay rates β1\beta_1 and β2\beta_2 in [0,1)[0, 1) and a small constant ε>0\varepsilon > 0, with common defaults η=0.001\eta = 0.001, β1=0.9\beta_1 = 0.9, β2=0.999\beta_2 = 0.999 and ε=10−8\varepsilon = 10^{-8}. Starting from m0=v0=0\mathbf{m}_0 = \mathbf{v}_0 = \mathbf{0}, step t=1,2,…t = 1, 2, \dots takes the gradient gt\mathbf{g}_t at θt−1\boldsymbol{\theta}_{t-1} and computes

mt=β1mt−1+(1−β1) gt,vt=β2vt−1+(1−β2) gt2,m^t=mt/(1−β1t),v^t=vt/(1−β2t),\begin{aligned} \mathbf{m}_t &= \beta_1\mathbf{m}_{t-1} + (1 - \beta_1)\,\mathbf{g}_t, \\[0.4em] \mathbf{v}_t &= \beta_2\mathbf{v}_{t-1} + (1 - \beta_2)\,\mathbf{g}_t^2, \\[0.4em] \hat{\mathbf{m}}_t &= \mathbf{m}_t / (1 - \beta_1^t), \\[0.4em] \hat{\mathbf{v}}_t &= \mathbf{v}_t / (1 - \beta_2^t), \end{aligned}

and then

θt=θt−1−η m^tv^t+ε.\boldsymbol{\theta}_t = \boldsymbol{\theta}_{t-1} - \eta\, \frac{\hat{\mathbf{m}}_t}{\sqrt{\hat{\mathbf{v}}_t} + \varepsilon} .

The square, the square root and the division act entry by entry, so every parameter gets its own effective step size. The second moment vt\mathbf{v}_t averages squared gradients, which is not the square of the averaged gradient. The bias corrections undo the pull of the zero starting states, and for a constant gradient g\mathbf{g} they give exactly m^t=g\hat{\mathbf{m}}_t = \mathbf{g} and v^t=g2\hat{\mathbf{v}}_t = \mathbf{g}^2. The vectors mt\mathbf{m}_t and vt\mathbf{v}_t and the counter tt are part of the state of the run. Adam guarantees neither convergence nor good accuracy on new data, and simple convex problems are known on which it does not converge to the minimizer.

In plain words Adam combines momentum with a separate scale for every parameter. Dividing the averaged gradient by the root of the averaged squared gradient makes typical steps about η\eta in size, whatever the scale of each parameter’s gradient, which helps when gradients differ greatly between layers. It is a common default for networks, but it still needs a tuned learning rate and validation checks.

Example At the first step m^1=g1\hat{\mathbf{m}}_1 = \mathbf{g}_1 and v^1=g12\hat{\mathbf{v}}_1 = \mathbf{g}_1^2, so each entry moves by −ηg/(∣g∣+ε)-\eta g/(\lvert g \rvert + \varepsilon), almost exactly η\eta against the sign of its gradient. With η=0.01\eta = 0.01, the default decay rates and a gradient of 22, the raw states are m1=0.2m_1 = 0.2 and v1=0.004v_1 = 0.004, the corrected ones are 22 and 44, and the parameter moves by −0.01⋅2/(2+10−8)≈−0.01-0.01 \cdot 2/(2 + 10^{-8}) \approx -0.01. A gradient of 0.0010.001 moves another parameter by about −0.0099990-0.0099990, nearly the same, while a gradient of 10−910^{-9}, smaller than ε\varepsilon, moves it by only about −0.00091-0.00091. The state matters when a run resumes. If the second gradient of the first parameter is −2-2, the saved state gives m^2=−0.02/0.19≈−0.1053\hat{m}_2 = -0.02/0.19 \approx -0.1053 and v^2=4\hat{v}_2 = 4, a step of about +0.00053+0.00053. A run restarted with fresh zero states would instead step by +0.01+0.01, about nineteen times as far.

Batch normalization

Definition Let a layer’s values for a mini-batch of m≥2m \ge 2 examples form an array with entry hijh_{ij} for example ii and feature jj. In training mode batch normalization computes, for each feature jj over the batch axis,

μj=1m∑i=1mhij,σj2=1m∑i=1m(hij−μj)2,\begin{aligned} \mu_j &= \frac{1}{m}\sum_{i=1}^{m} h_{ij}, \\[0.4em] \sigma_j^2 &= \frac{1}{m}\sum_{i=1}^{m} (h_{ij} - \mu_j)^2, \end{aligned}

and outputs

yij=γj hij−μjσj2+ε+βj,y_{ij} = \gamma_j\, \frac{h_{ij} - \mu_j}{\sqrt{\sigma_j^2 + \varepsilon}} + \beta_j ,

where ε>0\varepsilon > 0 is a small constant and the scale γj\gamma_j and the shift βj\beta_j are learned parameters, usually started at 11 and 00. This shift has nothing to do with the decay rates of an optimizer. The backward pass differentiates through μj\mu_j and σj2\sigma_j^2, so each example’s gradient depends on the other examples of its batch. Training also keeps running estimates of each feature’s mean and variance, typically exponential moving averages of the batch statistics. In evaluation mode the layer uses those stored estimates instead of the current batch, so it applies a fixed affine map to each feature and a prediction depends only on its own input. Libraries differ in details such as the averaging rate and whether the running variance divides by mm or m−1m - 1.

In plain words Batch normalization rescales each feature to mean about 00 and variance about 11 within the batch and then lets the network learn a new scale and shift. It often permits larger learning rates and makes training less sensitive to the initialization. Its two modes really compute different functions, so validation and prediction must run in evaluation mode, and the running estimates should come from training batches only.

Example One feature takes the values 11, 22, 33 and 66 in a batch of four. Then μ=3\mu = 3 and σ2=(4+1+0+9)/4=3.5\sigma^2 = (4 + 1 + 0 + 9)/4 = 3.5, and with γ=1\gamma = 1, β=0\beta = 0 and ε=10−5\varepsilon = 10^{-5} the outputs are about −1.069-1.069, −0.535-0.535, 00 and 1.6041.604. In a batch with the values 33, 44, 55 and 66 the same input value 33 becomes about −1.342-1.342, so in training mode an example’s output changes with its batch mates. If the stored estimates were mean 33 and variance 3.53.5, evaluation mode would map the value 33 to 00 in every batch. A training-mode batch of one example has σ2=0\sigma^2 = 0, so every output equals βj\beta_j whatever the input, and the layer erases the information, which is why batch normalization needs batches of at least two and works poorly with very small ones.

Check yourself

  1. Adam starts with η=0.01\eta = 0.01, β1=0.9\beta_1 = 0.9, β2=0.999\beta_2 = 0.999 and ε=10−8\varepsilon = 10^{-8}, and the first gradient of a parameter is −3-3. Find the raw and the corrected moments and the change of the parameter. Compare with plain gradient descent at the same rate, and with a first gradient of −0.03-0.03.
Show the answer

The raw moments are m1=0.1⋅(−3)=−0.3m_1 = 0.1 \cdot (-3) = -0.3 and v1=0.001⋅9=0.009v_1 = 0.001 \cdot 9 = 0.009. The corrections divide by 1−0.9=0.11 - 0.9 = 0.1 and 1−0.999=0.0011 - 0.999 = 0.001, giving m^1=−3\hat{m}_1 = -3 and v^1=9\hat{v}_1 = 9. The update is −0.01⋅(−3)/(3+10−8)≈+0.01-0.01 \cdot (-3)/(3 + 10^{-8}) \approx +0.01, so the parameter increases by about 0.010.01. Moving against a negative derivative raises the parameter and lowers the loss to first order.

Plain gradient descent at rate 0.010.01 would move the parameter by +0.03+0.03. With a first gradient of −0.03-0.03, Adam still moves it by about +0.01+0.01, while plain gradient descent would move it by only +0.0003+0.0003. The first Adam step depends on the sign of the gradient and hardly on its size, as long as the gradient is much larger than ε\varepsilon.

  1. A model has one parameter and the training objective 12θ2\tfrac12 \theta^2, whose gradient is θ\theta. Gradient descent starts at θ=1\theta = 1 with rate 0.10.1. The framework adds each new gradient into a stored buffer, and the loop never clears it. Compute the first three updates with and without the bug, and describe the trace of the loss.
Show the answer

The correct loop multiplies θ\theta by 0.90.9 at every step, giving 0.90.9, 0.810.81 and 0.7290.729, and after 5050 steps about 0.00520.0052. With the bug the update uses the sum of all gradients so far. The first step uses 11 and gives 0.90.9. The buffer then holds 1+0.9=1.91 + 0.9 = 1.9, so θ=0.9−0.19=0.71\theta = 0.9 - 0.19 = 0.71. Next it holds 1.9+0.71=2.611.9 + 0.71 = 2.61, so θ=0.71−0.261=0.449\theta = 0.71 - 0.261 = 0.449.

The values continue 0.14310.1431, −0.1771-0.1771, −0.4796-0.4796 and keep swinging between about −1.01-1.01 and 1.011.01 without settling. Subtracting consecutive updates gives θt+1=1.9 θt−θt−1\theta_{t+1} = 1.9\,\theta_t - \theta_{t-1}, whose characteristic roots are complex with modulus 11, so the oscillation never decays, and the loss keeps climbing back to about 0.50.5. A loss that falls at first and then oscillates or rises at a learning rate that should be safe is a typical sign of this bug. The fix is to clear the gradients before every backward pass, or, when several batches are accumulated on purpose, to scale the loss by the number of batches, update once and then clear.

  1. A network with dropout and batch normalization is trained by a loop with the following evaluation step. After each epoch the code turns off gradient recording and computes the validation loss with the model still in training mode. It also computes the test loss, and whenever the test loss is the lowest so far it stores best = params, where params is the list of the live parameter arrays. Find the problems and fix them.
Show the answer

Validation in training mode is wrong. Dropout randomly removes units, so the validation loss is noisy and is not the loss of the model that will be used. Batch normalization uses the statistics of each validation batch instead of the stored ones, and in common libraries a training-mode pass also updates the running estimates, so validation data leak into the model. Switch to evaluation mode for validation and back to training mode afterward. Turning off gradient recording only saves memory and time and does not change how these layers behave, so both settings are needed.

Choosing the checkpoint by test loss makes the test set part of model selection, and its loss is then an optimistic estimate. Select the checkpoint by validation loss and evaluate the test set once, at the end.

Storing best = params keeps references to the arrays that later updates keep changing, so the saved model silently becomes the final model. Save copies of the parameters, together with the epoch and, if training may resume, the optimizer state.

How this lesson connects