etensor_core/backends/cpu/
unary.rs1use crate::tensor::Tensor;
7use crate::buffer::Buffer;
8use crate::device::Device;
9use crate::errors::EtensorResult;
10use rayon::prelude::*;
11
12const RAYON_THRESHOLD_COMPUTE: usize = 131_072; pub fn relu_forward(a: &Tensor) -> EtensorResult<Tensor> {
21 let slice = a.data.as_f32_slice()?;
22
23 let out_vec: Vec<f32> = slice.iter().map(|&x| x.max(0.0)).collect();
24
25 Ok(Tensor::new(
26 Buffer::from_f32_vec(out_vec),
27 a.shape.clone(),
28 Device::Cpu,
29 a.dtype,
30 false, ))
32}
33
34pub fn sigmoid_forward(a: &Tensor) -> EtensorResult<Tensor> {
39 let slice = a.data.as_f32_slice()?;
40
41 let out_vec: Vec<f32> = if slice.len() < RAYON_THRESHOLD_COMPUTE {
42 slice.iter().map(|&x| 1.0 / (1.0 + (-x).exp())).collect()
43 } else {
44 slice.par_iter().map(|&x| 1.0 / (1.0 + (-x).exp())).collect()
45 };
46
47 Ok(Tensor::new(
48 Buffer::from_f32_vec(out_vec),
49 a.shape.clone(),
50 Device::Cpu,
51 a.dtype,
52 false,
53 ))
54}
55
56#[cfg(test)]
60mod tests {
61 use super::*;
62 use crate::shape::Shape;
63 use crate::dtypes::DType;
64
65 fn make_test_tensor(data: Vec<f32>) -> Tensor {
67 let len = data.len();
68 Tensor::new(
69 Buffer::from_f32_vec(data),
70 Shape::new(vec![len]),
71 Device::Cpu,
72 DType::F32,
73 false,
74 )
75 }
76
77 #[test]
78 fn test_cpu_relu() {
79 let a = make_test_tensor(vec![-5.0, 0.0, 3.14, -0.01, 42.0]);
80
81 let c = relu_forward(&a).unwrap();
82 let slice = c.data.as_f32_slice().unwrap();
83
84 assert_eq!(slice, &[0.0, 0.0, 3.14, 0.0, 42.0]);
85 }
86
87 #[test]
88 fn test_cpu_sigmoid() {
89 let a = make_test_tensor(vec![0.0, 100.0, -100.0]);
90
91 let c = sigmoid_forward(&a).unwrap();
92 let slice = c.data.as_f32_slice().unwrap();
93
94 assert_eq!(slice[0], 0.5);
95 assert!(slice[1] > 0.999);
96 assert!(slice[2] < 0.001);
97 }
98}