use crate::tensor::Tensor;
use crate::buffer::Buffer;
use crate::device::Device;
use crate::errors::EtensorResult;
use rayon::prelude::*;
const RAYON_THRESHOLD_COMPUTE: usize = 131_072;
pub fn relu_forward(a: &Tensor) -> EtensorResult<Tensor> {
let slice = a.data.as_f32_slice()?;
let out_vec: Vec<f32> = slice.iter().map(|&x| x.max(0.0)).collect();
Ok(Tensor::new(
Buffer::from_f32_vec(out_vec),
a.shape.clone(),
Device::Cpu,
a.dtype,
false, ))
}
pub fn sigmoid_forward(a: &Tensor) -> EtensorResult<Tensor> {
let slice = a.data.as_f32_slice()?;
let out_vec: Vec<f32> = if slice.len() < RAYON_THRESHOLD_COMPUTE {
slice.iter().map(|&x| 1.0 / (1.0 + (-x).exp())).collect()
} else {
slice.par_iter().map(|&x| 1.0 / (1.0 + (-x).exp())).collect()
};
Ok(Tensor::new(
Buffer::from_f32_vec(out_vec),
a.shape.clone(),
Device::Cpu,
a.dtype,
false,
))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::shape::Shape;
use crate::dtypes::DType;
fn make_test_tensor(data: Vec<f32>) -> Tensor {
let len = data.len();
Tensor::new(
Buffer::from_f32_vec(data),
Shape::new(vec![len]),
Device::Cpu,
DType::F32,
false,
)
}
#[test]
fn test_cpu_relu() {
let a = make_test_tensor(vec![-5.0, 0.0, 3.14, -0.01, 42.0]);
let c = relu_forward(&a).unwrap();
let slice = c.data.as_f32_slice().unwrap();
assert_eq!(slice, &[0.0, 0.0, 3.14, 0.0, 42.0]);
}
#[test]
fn test_cpu_sigmoid() {
let a = make_test_tensor(vec![0.0, 100.0, -100.0]);
let c = sigmoid_forward(&a).unwrap();
let slice = c.data.as_f32_slice().unwrap();
assert_eq!(slice[0], 0.5);
assert!(slice[1] > 0.999);
assert!(slice[2] < 0.001);
}
}