Skip to main content

cubek_convolution/kernels/backward_data/
launch.rs

1use crate::{
2    backward_data::args::ConcreteArgs,
3    components::{ConvSetupError, ConvolutionOperation, ConvolutionProblem, Dimensionality},
4    kernels::backward_data::selector::launch_kernel_concrete,
5    launch::ConvolutionArgs,
6    routines::Routine,
7};
8use cubecl::{client::Client, prelude::*};
9use cubek_matmul::{
10    definition::{AvailableVectorSizes, MatmulElems, MatmulSetupError},
11    routine::BlueprintStrategy,
12};
13use cubek_std::{InputBinding, MatrixLayout};
14
15/// Backward-data dispatch helper.
16///
17/// Called by `cubek_convolution::launch_ref` after the routine and
18/// blueprint-strategy have been resolved. Backward-data does not currently
19/// support the TMA reading strategy: requesting it here returns a setup error.
20#[allow(clippy::result_large_err, clippy::too_many_arguments)]
21pub(crate) fn launch_internal<const N_SPATIAL: usize, Rt: Routine>(
22    client: &Client,
23    out_grad: InputBinding,
24    weights: InputBinding,
25    in_grad: TensorBinding,
26    args: ConvolutionArgs<N_SPATIAL>,
27    blueprint_strategy: &BlueprintStrategy<Rt::MatmulRoutine>,
28    dtypes: MatmulElems,
29) -> Result<(), ConvSetupError>
30where
31    Rt::Args: ConcreteArgs<Rt::MatmulRoutine>,
32{
33    let ConvolutionArgs {
34        stride,
35        padding,
36        dilation,
37    } = args;
38
39    let dimensionality = match N_SPATIAL {
40        1 => Dimensionality::Dim1,
41        2 => Dimensionality::Dim2,
42        3 => Dimensionality::Dim3,
43        other => unimplemented!("Unsupported dimensionality {other}"),
44    };
45
46    launch_with_routine::<Rt>(
47        client,
48        out_grad,
49        weights,
50        in_grad,
51        (&stride, &padding, &dilation),
52        dimensionality,
53        blueprint_strategy,
54        dtypes,
55    )
56}
57
58#[allow(clippy::too_many_arguments)]
59fn launch_with_routine<Rt: Routine>(
60    client: &Client,
61    out_grad: InputBinding,
62    weights: InputBinding,
63    in_grad: TensorBinding,
64    (stride, padding, dilation): (&[usize], &[usize], &[usize]),
65    dimensionality: Dimensionality,
66    blueprint_strategy: &BlueprintStrategy<Rt::MatmulRoutine>,
67    dtypes: MatmulElems,
68) -> Result<(), ConvSetupError>
69where
70    Rt::Args: ConcreteArgs<Rt::MatmulRoutine>,
71{
72    let rank = in_grad.shape.len();
73    let dim_c = rank - 1;
74
75    let n = in_grad.shape[0];
76    let c = in_grad.shape[dim_c];
77
78    let out_c = out_grad.shape()[dim_c];
79
80    let in_shape = &in_grad.shape[1..dim_c];
81    let kernel_shape = &weights.shape()[1..dim_c];
82    let out_shape = &out_grad.shape()[1..dim_c];
83
84    let op = ConvolutionOperation::BackwardData;
85
86    let out_grad_tmp = out_grad.clone();
87    let weights_tmp = weights.clone();
88
89    let out_grad_data =
90        Rt::correct_layout(client, out_grad_tmp.into_data(), dtypes.lhs_global, op)?;
91    let weights_data = Rt::correct_layout(client, weights_tmp.into_data(), dtypes.rhs_global, op)?;
92
93    let mut out_grad = out_grad.clone();
94    let mut weights = weights.clone();
95
96    *out_grad.data_mut() = out_grad_data;
97    *weights.data_mut() = weights_data;
98
99    let address_type = out_grad
100        .required_address_type()
101        .max(weights.required_address_type())
102        .max(in_grad.required_address_type(dtypes.acc_global.size()));
103
104    let problem = ConvolutionProblem {
105        m: n * in_shape.iter().product::<usize>(),
106        n: c,
107        k: out_c * kernel_shape.iter().product::<usize>(),
108
109        lhs_strides: out_grad.data().strides.clone(),
110        rhs_strides: weights.data().strides.clone(),
111        lhs_layout: MatrixLayout::RowMajor,
112        rhs_layout: MatrixLayout::RowMajor,
113        kernel_size: kernel_shape.iter().map(|it| *it as u32).collect(),
114        stride: stride.iter().map(|it| *it as u32).collect(),
115        padding: padding.iter().map(|it| *it as i32).collect(),
116        dilation: dilation.iter().map(|it| *it as u32).collect(),
117
118        batches: n,
119        in_shape: in_shape.into(),
120        out_shape: out_shape.into(),
121        channels: c,
122        out_channels: out_c,
123
124        padded_channels: out_c,
125        operation: op,
126
127        dimensionality,
128        global_dtypes: dtypes.as_global_elems(),
129        address_type,
130    };
131
132    launch_kernel::<Rt>(
133        client,
134        out_grad,
135        weights,
136        in_grad,
137        problem,
138        blueprint_strategy,
139        dtypes,
140    )
141}
142
143#[allow(clippy::result_large_err, clippy::too_many_arguments)]
144pub fn launch_kernel<Rt: Routine>(
145    client: &Client,
146    out_grad: InputBinding,
147    weights: InputBinding,
148    in_grad: TensorBinding,
149    problem: ConvolutionProblem,
150    blueprint_strategy: &BlueprintStrategy<Rt::MatmulRoutine>,
151    dtypes: MatmulElems,
152) -> Result<(), ConvSetupError>
153where
154    Rt::Args: ConcreteArgs<Rt::MatmulRoutine>,
155{
156    // Shape/strides are treated as k-major, with the last dim always being the contiguous one.
157    // So for the sake of selecting a vector size, the shape/strides are always row-major.
158    let vector_sizes = Rt::filter_vector_sizes(AvailableVectorSizes::from_type_sizes(
159        client,
160        out_grad.data_elem_size(),
161        weights.data_elem_size(),
162        dtypes.acc_global.size(),
163    ))
164    .filter_lhs_with_tensor(
165        &out_grad.data().strides,
166        &out_grad.data().shape,
167        MatrixLayout::RowMajor,
168    )
169    .filter_rhs_with_tensor(
170        &weights.data().strides,
171        &weights.data().shape,
172        MatrixLayout::RowMajor,
173    )
174    .filter_out_with_tensor(&in_grad.strides, &in_grad.shape)
175    .pick_max()?;
176
177    launch_kernel_concrete::<Rt::Args, Rt::MatmulRoutine>(
178        client,
179        out_grad,
180        weights,
181        in_grad,
182        problem,
183        vector_sizes,
184        blueprint_strategy,
185        &dtypes,
186    )
187}
188
189/// Returned by the unified `launch_ref` when the requested routine is not
190/// supported for backward-data. Currently only the TMA reading strategy is
191/// rejected.
192#[allow(dead_code)]
193pub(crate) fn unsupported_tma_error() -> ConvSetupError {
194    ConvSetupError::Matmul(MatmulSetupError::InvalidConfig(Box::new(
195        "Data backprop doesn't yet work with current TMA tiling strategy",
196    )))
197}