Why Deep Neural Networks Become Hard to Train: Vanishing Gradients, Exploding Gradients, and Weight Initialization
Contents
In the previous post, we looked at regularization through the lens of gradient descent.
We started with the update rule
and then asked what changes when we deliberately constrain the learning process using techniques such as L2 regularization and dropout.
But there is another problem hiding inside this equation.
The update rule assumes that is actually useful.
What happens if the gradient becomes almost zero?
Or what happens if it becomes enormous?
That takes us to one of the fundamental optimization problems in deep neural networks:
Vanishing and exploding gradients.
1. Where does the gradient come from?
Consider a deep network:
During forward propagation, information moves from the input toward the output.
During backpropagation, the gradient travels in the opposite direction:
Suppose we want to update the weights in the first layer.
The network needs to answer:
If I slightly change , how does the final loss change?
Mathematically:
The difficulty is that affects the loss through every layer after it.
So by the chain rule, the gradient contains many multiplied terms.
Schematically:
The important observation is not the exact expression.
It is this:
And repeated multiplication can behave very differently depending on the numbers involved.

Backpropagation does not pass a gradient back unchanged; each layer contributes another multiplication factor on the way to earlier weights.
2. What if those numbers are smaller than 1?
Imagine, just for intuition, that each layer contributes a factor of approximately:
With two layers:
With five layers:
With twenty layers:
The gradient has almost disappeared.
So an early-layer gradient might become:
Then gradient descent performs:
If
then:
The weights barely move.
This is the vanishing gradient problem.
The early layers of a deep network can learn extremely slowly because the learning signal becomes weaker and weaker as it travels backward.
3. What if the multiplied values are larger than 1?
Now suppose each layer contributes roughly:
After twenty layers:
Instead of disappearing, the gradient becomes enormous.
Suppose:
and:
Then:
A single gradient update can move a parameter by a huge amount.
Training may become unstable.
The loss can oscillate wildly or even become NaN.
This is the exploding gradient problem.
So the two extremes are:
and

Products below one can fade into an almost useless learning signal, while products above one can turn the same update rule unstable.
4. Where do these repeated factors come from?
Consider one layer:
and:
During backpropagation, we compute:
and then:
So every layer introduces factors involving:
- the weight matrix
- the derivative of the activation function
This is important.
Gradient flow is not determined by the activation function alone.
It depends on a chain involving both:
and
across many layers.
5. Why is sigmoid particularly problematic?
The sigmoid function is:
Its derivative is:
The maximum possible derivative is:
And when becomes very positive or very negative:
For example:
therefore:
Similarly:
and again:
This region is often called the saturated region of sigmoid.
During backpropagation:
If:
then:
And this small gradient is then passed to the previous layer.
If several layers behave this way:
the gradient can disappear.

A saturated activation behaves like a pinched pipe: the incoming gradient may be present, but the local derivative lets very little through.
6. What about tanh?
The hyperbolic tangent activation is:
with derivative:
Around:
its derivative can be close to:
which is better than sigmoid.
But when becomes large:
and therefore:
So tanh can also suffer from saturation and vanishing gradients.
7. Why did ReLU help?
ReLU is defined as:
Its derivative is:
For positive values:
So the gradient is not multiplied by something like:
or:
Instead:
for the positive region.
This dramatically improves gradient propagation compared with sigmoid in deep networks.
But ReLU does not magically eliminate all gradient problems.
Why?
Because the weights are still involved.
Recall:
Even if:
we are still repeatedly multiplying by weight matrices.
If the weights are too small, gradients can shrink.
If the weights are too large, gradients can explode.
That leads directly to another question:
How should we choose the initial weights of a deep neural network?
8. Why not initialize all weights to zero?
Suppose every neuron in a layer starts with:
Then every neuron receives the same input and produces the same output.
During backpropagation, they also receive identical gradients.
So after one update, they remain identical.
After another update, they are still identical.
The neurons fail to learn different features.
This is called the symmetry problem.
Therefore:
This is why we initialize them randomly.
But random initialization introduces another question.
How large should those random numbers be?
9. Why does the scale of initialization matter?
Consider:
Suppose every weight is large.
Then may become large.
That produces large activations, which then enter the next layer.
The process repeats:
The signal can explode as it travels forward.
The reverse can happen with very small weights.
Activations gradually shrink:
The same type of behavior can appear during backpropagation.
So initialization needs to achieve something subtle:
Keep the scale of activations and gradients reasonably stable as they pass through many layers.
10. Xavier initialization
For activation functions such as tanh, a common initialization is Xavier initialization, also called Glorot initialization.
A simplified form is:
where:
is the number of neurons feeding into the current layer.
In NumPy:
W = np.random.randn(n_l, n_prev) * np.sqrt(1 / n_prev)
The scaling factor is:
Why divide by the number of incoming neurons?
Because each neuron computes a sum:
As increases, more terms are being added together.
If the variance of the weights stayed fixed, the variance of would tend to increase as the number of inputs increased.
Scaling the weights based on:
helps counteract that growth.
The goal is approximately:
rather than letting activation variance continuously grow or shrink.

