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