use crate::error::Error;
use crate::neural_network::layers::ParamCounts;
use crate::neural_network::layers::pooling::pooling_engine::{
PoolKind, global_pool_backward, global_pool_forward,
};
use crate::neural_network::layers::pooling::{
layer_base_functions_pooling, layer_functions_global_pooling,
};
use crate::neural_network::traits::{LayerBase, UnaryLayer};
use crate::neural_network::{Ctx, Shape, Tensor};
#[derive(Debug)]
pub struct GlobalMaxPooling3D {
built: Option<Shape>,
}
impl GlobalMaxPooling3D {
pub fn new() -> Self {
GlobalMaxPooling3D { built: None }
}
}
impl Default for GlobalMaxPooling3D {
fn default() -> Self {
Self::new()
}
}
struct GlobalMaxPooling3DCache {
input_shape: Vec<usize>,
argmax: Option<Vec<usize>>,
}
impl LayerBase for GlobalMaxPooling3D {
fn layer_type(&self) -> &str {
"GlobalMaxPooling3D"
}
layer_base_functions_pooling!();
}
impl UnaryLayer for GlobalMaxPooling3D {
fn forward(&self, input: &Tensor, ctx: &mut Ctx) -> Result<Tensor, Error> {
if input.ndim() != 5 {
return Err(Error::invalid_input("input tensor is not 5D"));
}
let (output, argmax) = global_pool_forward(input, PoolKind::Max);
if ctx.is_training() {
ctx.push_cache(
"GlobalMaxPooling3D",
GlobalMaxPooling3DCache {
input_shape: input.shape().to_vec(),
argmax,
},
);
}
Ok(output)
}
fn backward(&self, grad_output: &Tensor, ctx: &mut Ctx) -> Result<Tensor, Error> {
let cache: GlobalMaxPooling3DCache = ctx.pop_cache("GlobalMaxPooling3D")?;
Ok(global_pool_backward(
grad_output,
&cache.input_shape,
PoolKind::Max,
cache.argmax.as_deref(),
))
}
layer_functions_global_pooling!("GlobalMaxPooling3D", 5);
}