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 LeakyReLU {
pub(super) negative_slope: f32,
output_cache: Option<Tensor>,
}
impl LeakyReLU {
pub fn new(negative_slope: f32) -> Result<Self, Error> {
Activation::LeakyReLU { negative_slope }.validate()?;
Ok(LeakyReLU {
negative_slope,
output_cache: None,
})
}
}
impl Default for LeakyReLU {
fn default() -> Self {
LeakyReLU {
negative_slope: 0.3,
output_cache: None,
}
}
}
impl Layer for LeakyReLU {
fn forward(&mut self, input: &Tensor) -> Result<Tensor, Error> {
if input.is_empty() {
return Err(Error::empty_input("input tensor"));
}
let output = Activation::LeakyReLU {
negative_slope: self.negative_slope,
}
.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::LeakyReLU {
negative_slope: self.negative_slope,
}
.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::LeakyReLU {
negative_slope: self.negative_slope,
}
.backward(output, grad_output)
} else {
Err(Error::forward_pass_not_run("LeakyReLU"))
}
}
fn layer_type(&self) -> &str {
"LeakyReLU"
}
fn output_shape(&self) -> String {
format_output_shape(&self.output_cache)
}
no_trainable_parameters_layer_functions!();
}