Skip to content

← ML Foundations step 4 of 10

Easy Primitives

Implement Tanh

Hyperbolic tangent, or tanh, maps negative inputs to negative outputs and positive inputs to positive outputs. It is zero at zero and approaches -1 or 1 as the input magnitude grows:

tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))

For [-1.0, 0.0, 1.0], the result is approximately [-0.761594, 0.0, 0.761594]. Unlike sigmoid, the output is centered around zero.

Compute the same function without overflow

The direct formula can produce infinity divided by infinity for large finite inputs. Divide its numerator and denominator by the larger exponential instead. If z = exp(-2 * abs(x)), the output's magnitude is (1 - z) / (1 + z). Give that magnitude the sign of x.

Near zero, subtracting z from one can lose precision. The function expm1(t) computes exp(t) - 1 accurately for small t. With u = expm1(-2 * abs(x)), the magnitude becomes -u / (2 + u).

You can construct the nonpositive exponent with where: choose -2x for nonnegative x and 2x otherwise. Compute expm1 once, then choose the output sign. This avoids large positive exponential arguments while retaining small outputs near zero.

Your task

Implement tanh(x) elementwise for a floating-point tensor of any shape. Return the same shape. Do not use torch.tanh, jnp.tanh or jax.nn.tanh; use basic arithmetic, expm1 and tensor selection.

The tests include large finite inputs and small inputs near zero. Avoid NaN from overflowing exponentials. In exact arithmetic the result lies strictly between -1 and 1 for finite x; floating-point results can round to either endpoint. This exercise checks forward values.

Loading visualization…