use crate::{Shape, Tape, Tensor};
use super::max_pool;
#[test]
fn max_pool_takes_window_maxima() {
let tape: Tape<f64> = Tape::new();
let input = tape.leaf(Tensor::new(
[1, 1, 4, 4],
(1..=16).map(|v| v as f64).collect::<Vec<_>>(),
));
let pooled = max_pool(input, 2, 2);
assert_eq!(pooled.shape(), Shape::new([1, 1, 2, 2]));
let pooled = pooled.symbol();
let network = tape.into_network();
let run = network.forward(&network.parameters(), []);
assert_eq!(run.of(pooled).to_vec(), &[6.0, 8.0, 14.0, 16.0]);
}
#[test]
fn max_pool_routes_the_gradient_to_the_maximum() {
let tape: Tape<f64> = Tape::new();
let input = tape.leaf(Tensor::new(
[1, 1, 4, 4],
(1..=16).map(|v| v as f64).collect::<Vec<_>>(),
));
let pooled = max_pool(input, 2, 2);
let loss = pooled.sum();
let (loss, input) = (loss.symbol(), input.symbol());
let network = tape.into_network();
let run = network.forward(&network.parameters(), []);
let gradients = run.backward(loss);
let mut expected = vec![0.0; 16];
for position in [5, 7, 13, 15] {
expected[position] = 1.0;
}
assert_eq!(gradients.of(input).to_vec(), expected);
}
#[test]
fn max_pool_ties_route_to_the_earliest_lane() {
let tape: Tape<f64> = Tape::new();
let input = tape.leaf(Tensor::filled([1, 1, 2, 2], 5.0_f64));
let pooled = max_pool(input, 2, 2);
let loss = pooled.sum();
let (pooled, loss, input) = (pooled.symbol(), loss.symbol(), input.symbol());
let network = tape.into_network();
let run = network.forward(&network.parameters(), []);
assert_eq!(run.of(pooled).to_vec(), &[5.0]);
let gradients = run.backward(loss);
assert_eq!(gradients.of(input).to_vec(), &[1.0, 0.0, 0.0, 0.0]);
}
#[test]
#[should_panic(expected = "must be rank 4")]
fn pooling_rejects_non_image_input() {
let tape: Tape<f64> = Tape::new();
let input = tape.leaf(Tensor::filled([1, 4, 4], 0.0_f64));
max_pool(input, 2, 2);
}