Sahaj.blogs
28 Jan 2025 · StudyPhase 8 · Deep Learning

Deep Learning · Activation functions

Sigmoid, tanh, ReLU, Leaky ReLU and GELU compared by shape and gradient, and why saturating activations make deep networks hard to train.

activationrangegradient notes
sigmoid(0, 1)at most 0.25, vanishes for large inputs
tanh(−1, 1)at most 1, zero-centred, still saturates
ReLU[0, ∞)exactly 1 for positive inputs, 0 otherwise (units can “die”)
Leaky ReLUℝa small slope for negative inputs avoids dead units
GELUℝsmooth, used in Transformers (Hendrycks and Gimpel, 2016)

Why it matters: backprop multiplies local gradients layer after layer. With sigmoids, each factor is at most 0.25, so after 10 layers the gradient can shrink by about 0.25¹⁰. That’s the vanishing gradient. I measured the input-gradient norm through 10-layer stacks using PyTorch autograd.

import torch

x = torch.linspace(-4, 4, 9, requires_grad=True)
acts = {"sigmoid": torch.sigmoid, "tanh": torch.tanh, "relu": torch.relu,
        "leaky_relu": torch.nn.functional.leaky_relu, "gelu": torch.nn.functional.gelu}
for name, f in acts.items():
    g, = torch.autograd.grad(f(x).sum(), x)
    print(f"{name:>10}: grad at x=-4..4 -> {[round(v, 3) for v in g.tolist()]}")

torch.manual_seed(0)
for name, f in [("sigmoid", torch.sigmoid), ("tanh", torch.tanh), ("relu", torch.relu)]:
    layers = [torch.nn.Linear(64, 64) for _ in range(10)]
    for l in layers:
        torch.nn.init.kaiming_normal_(l.weight) if name == "relu" else torch.nn.init.xavier_normal_(l.weight)
    inp = torch.randn(32, 64, requires_grad=True)
    h = inp
    for l in layers:
        h = f(l(h))
    h.sum().backward()
    print(f"{name:>8} 10-layer stack: input-gradient norm {inp.grad.norm():.2e}")

Output:

   sigmoid: grad at x=-4..4 -> [0.018, 0.045, 0.105, 0.197, 0.25, 0.197, 0.105, 0.045, 0.018]
      tanh: grad at x=-4..4 -> [0.001, 0.01, 0.071, 0.42, 1.0, 0.42, 0.071, 0.01, 0.001]
      relu: grad at x=-4..4 -> [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0]
leaky_relu: grad at x=-4..4 -> [0.01, 0.01, 0.01, 0.01, 0.01, 1.0, 1.0, 1.0, 1.0]
      gelu: grad at x=-4..4 -> [-0.001, -0.012, -0.085, -0.083, 0.5, 1.083, 1.085, 1.012, 1.001]
 sigmoid 10-layer stack: input-gradient norm 1.40e-05
    tanh 10-layer stack: input-gradient norm 9.23e+00
    relu 10-layer stack: input-gradient norm 8.39e+01

#deep-learning#activations

Sources

  1. CS231n: Neural Networks Part 1 (activation functions) — Stanford CS231n
  2. PyTorch: Non-linear activations — PyTorch
  3. Hendrycks & Gimpel (2016), Gaussian Error Linear Units (GELUs) — arXiv