burn_cubecl/kernel/interpolate/
base.rs1#[cfg(feature = "autotune")]
2use crate::kernel::interpolate::interpolate_autotune;
3use crate::{
4 kernel::into_contiguous,
5 ops::{numeric::empty_device_dtype, permute_nchw_to_nhwc, permute_nhwc_to_nchw},
6 tensor::CubeTensor,
7};
8use burn_backend::cubecl::dtype_to_storage_type;
9use burn_backend::{Shape, TensorMetadata, ops::InterpolateMode, ops::InterpolateOptions};
10use cubek::interpolate::{
11 InterpolateStrategy as CubekInterpolateStrategy,
12 definition::{
13 InterpolateError, InterpolateMode as CubekInterpolateMode,
14 InterpolateOptions as CubekInterpolateOptions, NearestMode as CubekNearestMode,
15 },
16 interpolate as cubek_interpolate, interpolate_backward as cubek_interpolate_backward,
17};
18
19#[derive(Debug)]
20pub enum InterpolateStrategy {
22 Specific(CubekInterpolateStrategy),
26
27 #[cfg(feature = "autotune")]
29 Autotune,
30}
31
32impl Default for InterpolateStrategy {
33 fn default() -> Self {
34 #[cfg(feature = "autotune")]
36 return InterpolateStrategy::Autotune;
37
38 #[cfg(not(feature = "autotune"))]
41 InterpolateStrategy::Specific(CubekInterpolateStrategy::MaximizeThroughput)
42 }
43}
44
45pub fn interpolate(
49 input: CubeTensor,
50 output_size: [usize; 2],
51 options: InterpolateOptions,
52 strategy: InterpolateStrategy,
53) -> Result<CubeTensor, InterpolateError> {
54 match strategy {
55 InterpolateStrategy::Specific(strategy) => {
56 execute_interpolate(input, output_size, options, strategy)
57 }
58 #[cfg(feature = "autotune")]
59 InterpolateStrategy::Autotune => Ok(interpolate_autotune(input, output_size, options)),
60 }
61}
62
63pub fn execute_interpolate(
66 input: CubeTensor,
67 output_size: [usize; 2],
68 options: InterpolateOptions,
69 strategy: CubekInterpolateStrategy,
70) -> Result<CubeTensor, InterpolateError> {
71 let [batch_size, channels, _, _] = input.meta.shape().dims();
72 let [out_height, out_width] = output_size;
73
74 let input = into_contiguous(permute_nchw_to_nhwc(input));
75
76 let shape_out = Shape::new([batch_size, out_height, out_width, channels]);
77 let output = empty_device_dtype(
78 input.client.clone(),
79 input.device.clone(),
80 shape_out,
81 input.dtype,
82 );
83
84 cubek_interpolate(
85 &input.client.clone(),
86 input.clone().binding(),
87 output.clone().binding(),
88 map_options(options.clone()),
89 strategy,
90 dtype_to_storage_type(input.dtype),
91 )?;
92
93 Ok(permute_nhwc_to_nchw(output))
94}
95
96pub fn interpolate_backward(
100 input: CubeTensor,
101 out_grad: CubeTensor,
102 _output_size: [usize; 2],
103 options: InterpolateOptions,
104) -> CubeTensor {
105 let input = permute_nchw_to_nhwc(input);
106 let out_grad = permute_nchw_to_nhwc(out_grad);
107
108 let output_shape = input.shape();
109 let output = empty_device_dtype(
110 input.client.clone(),
111 input.device.clone(),
112 output_shape,
113 input.dtype,
114 );
115
116 cubek_interpolate_backward(
117 &input.client.clone(),
118 input.clone().binding(),
119 out_grad.binding(),
120 output.clone().binding(),
121 map_options(options.clone()),
122 dtype_to_storage_type(input.dtype),
123 )
124 .unwrap_or_else(|e| {
125 panic!(
126 "interpolate_backward kernel failed (device={0:?}, dtype={1:?}, options={2:?}): {3}",
127 input.device, input.dtype, options, e
128 )
129 });
130
131 permute_nhwc_to_nchw(output)
132}
133
134pub(crate) fn map_mode(mode: InterpolateMode) -> CubekInterpolateMode {
135 match mode {
136 InterpolateMode::Nearest => CubekInterpolateMode::Nearest(CubekNearestMode::Floor),
137 InterpolateMode::NearestExact => CubekInterpolateMode::Nearest(CubekNearestMode::Exact),
138 InterpolateMode::Bilinear => CubekInterpolateMode::Bilinear,
139 InterpolateMode::Bicubic => CubekInterpolateMode::Bicubic,
140 InterpolateMode::Lanczos3 => CubekInterpolateMode::Lanczos3,
141 }
142}
143
144pub(crate) fn map_options(options: InterpolateOptions) -> CubekInterpolateOptions {
145 CubekInterpolateOptions {
146 mode: map_mode(options.mode),
147 align_corners: options.align_corners,
148 }
149}