Let .

ActivationNote
Sigmoidmax slope , saturates both ends
Tanhmax slope , zero-centered
ReLUundefined at , take
Leaky ReLU if else no dead units
ELU or if else reuse the forward value
GELU is the normal pdf
SiLU / Swishnon-monotone near
Softplussmooth ReLU

Two useful identities

Both let you compute the derivative from the forward output, so you store one tensor instead of two:

From scratch

import torch
 
def check(f, df, x):
    """Compare an analytic derivative against autograd."""
    x = x.clone().requires_grad_(True)
    f(x).sum().backward()
    return (x.grad - df(x.detach())).abs().max()
 
sigmoid   = lambda x: torch.sigmoid(x)
d_sigmoid = lambda x: torch.sigmoid(x) * (1 - torch.sigmoid(x))
 
silu      = lambda x: x * torch.sigmoid(x)
d_silu    = lambda x: (s := torch.sigmoid(x)) * (1 + x * (1 - s))
 
gelu      = lambda x: x * torch.distributions.Normal(0., 1.).cdf(x)
d_gelu    = lambda x: (torch.distributions.Normal(0., 1.).cdf(x)
                       + x * torch.exp(-x**2 / 2) / (2 * torch.pi)**0.5)
 
x = torch.randn(1000, dtype=torch.double)
assert all(check(f, d, x) < 1e-9 for f, d in
           [(sigmoid, d_sigmoid), (silu, d_silu), (gelu, d_gelu)])