Skip to content

Commit bc2f6eb

Browse files
Enhance softmax with numerical stability and axis parameter (#13409)
* Update softmax.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update softmax.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 96c429d commit bc2f6eb

1 file changed

Lines changed: 45 additions & 26 deletions

File tree

maths/softmax.py

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,75 @@
11
"""
22
This script demonstrates the implementation of the Softmax function.
33
4-
Its a function that takes as input a vector of K real numbers, and normalizes
5-
it into a probability distribution consisting of K probabilities proportional
6-
to the exponentials of the input numbers. After softmax, the elements of the
7-
vector always sum up to 1.
4+
It takes as input a vector of K real numbers and normalizes it into a
5+
probability distribution consisting of K probabilities proportional
6+
to the exponentials of the input numbers. After applying softmax,
7+
the elements of the vector always sum up to 1.
88
9-
Script inspired from its corresponding Wikipedia article
9+
Script inspired by its corresponding Wikipedia article:
1010
https://en.wikipedia.org/wiki/Softmax_function
1111
"""
1212

1313
import numpy as np
14+
from numpy.exceptions import AxisError
1415

1516

16-
def softmax(vector):
17+
def softmax(vector: np.ndarray, axis: int = -1) -> np.ndarray:
1718
"""
18-
Implements the softmax function
19+
Implements the softmax function.
1920
2021
Parameters:
21-
vector (np.array,list,tuple): A numpy array of shape (1,n)
22-
consisting of real values or a similar list,tuple
23-
22+
vector (np.ndarray | list | tuple): A numpy array of shape (1, n)
23+
consisting of real values or a similar list/tuple.
24+
axis (int, optional): Axis along which to compute softmax.
25+
Default is -1.
2426
2527
Returns:
26-
softmax_vec (np.array): The input numpy array after applying
27-
softmax.
28+
np.ndarray: The input numpy array after applying softmax.
29+
30+
The softmax vector adds up to one. We need to ceil to mitigate precision.
2831
29-
The softmax vector adds up to one. We need to ceil to mitigate for
30-
precision
31-
>>> float(np.ceil(np.sum(softmax([1,2,3,4]))))
32+
>>> float(np.ceil(np.sum(softmax([1, 2, 3, 4]))))
3233
1.0
3334
34-
>>> vec = np.array([5,5])
35+
>>> vec = np.array([5, 5])
3536
>>> softmax(vec)
3637
array([0.5, 0.5])
3738
3839
>>> softmax([0])
3940
array([1.])
4041
"""
41-
42-
# Calculate e^x for each x in your vector where e is Euler's
43-
# number (approximately 2.718)
44-
exponent_vector = np.exp(vector)
45-
46-
# Add up the all the exponentials
47-
sum_of_exponents = np.sum(exponent_vector)
48-
49-
# Divide every exponent by the sum of all exponents
42+
# Convert input to numpy array of floats
43+
vector = np.asarray(vector, dtype=float)
44+
45+
# Handle empty input
46+
if vector.size == 0:
47+
raise ValueError("softmax input must be non-empty")
48+
49+
# Validate axis
50+
ndim = vector.ndim
51+
if axis >= ndim or axis < -ndim:
52+
error_message = f"axis {axis} is out of bounds for array of dimension {ndim}"
53+
raise AxisError(error_message)
54+
# Subtract max for numerical stability
55+
vector_max = np.max(vector, axis=axis, keepdims=True)
56+
exponent_vector = np.exp(vector - vector_max)
57+
58+
# Sum of exponentials along the axis
59+
sum_of_exponents = np.sum(exponent_vector, axis=axis, keepdims=True)
60+
61+
# Divide each exponent by the sum along the axis
5062
softmax_vector = exponent_vector / sum_of_exponents
51-
5263
return softmax_vector
5364

5465

5566
if __name__ == "__main__":
67+
# Single value
5668
print(softmax((0,)))
69+
# Vector
70+
print(softmax([1, 2, 3]))
71+
# Matrix along last axis
72+
mat = np.array([[1, 2, 3], [4, 5, 6]])
73+
print("Softmax along last axis:\n", softmax(mat))
74+
# Matrix along axis 0
75+
print("Softmax along axis 0:\n", softmax(mat, axis=0))

0 commit comments

Comments
 (0)