use cubecl::{calculate_cube_count_elemwise, prelude::*};
use crate::{tensor::JitTensor, FloatElement, JitRuntime};
#[cube(launch_unchecked)]
fn interpolate_nearest_backward_kernel<F: Float>(grad: &Tensor<F>, output: &mut Tensor<F>) {
if ABSOLUTE_POS >= output.len() {
return;
}
let out_h = output.shape(2);
let out_w = output.shape(3);
let grad_h = grad.shape(2);
let grad_w = grad.shape(3);
let batch = ABSOLUTE_POS / output.stride(0) % output.shape(0);
let channel = ABSOLUTE_POS / output.stride(1) % output.shape(1);
let oh = ABSOLUTE_POS / output.stride(2) % out_h;
let ow = ABSOLUTE_POS / output.stride(3) % out_w;
let gh_start = start_index::<F>(oh, grad_h, out_h);
let gh_end = end_index::<F>(oh, grad_h, out_h);
let gw_start = start_index::<F>(ow, grad_w, out_w);
let gw_end = end_index::<F>(ow, grad_w, out_w);
let index_grad_base = batch * grad.stride(0) + channel * grad.stride(1);
let mut sum = F::new(0.0);
for gh in gh_start..gh_end {
for gw in gw_start..gw_end {
let index_grad = index_grad_base + gh * grad.stride(2) + gw * grad.stride(3);
sum += grad[index_grad];
}
}
output[ABSOLUTE_POS] = sum;
}
#[cube]
fn start_index<F: Float>(input_index: u32, output_size: u32, input_size: u32) -> u32 {
let numerator = F::cast_from(input_index * output_size);
let div: F = Ceil::ceil(numerator / F::cast_from(input_size));
u32::cast_from(div)
}
#[cube]
fn end_index<F: Float>(input_index: u32, output_size: u32, input_size: u32) -> u32 {
let numerator = F::cast_from((input_index + 1) * output_size);
let div: F = Ceil::ceil(numerator / F::cast_from(input_size));
let index = u32::cast_from(div);
Min::min(output_size, index)
}
pub(crate) fn interpolate_nearest_backward_launch<R: JitRuntime, E: FloatElement>(
out_grad: JitTensor<R>,
output: JitTensor<R>,
) -> JitTensor<R> {
let cube_dim = CubeDim::default();
let cube_count = calculate_cube_count_elemwise(output.shape.num_elements(), cube_dim);
unsafe {
interpolate_nearest_backward_kernel::launch_unchecked::<E, R>(
&out_grad.client,
cube_count,
cube_dim,
out_grad.as_tensor_arg::<E>(1),
output.as_tensor_arg::<E>(1),
)
};
output
}