EasyActivation Functions

Implement Tanh Activation

Activation Functions

Easy

Problem

Apply the hyperbolic tangent activation elementwise:

\tanh(x) = \frac{e^x-e^{-x}}{e^x+e^{-x}}

Here, x is each input value. Return a NumPy array with the same shape as the input and values in (-1,1).

Theory

Before ReLU took over, neural networks needed activation functions that had two properties:

  1. Bounded outputs: prevent activations from growing unboundedly as they pass through many layers
  2. Zero-centered: output both positive and negative values, so the mean activation is close to zero

Sigmoid (\sigma(x) = \frac{1}{1 + e^{-x}}) provides bounded outputs in (0, 1), but it is not zero-centered. All outputs are positive, which creates a systematic bias that can slow down gradient descent.

Tanh solves this.


What Tanh Does

The hyperbolic tangent function is:

\tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}

It squashes any input into the range (-1, 1):

The function is an S-shaped curve, symmetric around the origin. It looks similar to sigmoid but shifted and scaled.


Tanh and Sigmoid: The Exact Relationship

Tanh is actually a rescaled version of sigmoid:

\tanh(x) = 2\sigma(2x) - 1

Both functions have the same S-shape. The difference:

This shift matters for training. When all activations are positive (sigmoid), the gradients for the weights in the next layer all have the same sign. This constrains the gradient to only move in certain directions, causing a zigzag path during optimization. Zero-centered activations (tanh) allow gradients to have mixed signs, enabling more direct paths to the minimum.


The Gradient

The derivative of tanh has a clean formula:

\frac{d}{dx} \tanh(x) = 1 - \tanh^2(x)

This means once you have computed \tanh(x), the gradient is essentially free to calculate.

Some derivative values:

The gradient is largest at the origin and drops off quickly as the input moves away from zero. For |x| > 3, the gradient is practically zero.


The Vanishing Gradient Problem

This rapid gradient decay is tanh's biggest weakness. In deep networks or recurrent networks:

For example, if the derivative is about 0.4 at each of 10 layers:

0.4^{10} \approx 0.0001

The gradient reaching the first layer is 10,000 times smaller than at the last layer.

This is why tanh was largely replaced by ReLU for deep feedforward networks. ReLU's gradient is 1 for positive inputs, so it does not suffer from this multiplicative shrinking.


Where Tanh Is Still Used

Despite the vanishing gradient issue, tanh remains important in several contexts:


Numerical Stability

Computing tanh from the raw formula \frac{e^x - e^{-x}}{e^x + e^{-x}} can cause overflow for large |x| because e^x grows very fast. In practice:

Examples

Example 1

Input
x = [0, 1, -1, 3]
Output
[0.0, 0.761594, -0.761594, 0.995055]
Explanation
Tanh maps zero to zero and maps positive and negative inputs symmetrically toward 1 and -1.

Example 2

Input
x = [[0, 1], [-1, 2]]
Output
[[0.0, 0.761594], [-0.761594, 0.964028]]

Hints

  1. Convert the input with np.asarray(x, dtype=float).
  2. Use NumPy's vectorized np.tanh function.

Requirements

Constraints

Starter Code

import numpy as np

def tanh(x: list) -> np.ndarray:
    """
    Returns a NumPy array with the same shape as x.
    """
    # Write code here
    pass

Test Cases

CaseMatches
Mixed valuesExample 1public
2D arrayExample 3public