ml-models / Neural network fundamentals / Activation functions intro

Activation functions

The nonlinearity applied after each linear layer: what gives a network more than a straight line. This page shows the shape and slope of sigmoid, tanh, ReLU, leaky ReLU, GELU, SiLU and softplus, why some of them saturate or die, and how gated units such as SwiGLU use a function as a gate.

On this page
  1. Problem
  2. Intuition
  3. Mechanics
  4. The functions and their slopes
  5. Saturation and vanishing gradients
  6. Dead units
  7. GELU and SiLU
  8. Gated linear units
  9. Worked example
  10. Values and slopes at five points
  11. Ten layers of gradient
  12. How a negative bias kills a unit
  13. GELU: exact versus tanh approximation
  14. Gating one number with another
  15. Implementation
  16. Tradeoffs
  17. Check yourself
  18. Connections
  19. Read first
  20. Read next
  21. References

Problem

The neurons and layers page showed that stacking linear layers without anything between them collapses to one linear layer. Something nonlinear has to sit between them. But the choice matters in practice: it decides how well gradients travel backwards through many layers (see backpropagation), how fast training is, and which units can stop learning altogether.

Intuition

An activation is a small fixed curve applied to each number independently. Two properties of the curve decide almost everything:

  • Its range and flatness. Sigmoid and tanh squash large inputs into a bounded interval and go flat there (saturate), so the gradient through them shrinks towards zero. ReLU and its relatives are unbounded on the positive side with slope 1, so the gradient passes through unchanged.
  • What happens for negative inputs. ReLU outputs exactly 0 with slope 0 there: a unit whose input is always negative has no gradient and never recovers (a dead unit). Leaky ReLU, GELU and SiLU keep a small slope or a small negative dip, so something still flows back.

Modern transformers use smooth ReLU-like curves (GELU, SiLU) inside the feed-forward blocks, often as the gate of a gated linear unit (GLU) such as SwiGLU.

Activation functions on the interval −4 to 4 Five curves over x from −4 to 4. Sigmoid rises from 0 to 1 through 0.500 at x = 0. Tanh rises from −1 to 1. ReLU is zero for negative x and equal to x for positive x. GELU and SiLU follow ReLU for large positive x, dip slightly below zero for negative x (GELU reaches about -0.154 near x = −1.5) and return to zero for large negative x. −4 4 0 4 sigmoid (solid) tanh (dashed) relu (grey) gelu (accent) silu (accent, dotted)

GELU and SiLU hug ReLU for positive inputs and are smooth at zero. Their dip below zero is small and shallow.

Mechanics

The functions and their slopes

Namef(x)f′(x)Notes
sigmoid1 / (1 + e⁻ˣ)σ(1 − σ), at most 0.25Output in (0, 1); saturates at both ends.
tanh(eˣ − e⁻ˣ) / (eˣ + e⁻ˣ)1 − tanh², at most 1Zero-centered; saturates at both ends.
ReLUmax(0, x)1 for x > 0, else 0Cheap; dead for x < 0.
leaky ReLUx if x > 0 else 0.01x1 or 0.01Small slope keeps negative inputs trainable.
GELUx · Φ(x)Φ(x) + x·φ(x)Φ is the standard normal CDF, φ its density. Smooth.
SiLU (Swish)x · σ(x)σ(x)(1 + x(1 − σ(x)))Smooth; GELU is close to x·σ(1.702x).
softplusln(1 + eˣ)σ(x)A smooth ReLU; always positive.
Slopes of the activation functions Derivatives over x from −4 to 4. Sigmoid's slope peaks at 0.250 at zero and is almost zero beyond ±4. Tanh's slope peaks at 1.000. ReLU's slope is a step from 0 to 1. GELU's slope overshoots 1 slightly (up to about 1.083 near x = 1) before settling at 1. −4 4 0 1 sigmoid slope tanh slope (dashed) relu slope (grey) gelu slope (accent)

Sigmoid's slope never exceeds 0.25 and tanh's never exceeds 1; both fall to zero away from the origin.

Saturation and vanishing gradients

Backpropagation multiplies the activation's slope into the gradient at every layer. If the slope is at most 0.25, as for sigmoid, ten layers shrink the signal by at least a factor 4¹⁰ ≈ one million. This is the vanishing gradient problem that kept deep sigmoid networks hard to train until ReLU and good initialization arrived. The cure is an activation whose slope is near 1 over a wide range, plus residual connections and normalization (see layer norm and residuals).

