1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
use ndarray::Array2; use ndarray_stats::QuantileExt; use num::Float; /// `identity` generates the identity function /// \\( /// \text{id}(x)=x /// \\) for `Array2` pub fn identity<T>() -> Box<dyn Fn(Array2<T>) -> Array2<T>> { Box::new(|x| -> Array2<T> { x }) } /// `sigmoid` generates the sigmoid function /// \\[ /// S(x)=\dfrac{1}{1+\exp(-x)} /// \\] for `Array2` where \\(x\in\mathbb{R}\\). pub fn sigmoid<T: Float>() -> Box<dyn Fn(Array2<T>) -> Array2<T>> { Box::new(|x| -> Array2<T> { x.map(|val| T::one() / (T::one() + (-*val).exp())) }) } /// `rectified_linear_unit` generates the Rectufied Linear Unit (ReLU) function /// \\[ /// \text{ReLU}(x)=\begin{cases} /// x & (x\gt 0) \\\\ /// 0 & (\text{otherwise}) /// \end{cases} /// \\] for `Array2` where \\(x\in\mathbb{R}\\). pub fn rectified_linear_unit<T: Float>() -> Box<dyn Fn(Array2<T>) -> Array2<T>> { Box::new(|x| -> Array2<T> { x.map(|val| if *val > T::zero() { *val } else { T::zero() }) }) } /// `softmax` generates the softmax function: /// \\\[ /// \text{SoftMax}(\boldsymbol{x})=\left( \dfrac{\exp(x_1)}{\displaystyle\sum^n_{j=1}\exp(x_j)}, /// \dfrac{\exp(x_2)}{\displaystyle\sum^n_{j=1}\exp(x_j)}, \cdots, /// \dfrac{\exp(x_n)}{\displaystyle\sum^n_{j=1}\exp(x_j)} \right) /// \\] for `Array2` where \\(\boldsymbol{x}=\left(x_1,\cdots,x_n\right)^T\subseteq\mathbb{R}^{n\times 1}\\). /// To prevent overflow, actually calculate according to the following equation: /// \\[ /// \begin{array}{lll} /// \dfrac{\exp(x_i)}{\displaystyle\sum^n_{j=1}\exp(x_j)}&=&\dfrac{C\exp(x_i)}{C\displaystyle\sum^n_{j=1}\exp(x_j)}\\\\ /// &=&\dfrac{\exp(x_i+\log C)}{\displaystyle\sum^n_{j=1}\exp(x_j+\log C)}\\\\ /// &=&\dfrac{\exp(x_i+C')}{\displaystyle\sum^n_{j=1}\exp(x_j+C')} /// \end{array} /// \\] /// Therefore, \\(C'\\) can be for all value. /// Thus \\(C'=x_{\text{max}}\\) where \\(^\forall x_i, ^\exists x_{\text{max}}\in\boldsymbol{x}\\) s.t. \\(x_{\text{max}}\geq x_i\\). pub fn softmax<T: Float>() -> Box<dyn Fn(Array2<T>) -> Array2<T>> { Box::new(|x| -> Array2<T> { let max: T = *x.max().unwrap(); let sum: T = x.fold(T::zero(), |acc, val| acc + (*val - max).exp()); // Subtract the maximum value to prevent overflow (this is the equivalent calculation as explained above) x.map(|val| (*val - max).exp() / sum) }) }