Initialization is less about making weights generically small and more about keeping the signal scale stable as it moves across layers.
11. Why does ReLU use a different initialization?
ReLU has an important property:
If the input distribution is roughly symmetric around zero, a substantial fraction of activations become zero.
So compared with an activation that preserves both positive and negative values, ReLU effectively removes part of the signal.
To compensate, we use a slightly larger initialization variance.
This leads to He initialization, introduced for rectifier networks.
The common form is:
In NumPy:
W = np.random.randn(n_l, n_prev) * np.sqrt(2 / n_prev)
The scaling factor is:
Compare that with Xavier:
and:
A useful rule of thumb is:
and:
12. What exactly are we trying to preserve?
It is tempting to think weight initialization is simply about choosing “small enough” weights.
That is not quite right.
The real objective is to avoid systematic growth or shrinkage of the signal as depth increases.
Ideally:
and similarly during backpropagation:
Not exactly.
But approximately enough that information can travel through a deep network without disappearing or exploding.
This gives us the central idea:
13. A small experiment
We can see the idea with a simple NumPy experiment.
Suppose we repeatedly pass activations through many linear layers.
import numpy as np
np.random.seed(42)
n = 100
layers = 20
A = np.random.randn(n, 1000)
for l in range(layers):
W = np.random.randn(n, n)
Z = W @ A
A = np.maximum(0, Z)
print(
f"Layer {l + 1:2d} | "
f"mean={A.mean():.4f} | "
f"std={A.std():.4f}"
)
Without appropriate scaling, the activation magnitude can grow rapidly.
Now change the weight initialization to:
W = np.random.randn(n, n) * np.sqrt(2 / n)
This is He initialization.
Run the same experiment again.
The activation scale should remain much more stable across depth.
That difference is exactly what the initialization is trying to achieve.
14. Weight initialization does not solve everything
Even good initialization only determines where optimization starts.
After training begins, weights change.
A network can still encounter:
- unstable gradients
- poorly chosen learning rates
- saturated activations
- dead ReLU neurons
- badly scaled inputs
- optimization difficulties
Modern deep networks therefore combine several ideas:
Later techniques such as Batch Normalization, residual connections, normalization layers, and carefully designed architectures all attack different parts of the same underlying problem:
How do we make information and gradients flow reliably through very deep networks?
15. Connecting everything together
The full conceptual chain is:
Activation functions influence this because:
Sigmoid and tanh can produce:
in saturated regions.
ReLU improves gradient flow for:
because:
But weights still control signal magnitude.
Therefore we carefully initialize them.
For tanh:
For ReLU:
Final Mental Model
Vanishing and exploding gradients are not mysterious bugs.
They are a natural consequence of repeatedly multiplying quantities during backpropagation.
If those quantities systematically have magnitude below :
If they systematically have magnitude above :
Good activation functions and good initialization try to keep the network in the middle:
And this is one of the central ideas behind making deep neural networks trainable.
Papers Worth Reading
If you want to go beyond this intuition, two foundational papers connect directly to the ideas discussed here.
Xavier / Glorot Initialization
Xavier Glorot and Yoshua Bengio — Understanding the Difficulty of Training Deep Feedforward Neural Networks (2010)
This paper studies why deep networks can be difficult to optimize and develops the initialization strategy now commonly called Xavier or Glorot initialization.
He Initialization
Kaiming He, Xiangyu Zhang, Shaoqing Ren, and Jian Sun — Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification (2015)
This work analyzes rectifier networks and introduces the initialization strategy now commonly known as He or Kaiming initialization.
What’s Next?
Initialization helps us control the scale of activations at the beginning of training.
But another question naturally follows:
What if the input features themselves exist on wildly different scales before they even enter the network?
For example:
while:
That leads to the next topic:
Why Normalizing Inputs Makes Gradient Descent Faster.