use crate::autograd::Variable;
use crate::nn::Module;
use crate::serialization::core::{Loadable, Saveable, SerializationResult};
use crate::tensor::Tensor;
use num_traits::Float;
use std::collections::HashMap;
use std::fmt::Debug;
pub fn relu<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_data = x.data().read().unwrap().clone();
let output_data = apply_relu(&input_data);
if x.requires_grad() {
let result = Variable::new(output_data, true);
result
} else {
Variable::new(output_data, false)
}
}
pub fn sigmoid<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_data = x.data().read().unwrap().clone();
let output_data = apply_sigmoid(&input_data);
if x.requires_grad() {
Variable::new(output_data, true)
} else {
Variable::new(output_data, false)
}
}
pub fn tanh<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_data = x.data().read().unwrap().clone();
let output_data = apply_tanh(&input_data);
if x.requires_grad() {
Variable::new(output_data, true)
} else {
Variable::new(output_data, false)
}
}
pub fn leaky_relu<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive,
>(
x: &Variable<T>,
alpha: T,
) -> Variable<T> {
let input_data = x.data().read().unwrap().clone();
let output_data = apply_leaky_relu(&input_data, alpha);
if x.requires_grad() {
Variable::new(output_data, true)
} else {
Variable::new(output_data, false)
}
}
pub fn softmax<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_data = x.data().read().unwrap().clone();
let output_data = apply_softmax(&input_data);
if x.requires_grad() {
Variable::new(output_data, true)
} else {
Variable::new(output_data, false)
}
}
fn apply_relu<T: Float + 'static>(tensor: &Tensor<T>) -> Tensor<T> {
let data = tensor.as_array();
let result_data: Vec<T> = data
.iter()
.map(|&x| if x > T::zero() { x } else { T::zero() })
.collect();
Tensor::from_vec(result_data, tensor.shape().to_vec())
}
fn apply_sigmoid<T: Float + 'static>(tensor: &Tensor<T>) -> Tensor<T> {
let data = tensor.as_array();
let result_data: Vec<T> = data
.iter()
.map(|&x| {
let one = T::one();
one / (one + (-x).exp())
})
.collect();
Tensor::from_vec(result_data, tensor.shape().to_vec())
}
fn apply_tanh<T: Float + 'static>(tensor: &Tensor<T>) -> Tensor<T> {
let data = tensor.as_array();
let result_data: Vec<T> = data
.iter()
.map(|&x| {
let exp_x = x.exp();
let exp_neg_x = (-x).exp();
(exp_x - exp_neg_x) / (exp_x + exp_neg_x)
})
.collect();
Tensor::from_vec(result_data, tensor.shape().to_vec())
}
fn apply_leaky_relu<T: Float + 'static>(tensor: &Tensor<T>, alpha: T) -> Tensor<T> {
let data = tensor.as_array();
let result_data: Vec<T> = data
.iter()
.map(|&x| if x > T::zero() { x } else { alpha * x })
.collect();
Tensor::from_vec(result_data, tensor.shape().to_vec())
}
fn apply_softmax<T: Float + 'static>(tensor: &Tensor<T>) -> Tensor<T> {
let data = tensor.as_array();
let max_val = data
.iter()
.copied()
.max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
.unwrap_or(T::zero());
let exp_values: Vec<T> = data.iter().map(|&x| (x - max_val).exp()).collect();
let sum_exp = exp_values.iter().fold(T::zero(), |acc, &x| acc + x);
let result_data: Vec<T> = exp_values.iter().map(|&x| x / sum_exp).collect();
Tensor::from_vec(result_data, tensor.shape().to_vec())
}
pub fn gelu<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_data = x.data().read().unwrap().clone();
let output_data = apply_gelu(&input_data);
if x.requires_grad() {
Variable::new(output_data, true)
} else {
Variable::new(output_data, false)
}
}
pub fn swish<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_data = x.data().read().unwrap().clone();
let output_data = apply_swish(&input_data);
if x.requires_grad() {
Variable::new(output_data, true)
} else {
Variable::new(output_data, false)
}
}
pub fn elu<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive,
>(
x: &Variable<T>,
alpha: T,
) -> Variable<T> {
let input_data = x.data().read().unwrap().clone();
let output_data = apply_elu(&input_data, alpha);
if x.requires_grad() {
Variable::new(output_data, true)
} else {
Variable::new(output_data, false)
}
}
pub fn selu<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_data = x.data().read().unwrap().clone();
let alpha = T::from(1.673_263_242_354_377_284_817_042_991_671_7_f32).unwrap();
let scale = T::from(1.050_700_987_355_480_493_419_334_985_294_6_f32).unwrap();
let output_data = apply_selu(&input_data, alpha, scale);
if x.requires_grad() {
Variable::new(output_data, true)
} else {
Variable::new(output_data, false)
}
}
pub fn mish<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_data = x.data().read().unwrap().clone();
let output_data = apply_mish(&input_data);
if x.requires_grad() {
Variable::new(output_data, true)
} else {
Variable::new(output_data, false)
}
}
pub fn glu<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive + Default,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_tensor = x.data();
let input_guard = input_tensor.read().unwrap();
let input_shape = input_guard.shape();
let input_data = input_guard.as_slice().unwrap();
let last_dim = input_shape[input_shape.len() - 1];
assert_eq!(
last_dim % 2,
0,
"GLU requires even number of elements on last dimension"
);
let half_size = last_dim / 2;
let total_elements = input_shape.iter().product::<usize>();
let batch_size = total_elements / last_dim;
let mut output_shape = input_shape.to_vec();
let last_dim_idx = output_shape.len() - 1;
output_shape[last_dim_idx] = half_size;
let output_size = output_shape.iter().product::<usize>();
let mut output_data = vec![T::default(); output_size];
for batch in 0..batch_size {
let input_offset = batch * last_dim;
let output_offset = batch * half_size;
for i in 0..half_size {
let a = input_data[input_offset + i]; let b = input_data[input_offset + half_size + i];
let sigmoid_b = T::from_f32(1.0).unwrap() / (T::from_f32(1.0).unwrap() + (-b).exp());
output_data[output_offset + i] = a * sigmoid_b;
}
}
let output_tensor = Tensor::from_vec(output_data, output_shape);
Variable::new(output_tensor, x.requires_grad())
}
#[derive(Debug)]
pub struct GLU<T: Float + Send + Sync + ndarray::ScalarOperand + num_traits::FromPrimitive> {
_phantom: std::marker::PhantomData<T>,
}
pub fn swiglu<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive + Default,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_tensor = x.data();
let input_guard = input_tensor.read().unwrap();
let input_shape = input_guard.shape();
let input_data = input_guard.as_slice().unwrap();
let last_dim = input_shape[input_shape.len() - 1];
assert_eq!(
last_dim % 2,
0,
"SwiGLU requires even number of elements on last dimension"
);
let half_size = last_dim / 2;
let total_elements = input_shape.iter().product::<usize>();
let batch_size = total_elements / last_dim;
let mut output_shape = input_shape.to_vec();
let last_idx = output_shape.len() - 1;
output_shape[last_idx] = half_size;
let mut output_data = vec![T::default(); batch_size * half_size];
for i in 0..batch_size {
let offset = i * last_dim;
for j in 0..half_size {
let a = input_data[offset + j];
let b = input_data[offset + j + half_size];
let swish_b =
b * (T::from_f32(1.0).unwrap() / (T::from_f32(1.0).unwrap() + (-b).exp()));
output_data[i * half_size + j] = a * swish_b;
}
}
let output_tensor = Tensor::from_vec(output_data, output_shape);
Variable::new(output_tensor, x.requires_grad())
}
pub fn geglu<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive + Default,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_tensor = x.data();
let input_guard = input_tensor.read().unwrap();
let input_shape = input_guard.shape();
let input_data = input_guard.as_slice().unwrap();
let last_dim = input_shape[input_shape.len() - 1];
assert_eq!(
last_dim % 2,
0,
"GeGLU requires even number of elements on last dimension"
);
let half_size = last_dim / 2;
let total_elements = input_shape.iter().product::<usize>();
let batch_size = total_elements / last_dim;
let mut output_shape = input_shape.to_vec();
let last_idx = output_shape.len() - 1;
output_shape[last_idx] = half_size;
let mut output_data = vec![T::default(); batch_size * half_size];
for i in 0..batch_size {
let offset = i * last_dim;
for j in 0..half_size {
let a = input_data[offset + j];
let b = input_data[offset + j + half_size];
let gelu_b = b
* T::from_f32(0.5).unwrap()
* (T::from_f32(1.0).unwrap()
+ (b * T::from_f32(0.7978845608).unwrap()
* (T::from_f32(1.0).unwrap() + T::from_f32(0.044715).unwrap() * b * b))
.tanh());
output_data[i * half_size + j] = a * gelu_b;
}
}
let output_tensor = Tensor::from_vec(output_data, output_shape);
Variable::new(output_tensor, x.requires_grad())
}
pub fn reglu<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive + Default,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_tensor = x.data();
let input_guard = input_tensor.read().unwrap();
let input_shape = input_guard.shape();
let input_data = input_guard.as_slice().unwrap();
let last_dim = input_shape[input_shape.len() - 1];
assert_eq!(
last_dim % 2,
0,
"ReGLU requires even number of elements on last dimension"
);
let half_size = last_dim / 2;
let total_elements = input_shape.iter().product::<usize>();
let batch_size = total_elements / last_dim;
let mut output_shape = input_shape.to_vec();
let last_idx = output_shape.len() - 1;
output_shape[last_idx] = half_size;
let mut output_data = vec![T::default(); batch_size * half_size];
for i in 0..batch_size {
let offset = i * last_dim;
for j in 0..half_size {
let a = input_data[offset + j];
let b = input_data[offset + j + half_size];
let relu_b = if b > T::zero() { b } else { T::zero() };
output_data[i * half_size + j] = a * relu_b;
}
}
let output_tensor = Tensor::from_vec(output_data, output_shape);
Variable::new(output_tensor, x.requires_grad())
}
impl<
T: Float
+ Send
+ Sync
+ 'static
+ Debug
+ ndarray::ScalarOperand
+ num_traits::FromPrimitive
+ Default,
> GLU<T>
{
pub fn new() -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
impl<
T: Float
+ Send
+ Sync
+ 'static
+ Debug
+ ndarray::ScalarOperand
+ num_traits::FromPrimitive
+ Default,
> Module<T> for GLU<T>
{
fn forward(&self, input: &Variable<T>) -> Variable<T> {
glu(input)
}
fn parameters(&self) -> Vec<Variable<T>> {
Vec::new()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
pub fn hardswish<
T: Float + Send + Sync + 'static + ndarray::ScalarOperand + num_traits::FromPrimitive,
>(
x: &Variable<T>,
) -> Variable<T> {
let input_data = x.data().read().unwrap().clone();
let output_data = apply_hardswish(&input_data);
if x.requires_grad() {
Variable::new(output_data, true)
} else {
Variable::new(output_data, false)
}
}
fn apply_gelu<T: Float + 'static>(tensor: &Tensor<T>) -> Tensor<T> {
let data = tensor.as_array();
let result_data: Vec<T> = data
.iter()
.map(|&x| {
let sqrt_2_over_pi = T::from(0.7978845608028654f32).unwrap(); let coeff = T::from(0.044715f32).unwrap();
let half = T::from(0.5f32).unwrap();
let one = T::one();
let x_cubed = x * x * x;
let inner = sqrt_2_over_pi * (x + coeff * x_cubed);
let tanh_val = {
let exp_2x = (inner + inner).exp();
(exp_2x - one) / (exp_2x + one)
};
half * x * (one + tanh_val)
})
.collect();
Tensor::from_vec(result_data, tensor.shape().to_vec())
}
fn apply_swish<T: Float + 'static>(tensor: &Tensor<T>) -> Tensor<T> {
let data = tensor.as_array();
let result_data: Vec<T> = data
.iter()
.map(|&x| {
let sigmoid_x = T::one() / (T::one() + (-x).exp());
x * sigmoid_x
})
.collect();
Tensor::from_vec(result_data, tensor.shape().to_vec())
}
fn apply_elu<T: Float + 'static>(tensor: &Tensor<T>, alpha: T) -> Tensor<T> {
let data = tensor.as_array();
let result_data: Vec<T> = data
.iter()
.map(|&x| {
if x > T::zero() {
x
} else {
alpha * (x.exp() - T::one())
}
})
.collect();
Tensor::from_vec(result_data, tensor.shape().to_vec())
}
fn apply_selu<T: Float + 'static>(tensor: &Tensor<T>, alpha: T, scale: T) -> Tensor<T> {
let data = tensor.as_array();
let result_data: Vec<T> = data
.iter()
.map(|&x| {
if x > T::zero() {
scale * x
} else {
scale * alpha * (x.exp() - T::one())
}
})
.collect();
Tensor::from_vec(result_data, tensor.shape().to_vec())
}
fn apply_mish<T: Float + 'static>(tensor: &Tensor<T>) -> Tensor<T> {
let data = tensor.as_array();
let result_data: Vec<T> = data
.iter()
.map(|&x| {
let softplus = (T::one() + x.exp()).ln();
let tanh_softplus = {
let exp_2x = (softplus + softplus).exp();
(exp_2x - T::one()) / (exp_2x + T::one())
};
x * tanh_softplus
})
.collect();
Tensor::from_vec(result_data, tensor.shape().to_vec())
}
fn apply_hardswish<T: Float + 'static>(tensor: &Tensor<T>) -> Tensor<T> {
let data = tensor.as_array();
let result_data: Vec<T> = data
.iter()
.map(|&x| {
let three = T::from(3.0f32).unwrap();
let six = T::from(6.0f32).unwrap();
let relu6_val = (x + three).max(T::zero()).min(six);
x * relu6_val / six
})
.collect();
Tensor::from_vec(result_data, tensor.shape().to_vec())
}
#[derive(Debug, Clone)]
pub struct ReLU<T: Float + Send + Sync + 'static + Debug> {
_phantom: std::marker::PhantomData<T>,
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> ReLU<T>
{
pub fn new() -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> Module<T> for ReLU<T>
{
fn forward(&self, input: &Variable<T>) -> Variable<T> {
relu(input)
}
fn parameters(&self) -> Vec<Variable<T>> {
Vec::new()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn train(&mut self) {
}
fn eval(&mut self) {
}
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> Saveable for ReLU<T>
{
fn save_binary(&self) -> SerializationResult<Vec<u8>> {
Ok(vec![0u8])
}
fn type_id(&self) -> &'static str {
"nn.ReLU"
}
fn metadata(&self) -> HashMap<String, String> {
let mut meta = HashMap::new();
meta.insert("activation_type".to_string(), "ReLU".to_string());
meta.insert("stateless".to_string(), "true".to_string());
meta
}
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> Loadable for ReLU<T>
{
fn load_binary(_data: &[u8]) -> SerializationResult<Self> {
Ok(ReLU::new())
}
fn expected_type_id() -> &'static str {
"nn.ReLU"
}
}
#[derive(Debug, Clone)]
pub struct Softmax<T: Float + Send + Sync + 'static + Debug> {
_phantom: std::marker::PhantomData<T>,
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> Softmax<T>
{
pub fn new(_dim: i32) -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> Module<T> for Softmax<T>
{
fn forward(&self, input: &Variable<T>) -> Variable<T> {
softmax(input)
}
fn parameters(&self) -> Vec<Variable<T>> {
Vec::new()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn train(&mut self) {
}
fn eval(&mut self) {
}
}
#[derive(Debug, Clone)]
pub struct GELU<T: Float + Send + Sync + 'static + Debug> {
_phantom: std::marker::PhantomData<T>,
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> GELU<T>
{
pub fn new() -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> Module<T> for GELU<T>
{
fn forward(&self, input: &Variable<T>) -> Variable<T> {
gelu(input)
}
fn parameters(&self) -> Vec<Variable<T>> {
Vec::new()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn train(&mut self) {
}
fn eval(&mut self) {
}
}
#[derive(Debug, Clone)]
pub struct Swish<T: Float + Send + Sync + 'static + Debug> {
_phantom: std::marker::PhantomData<T>,
}
#[derive(Debug, Clone)]
pub struct Tanh<T: Float + Send + Sync + 'static + Debug> {
_phantom: std::marker::PhantomData<T>,
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> Swish<T>
{
pub fn new() -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> Tanh<T>
{
pub fn new() -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> Module<T> for Swish<T>
{
fn forward(&self, input: &Variable<T>) -> Variable<T> {
swish(input)
}
fn parameters(&self) -> Vec<Variable<T>> {
Vec::new()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn train(&mut self) {
}
fn eval(&mut self) {
}
}
impl<
T: Float + Send + Sync + 'static + Debug + ndarray::ScalarOperand + num_traits::FromPrimitive,
> Module<T> for Tanh<T>
{
fn forward(&self, input: &Variable<T>) -> Variable<T> {
tanh(input)
}
fn parameters(&self) -> Vec<Variable<T>> {
Vec::new()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn train(&mut self) {
}
fn eval(&mut self) {
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tensor::Tensor;
use approx::assert_abs_diff_eq;
#[test]
fn test_relu() {
let input = Variable::new(
Tensor::from_vec(vec![-2.0, -1.0, 0.0, 1.0, 2.0], vec![5]),
false,
);
let output = relu(&input);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
let expected = [0.0, 0.0, 0.0, 1.0, 2.0];
for (actual, expected) in result_data.as_array().iter().zip(expected.iter()) {
assert_abs_diff_eq!(*actual, *expected, epsilon = 1e-6);
}
}
#[test]
fn test_sigmoid() {
let input = Variable::new(Tensor::from_vec(vec![0.0], vec![1]), false);
let output = sigmoid(&input);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
assert_abs_diff_eq!(
result_data.as_array().iter().next().unwrap(),
&0.5,
epsilon = 1e-6
);
}
#[test]
fn test_tanh() {
let input = Variable::new(Tensor::from_vec(vec![0.0], vec![1]), false);
let output = tanh(&input);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
assert_abs_diff_eq!(
result_data.as_array().iter().next().unwrap(),
&0.0,
epsilon = 1e-6
);
}
#[test]
fn test_leaky_relu() {
let input = Variable::new(Tensor::from_vec(vec![-1.0, 0.0, 1.0], vec![3]), false);
let output = leaky_relu(&input, 0.1);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
let expected = [-0.1, 0.0, 1.0];
for (actual, expected) in result_data.as_array().iter().zip(expected.iter()) {
assert_abs_diff_eq!(*actual, *expected, epsilon = 1e-6);
}
}
#[test]
fn test_softmax() {
let input = Variable::new(Tensor::from_vec(vec![1.0, 2.0, 3.0], vec![3]), false);
let output = softmax(&input);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
let sum: f32 = result_data.as_array().iter().sum();
assert_abs_diff_eq!(sum, 1.0, epsilon = 1e-6);
for &val in result_data.as_array().iter() {
assert!(val > 0.0);
}
}
#[test]
fn test_relu_with_gradients() {
let input = Variable::new(Tensor::from_vec(vec![-1.0, 0.0, 1.0], vec![3]), true);
let output = relu(&input);
assert!(output.requires_grad());
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
let expected = [0.0, 0.0, 1.0];
for (actual, expected) in result_data.as_array().iter().zip(expected.iter()) {
assert_abs_diff_eq!(*actual, *expected, epsilon = 1e-6);
}
}
#[test]
fn test_gelu() {
let input = Variable::new(Tensor::from_vec(vec![0.0, 1.0, -1.0], vec![3]), false);
let output = gelu(&input);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
assert_abs_diff_eq!(result_data.as_array()[0], 0.0, epsilon = 1e-3);
assert!(result_data.as_array()[1] > 0.8);
assert!(result_data.as_array()[2] < 0.0);
}
#[test]
fn test_swish() {
let input = Variable::new(Tensor::from_vec(vec![0.0, 1.0, -1.0], vec![3]), false);
let output = swish(&input);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
assert_abs_diff_eq!(result_data.as_array()[0], 0.0, epsilon = 1e-6);
assert!(result_data.as_array()[1] > 0.7);
assert!(result_data.as_array()[2] < 0.0);
}
#[test]
fn test_elu() {
let input = Variable::new(Tensor::from_vec(vec![-1.0, 0.0, 1.0], vec![3]), false);
let output = elu(&input, 1.0);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
assert!(result_data.as_array()[0] < 0.0 && result_data.as_array()[0] > -1.0);
assert_abs_diff_eq!(result_data.as_array()[1], 0.0, epsilon = 1e-6);
assert_abs_diff_eq!(result_data.as_array()[2], 1.0, epsilon = 1e-6);
}
#[test]
fn test_selu() {
let input = Variable::new(Tensor::from_vec(vec![0.0, 1.0], vec![2]), false);
let output = selu(&input);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
assert_abs_diff_eq!(result_data.as_array()[0], 0.0, epsilon = 1e-6);
assert!(result_data.as_array()[1] > 1.0); }
#[test]
fn test_mish() {
let input = Variable::new(Tensor::from_vec(vec![0.0, 1.0, -1.0], vec![3]), false);
let output = mish(&input);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
assert_abs_diff_eq!(result_data.as_array()[0], 0.0, epsilon = 1e-3);
assert!(result_data.as_array()[1] > 0.8);
assert!(result_data.as_array()[2] < 0.0);
}
#[test]
fn test_hardswish() {
let input = Variable::new(Tensor::from_vec(vec![-3.0, 0.0, 3.0, 6.0], vec![4]), false);
let output = hardswish(&input);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
assert_abs_diff_eq!(result_data.as_array()[0], 0.0, epsilon = 1e-6);
assert_abs_diff_eq!(result_data.as_array()[1], 0.0, epsilon = 1e-6);
assert_abs_diff_eq!(result_data.as_array()[2], 3.0, epsilon = 1e-6);
assert_abs_diff_eq!(result_data.as_array()[3], 6.0, epsilon = 1e-6);
}
#[test]
fn test_glu() {
let input = Variable::new(Tensor::from_vec(vec![1.0, 2.0, 0.5, -1.0], vec![4]), false);
let output = glu(&input);
let result_binding = output.data();
let result_data = result_binding.read().unwrap();
assert_eq!(result_data.shape(), &[2]); assert!(result_data.as_array()[0] > 0.5); assert!(result_data.as_array()[1] > 0.0 && result_data.as_array()[1] < 1.0);
}
}