Dead units

ReLU's slope is exactly 0 for negative inputs. If a large learning-rate step pushes a unit's bias or weights so that its pre-activation is negative for every example, that unit's output and gradient are both 0 from then on. Nothing in the loss can bring it back. Leaky ReLU (a small fixed slope) or the smooth GELU and SiLU leave a path for gradient.

GELU and SiLU

GELU multiplies x by the probability Φ(x) that a standard normal variable is below x, a smooth gate that is nearly 0 for very negative inputs and nearly 1 for large positive ones. SiLU does the same with the logistic function σ(x) as the gate. Both are non-monotonic: they dip slightly below zero before rising. PyTorch's nn.GELU takes approximate="none" (exact, using the error function) or "tanh", the cheaper formula used in the original GPT-2 and BERT code.

Gated linear units

A GLU splits a projection into two halves a and b and returns a ⊙ gate(b). With a sigmoid gate that is the original GLU (PyTorch's F.glu); with SiLU as the gate on a it is SwiGLU, and with GELU it is GeGLU. The feed-forward blocks of many recent language models use SwiGLU: three weight matrices instead of two, with the hidden size reduced (typically to 2/3) to keep the parameter count similar. See the transformer page for where the feed-forward block sits.

ComponentShape/ParamsMeaningSource
ReLU elementwise, inplace Module wrapper around F.relu. activation.py
Sigmoid / Tanh elementwise Modules that return torch.sigmoid(input) and torch.tanh(input). activation.py, Tanh
LeakyReLU negative_slope=0.01 Slope on the negative side. activation.py
GELU approximate="none" or "tanh" Gaussian-gated linear unit, exact or tanh-approximated. activation.py
SiLU elementwise x times sigmoid of x. activation.py
GLU dim=-1 Splits the input in two along dim and returns the first half times the sigmoid of the second. activation.py
F.relu, F.glu input, dim The functional forms the modules call; glu requires an even size along dim. relu, glu
F.leaky_relu, F.gelu negative_slope, approximate gelu is bound to the C++ kernel and documented in place. leaky_relu, gelu
F.tanh, F.sigmoid, F.silu elementwise Thin wrappers over the tensor ops and C++ kernels. tanh, sigmoid, silu

Worked example

Values and slopes at five points

Functionx = -3x = -1x = 0x = 1x = 3
sigmoid0.047 (0.045)0.269 (0.197)0.500 (0.250)0.731 (0.197)0.953 (0.045)
tanh-0.995 (0.010)-0.762 (0.420)0.000 (1.000)0.762 (0.420)0.995 (0.010)
relu0.000 (0.000)0.000 (0.000)0.000 (0.000)1.000 (1.000)3.000 (1.000)
leaky_relu-0.030 (0.010)-0.010 (0.010)0.000 (0.010)1.000 (1.000)3.000 (1.000)
gelu-0.004 (-0.012)-0.159 (-0.083)0.000 (0.500)0.841 (1.083)2.996 (1.012)
silu-0.142 (-0.088)-0.269 (0.072)0.000 (0.500)0.731 (0.928)2.858 (1.088)
softplus0.049 (0.047)0.313 (0.269)0.693 (0.500)1.313 (0.731)3.049 (0.953)

Each cell is f(x) with the slope f′(x) in brackets. At x = 3 sigmoid's output is 0.953 and its slope is 0.045: nearly flat. At x = −3, ReLU has value and slope 0, leaky ReLU has -0.030 and slope 0.01, GELU has -0.004 with slope -0.012. At x = −1, GELU is -0.159 and SiLU is -0.269: the negative dip. The slopes are checked against finite differences in the test suite.

Ten layers of gradient

Suppose every one of 10 layers has pre-activation z, so backpropagation multiplies the activation's slope 10 times. The product, ignoring the weights:

Activationz = 0z = 2
sigmoid9.5e-071.6e-10
tanh1.0003.1e-12
relu01.000
gelu9.8e-042.266
silu9.8e-042.384

Sigmoid, even at its best point z = 0, passes 9.5e-07 of the gradient (0.25 to the 10th power), and at z = 2 only 1.6e-10. Tanh passes everything at z = 0 but almost nothing at z = 2, where it is saturated. ReLU passes exactly 1 when the unit is on, and exactly 0 when it is off, which leads to the next example. GELU and SiLU have slope slightly above 1 near z = 2, so their product there exceeds 1: smooth curves can amplify as well as shrink. (Real networks also multiply by weight matrices; careful initialization keeps those near 1 in scale.)

How a negative bias kills a unit

A ReLU unit's input is a standard normal variable (mean 0, std 1) plus a bias. The fraction of 4,000 examples for which the unit is active (input above 0):

Bias0-1-3-5
Fraction active49.1%16.5%0.2%0.0%

At bias 0 the unit is active half the time. At −3 it fires on a tiny fraction of examples and receives gradient only from those; at −5 it never fires in this sample: dead. A GELU or leaky unit in the same position would still pass a small gradient back.

GELU: exact versus tanh approximation

Over x from −6 to 6, the largest gap between the exact GELU (via the error function) and its tanh approximation is 0.00047, at x ≈ 2.7. Tiny, but not zero, and it matters when reproducing a checkpoint trained with one version and run with the other. At x = 1 they are 0.84134 and 0.84119.

Gating one number with another

Let a = 1 and b = 2 (the two halves of a projection). The four gated units give: GLU = a·σ(b) = 0.881; SwiGLU = silu(a)·b = 1.462; GeGLU = gelu(a)·b = 1.683; ReGLU = relu(a)·b = 2.000. In all of them one half passes through a nonlinearity and the other half scales it, so the layer can learn which features to let through for each input.

Implementation

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

x = torch.linspace(-4, 4, 9)
print(F.relu(x), F.gelu(x), F.silu(x), F.gelu(x, approximate="tanh"))

class SwiGLUFeedForward(nn.Module):
    def __init__(self, d_model, d_hidden):
        super().__init__()
        self.gate = nn.Linear(d_model, d_hidden, bias=False)
        self.up = nn.Linear(d_model, d_hidden, bias=False)
        self.down = nn.Linear(d_hidden, d_model, bias=False)

    def forward(self, x):
        return self.down(F.silu(self.gate(x)) * self.up(x))

F.glu takes one tensor and splits it in half; the SwiGLU feed-forward above uses two separate projections instead, which is how most transformer implementations write it.

Tradeoffs

  • ReLU is cheap and can die. Its simplicity is hard to beat for small models, but a bad learning rate can leave units permanently off.
  • Smooth curves cost more. GELU and SiLU need an exponential or error function per element, though on a GPU the cost is small next to the matrix multiplications.
  • Sigmoid and tanh are for gates and outputs. They are still right for recurrent-network gates, binary probabilities and bounded outputs, but not as the default hidden activation of a deep network.
  • Gated units add parameters. SwiGLU uses three matrices where a plain feed-forward uses two, so the hidden size is usually adjusted for a fair comparison.
  • Evidence is empirical. The gains of GELU, SiLU and SwiGLU over ReLU are measured on benchmarks, not proved; the difference between the smooth variants is small.
  • Exact and approximate GELU differ. Match the variant a checkpoint was trained with.

Check yourself

What is the largest value the derivative of sigmoid can take, and what does it imply for a 20-layer sigmoid network?

0.25, at z = 0. The activation slopes alone multiply to at most 0.25²⁰ ≈ 10⁻¹², so almost no gradient reaches the early layers.

Why can a ReLU unit become permanently dead but a leaky ReLU unit cannot?

ReLU's slope is exactly 0 for negative inputs, so a unit that is negative for all examples gets no gradient. Leaky ReLU keeps a small slope there, so gradient still flows and the unit can recover.

In SwiGLU(x) = silu(xW) ⊙ (xV), which part is the gate?

The silu(xW) branch: it scales the other branch xV element by element, so features can be passed or suppressed depending on the input.

Connections

Read first

Read next

No page builds on this one yet.

References

  • Hendrycks and Gimpel. Gaussian Error Linear Units (GELUs). 2016. arXiv:1606.08415.
  • Ramachandran, Zoph and Le. Searching for activation functions. 2017. arXiv:1710.05941.
  • Dauphin, Fan, Auli and Grangier. Language modeling with gated convolutional networks. ICML 2017. arXiv:1612.08083.
  • Shazeer. GLU variants improve transformer. 2020. arXiv:2002.05202.
  • Glorot, Bordes and Bengio. Deep sparse rectifier neural networks. AISTATS 2011.
  • PyTorch v2.15.0: GELU, F.glu.