|
1 | 1 | """ |
2 | 2 | This script demonstrates the implementation of the Softmax function. |
3 | 3 |
|
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. |
8 | 8 |
|
9 | | -Script inspired from its corresponding Wikipedia article |
| 9 | +Script inspired by its corresponding Wikipedia article: |
10 | 10 | https://en.wikipedia.org/wiki/Softmax_function |
11 | 11 | """ |
12 | 12 |
|
13 | 13 | import numpy as np |
| 14 | +from numpy.exceptions import AxisError |
14 | 15 |
|
15 | 16 |
|
16 | | -def softmax(vector): |
| 17 | +def softmax(vector: np.ndarray, axis: int = -1) -> np.ndarray: |
17 | 18 | """ |
18 | | - Implements the softmax function |
| 19 | + Implements the softmax function. |
19 | 20 |
|
20 | 21 | 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. |
24 | 26 |
|
25 | 27 | 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. |
28 | 31 |
|
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])))) |
32 | 33 | 1.0 |
33 | 34 |
|
34 | | - >>> vec = np.array([5,5]) |
| 35 | + >>> vec = np.array([5, 5]) |
35 | 36 | >>> softmax(vec) |
36 | 37 | array([0.5, 0.5]) |
37 | 38 |
|
38 | 39 | >>> softmax([0]) |
39 | 40 | array([1.]) |
40 | 41 | """ |
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 |
50 | 62 | softmax_vector = exponent_vector / sum_of_exponents |
51 | | - |
52 | 63 | return softmax_vector |
53 | 64 |
|
54 | 65 |
|
55 | 66 | if __name__ == "__main__": |
| 67 | + # Single value |
56 | 68 | 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