cubek-pool 0.3.0-pre.2

CubeK: Pool
Documentation
use crate::{definition::AdaptiveAvgPoolOptions, eval::cpu_reference::decode_index};
use cubek_test_utils::HostData;

pub fn run_adaptive_avg_pool_backward<const N: usize>(
    grad_output: &HostData,
    _opts: &AdaptiveAvgPoolOptions<N>,
    grad_input_dims: &[usize],
    grad_output_dims: &[usize],
    grad_input_strides: &[usize],
) -> Vec<f32> {
    let total: usize = grad_input_dims.iter().product();
    let mut grad_input = vec![0.0; total];

    if N != 2 {
        return grad_input;
    }

    let out_h = grad_input_dims[1];
    let out_w = grad_input_dims[2];
    let grad_h = grad_output_dims[1];
    let grad_w = grad_output_dims[2];

    for (i, grad_val) in grad_input.iter_mut().enumerate().take(total) {
        let coords = decode_index(i, grad_input_dims, grad_input_strides);
        let batch = coords[0];
        let ih = coords[1];
        let iw = coords[2];
        let channel = coords[3];

        let oh_start = start_index(ih, out_h, grad_h);
        let oh_end = end_index(ih, out_h, grad_h);
        let ow_start = start_index(iw, out_w, grad_w);
        let ow_end = end_index(iw, out_w, grad_w);

        let mut grad_acc = 0.0f32;

        for oh in oh_start..oh_end {
            let ih_start = start_index(oh, grad_h, out_h);
            let ih_end = end_index(oh, grad_h, out_h);

            if ih >= ih_start && ih < ih_end {
                for ow in ow_start..ow_end {
                    let iw_start = start_index(ow, grad_w, out_w);
                    let iw_end = end_index(ow, grad_w, out_w);

                    if iw >= iw_start && iw < iw_end {
                        let count = (ih_end - ih_start) * (iw_end - iw_start);
                        let out_coords = vec![batch, oh, ow, channel];
                        grad_acc += grad_output.get_f32(&out_coords) / count as f32;
                    }
                }
            }
        }

        *grad_val = grad_acc;
    }

    grad_input
}

fn start_index(output_size_index: usize, output_size: usize, input_size: usize) -> usize {
    (output_size_index * input_size) / output_size
}

fn end_index(output_size_index: usize, output_size: usize, input_size: usize) -> usize {
    let index = (output_size_index + 1) * input_size;
    let index = index.div_ceil(output_size);

    if input_size < index {
        input_size
    } else {
        index
    }
}