use crate::Matrix;
use std::f64::consts::PI;
use std::ops::{Add, Mul};
impl<T> Matrix<T>
where
T: PartialOrd + Default + Copy + Mul<Output = T>,
{
pub fn relu(&self) -> Matrix<T>
where
T: PartialOrd + Default + Copy,
{
let data: Vec<T> = self
.data
.iter()
.map(|&x| if x < T::default() { T::default() } else { x })
.collect();
Matrix {
data,
row_size: self.row_size,
col_size: self.col_size,
}
}
pub fn leaky_relu(&self, alpha: T) -> Matrix<T>
where
T: PartialOrd + Default + Copy + Mul<Output = T>,
{
let data: Vec<T> = self
.data
.iter()
.map(|&x| if x < T::default() { x * alpha } else { x })
.collect();
Matrix {
data,
row_size: self.row_size,
col_size: self.col_size,
}
}
pub fn relu_backward(&self) -> Matrix<T>
where
T: Copy + PartialOrd + Default + Add<T, Output = T> + Mul<T, Output = T> + From<u8>,
{
let data: Vec<T> = self
.data
.iter()
.map(|&x| {
if x >= T::default() {
T::default() + T::from(1u8)
} else {
T::default()
}
})
.collect();
Matrix {
data,
row_size: self.row_size,
col_size: self.col_size,
}
}
pub fn gelu(&self) -> Matrix<T>
where
T: Copy + PartialOrd + Default + From<f64> + Into<f64>,
{
let data: Vec<T> = self
.data
.iter()
.map(|&x| {
let x_f64: f64 = x.into();
let x_gelu = 0.5
* x_f64
* (1.0 + ((2.0 / PI).sqrt() * (x_f64 + 0.04715 * x_f64.powi(3))).tanh());
T::from(x_gelu)
})
.collect();
Matrix {
data,
row_size: self.row_size,
col_size: self.col_size,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_relu() {
let matrix = Matrix {
data: vec![1.0, -2.0, 3.0, -4.0, 5.0, -6.0, 7.0, -8.0, 9.0],
row_size: 3,
col_size: 3,
};
let expected = vec![1.0, 0.0, 3.0, 0.0, 5.0, 0.0, 7.0, 0.0, 9.0];
let result = matrix.relu();
assert_eq!(result.data, expected);
}
#[test]
fn test_leaky_relu() {
let matrix = Matrix {
data: vec![1.0, -2.0, 3.0, -4.0, 5.0, -6.0, 7.0, -8.0, 9.0],
row_size: 3,
col_size: 3,
};
let alpha = 0.1;
let expected = vec![
1.0,
-0.2,
3.0,
-0.4,
5.0,
-0.6000000000000001,
7.0,
-0.8,
9.0,
];
let result = matrix.leaky_relu(alpha);
assert_eq!(result.data, expected);
}
#[test]
fn test_relu_backward() {
let matrix = Matrix {
data: vec![1, -2, 3, -4, 5, -6, 7, -8, 9],
row_size: 3,
col_size: 3,
};
let expected = vec![1, 0, 1, 0, 1, 0, 1, 0, 1];
let result = matrix.relu_backward();
assert_eq!(result.data, expected);
}
#[test]
fn test_gelu() {
let matrix = Matrix {
data: vec![1.0, -2.0, 3.0, -4.0, 5.0, -6.0, 7.0, -8.0, 9.0],
row_size: 3,
col_size: 3,
};
let expected = [
0.841344746,
-0.045500263,
2.9963625,
-0.0003058,
4.9998675,
-0.0000009,
6.999999998,
-0.000000001,
8.9999999,
];
let result = matrix.gelu();
for (res, exp) in result.data.iter().zip(expected.iter()) {
assert!((Into::<f64>::into(*res) - exp).abs() < 1e-2);
}
}
}