use crate::error::Error;
use crate::neural_network::Tensor;
use crate::neural_network::layers::TrainingParameters;
use crate::neural_network::layers::activation::{Activation, format_output_shape};
use crate::neural_network::layers::layer_weight::LayerWeight;
use crate::neural_network::layers::no_trainable_parameters_layer_functions;
use crate::neural_network::traits::Layer;
#[derive(Debug)]
pub struct ELU {
pub(super) alpha: f32,
output_cache: Option<Tensor>,
}
impl ELU {
pub fn new(alpha: f32) -> Result<Self, Error> {
Activation::ELU { alpha }.validate()?;
Ok(ELU {
alpha,
output_cache: None,
})
}
}
impl Default for ELU {
fn default() -> Self {
ELU {
alpha: 1.0,
output_cache: None,
}
}
}
impl Layer for ELU {
fn forward(&mut self, input: &Tensor) -> Result<Tensor, Error> {
if input.is_empty() {
return Err(Error::empty_input("input tensor"));
}
let output = Activation::ELU { alpha: self.alpha }.forward(input)?;
self.output_cache = Some(output.clone());
Ok(output)
}
fn predict(&self, input: &Tensor) -> Result<Tensor, Error> {
if input.is_empty() {
return Err(Error::empty_input("input tensor"));
}
Activation::ELU { alpha: self.alpha }.forward(input)
}
fn backward(&mut self, grad_output: &Tensor) -> Result<Tensor, Error> {
if let Some(output) = &self.output_cache {
if grad_output.shape() != output.shape() {
return Err(Error::shape_mismatch(output.shape(), grad_output.shape()));
}
Activation::ELU { alpha: self.alpha }.backward(output, grad_output)
} else {
Err(Error::forward_pass_not_run("ELU"))
}
}
fn layer_type(&self) -> &str {
"ELU"
}
fn output_shape(&self) -> String {
format_output_shape(&self.output_cache)
}
no_trainable_parameters_layer_functions!();
}