use crate::error::Error;
use crate::neural_network::Tensor;
use crate::neural_network::layers::TrainingParameters;
use crate::neural_network::layers::convolution::PaddingType;
use crate::neural_network::layers::layer_weight::LayerWeight;
use crate::neural_network::layers::pooling::layer_functions_1d_pooling;
use crate::neural_network::layers::pooling::pooling_engine::{
PoolKind, windowed_pool_backward, windowed_pool_forward,
};
use crate::neural_network::layers::pooling::validation::{
validate_all_dims_positive, validate_input_shape_dims, validate_pool_size_1d,
validate_stride_1d,
};
use crate::neural_network::layers::shape_helpers::calculate_output_shape_1d_pooling;
use crate::neural_network::traits::Layer;
#[derive(Debug)]
pub struct AveragePooling1D {
pool_size: usize,
stride: usize,
input_shape: Vec<usize>,
padding: PaddingType,
forward_input_shape: Option<Vec<usize>>,
}
impl AveragePooling1D {
pub fn new(pool_size: usize, input_shape: Vec<usize>) -> Result<Self, Error> {
validate_input_shape_dims(&input_shape, 3, "AveragePooling1D")?;
validate_all_dims_positive(&input_shape)?;
validate_pool_size_1d(pool_size, input_shape[2])?;
Ok(AveragePooling1D {
pool_size,
stride: pool_size,
input_shape,
padding: PaddingType::Valid,
forward_input_shape: None,
})
}
pub fn with_stride(mut self, stride: usize) -> Result<Self, Error> {
validate_stride_1d(stride)?;
self.stride = stride;
Ok(self)
}
pub fn with_padding(mut self, padding: PaddingType) -> Self {
self.padding = padding;
self
}
}
impl Layer for AveragePooling1D {
fn forward(&mut self, input: &Tensor) -> Result<Tensor, Error> {
if input.ndim() != 3 {
return Err(Error::invalid_input("input tensor is not 3D"));
}
self.forward_input_shape = Some(input.shape().to_vec());
let (output, _) = windowed_pool_forward(
input,
&[self.pool_size],
&[self.stride],
PoolKind::Average,
self.padding,
);
Ok(output)
}
fn predict(&self, input: &Tensor) -> Result<Tensor, Error> {
if input.ndim() != 3 {
return Err(Error::invalid_input("input tensor is not 3D"));
}
let (output, _) = windowed_pool_forward(
input,
&[self.pool_size],
&[self.stride],
PoolKind::Average,
self.padding,
);
Ok(output)
}
fn backward(&mut self, grad_output: &Tensor) -> Result<Tensor, Error> {
let input_shape = self
.forward_input_shape
.as_ref()
.ok_or_else(|| Error::forward_pass_not_run("AveragePooling1D"))?;
Ok(windowed_pool_backward(
grad_output,
input_shape,
&[self.pool_size],
&[self.stride],
PoolKind::Average,
None,
self.padding,
))
}
fn layer_type(&self) -> &str {
"AveragePooling1D"
}
layer_functions_1d_pooling!();
}