Non-linear Activation Functions
Implement Sigmoid and ReLU activations to introduce non-linearity into the network.
First Principles: Why Do We Need Activation Functions?
In the previous stage, you calculated the affine combination of a neuron: . However, there is a fundamental mathematical limitation: linear combinations can only produce straight lines or flat planes.
If you stack multiple layers of purely linear neurons, combining linear operations always results in another linear operation. No purely linear network, regardless of depth, can solve non-linear problems such as the XOR logic gate or circular clusters.
To grant neural networks the expressive power to learn intricate curves, shapes, and complex decision boundaries, the linear sum must pass through a non-linear activation functionA mathematical function applied to a neuron's output to introduce non-linearityView official documentation.
Inputs (x) ──> [ Weighted Sum: z = Σ w·x + b ] ──> [ Activation: f(z) ] ──> Output (y)
The Two Essential Functions in this Stage
You will implement the two most influential activations in deep learning history:
1. Sigmoid ()
Squashes any real number from the infinite range into the bounded interval . This makes it ideal for modeling probabilities:
Key intuitive behavior:
- At , the neuron is in a neutral state: , yielding (50% probability).
- For positive values (e.g. ), , and .
- For negative values (e.g. ), , and .
2. ReLU (Rectified Linear Unit)
The workhorse of modern deep architectures due to its extreme computational efficiency and resistance to vanishing gradients:
- If , it returns directly (signal passes through).
- If , it returns (the neuron is deactivated).
Your Objective in this Stage
When standard input receives "op": "activation", your program must process:
function: activation name ("sigmoid"or"relu")value: floating point number
Examples
Example A (Sigmoid):
{ "op": "activation", "function": "sigmoid", "value": 2.0 }
Output:
{ "output": 0.8808 }
Example B (ReLU):
{ "op": "activation", "function": "relu", "value": -3.2 }
Output:
{ "output": 0 }
Practical Implementation and Code Advice
- In Python:
Use the built-in
mathmodule:import math if fn == "relu": out = max(0.0, float(value)) elif fn == "sigmoid": out = 1.0 / (1.0 + math.exp(-float(value))) - In TypeScript:
Use the global
Mathobject:if (fn === "relu") { return { output: roundValue(Math.max(0, value)) }; } if (fn === "sigmoid") { return { output: roundValue(1 / (1 + Math.exp(-value))) }; }
Common Pitfalls
- Do not drop the minus sign in sigmoid's exponent: it is , not .
- For ReLU, do not confuse with absolute value
abs(z): negative numbers must become0, not positive numbers.
Validation and Output Rules
- Allowed Functions: If
functionis neither"sigmoid"nor"relu", writeerrortostderrand exit with code1. - Numeric Precision: Round the result to 4 decimal places. If the rounded value is an integer (such as
0or3), serialize it as an integer in JSON. - Compact Output: Print only the JSON object terminated by a newline:
{ "output": 0.5 }