1use crate::{
2 AcceleratedTileKind, ConvolutionArgs, ReadingStrategy, Strategy,
3 backward_data::args::ConcreteArgs,
4 components::{ConvolutionOperation, global::args::RuntimeArgs},
5 kernels::algorithm::simple::*,
6};
7use crate::{components::ConvSetupError, kernels::backward_data::selector::launch_kernel_concrete};
8use crate::{
9 components::{ConvolutionProblem, Dimensionality},
10 kernels::algorithm::Algorithm,
11};
12use cubecl::{Runtime, client::ComputeClient, prelude::*, std::tensor::TensorHandle};
13use cubek_matmul::{
14 components::tile::{cmma::CmmaMatmul, io::Strided, mma::MmaMatmul},
15 definition::{AvailableLineSizes, MatmulElems, MatmulSetupError, MatrixLayout},
16 launch::{MatmulInputHandle, MatmulInputHandleRef},
17 routines::BlueprintStrategy,
18};
19use derive_new::new;
20
21macro_rules! with_tile_kind {
22 ($kind: expr, $T: ident, $launch: expr) => {
23 match $kind {
24 AcceleratedTileKind::Cmma => {
25 type $T = CmmaMatmul<Option<Strided>>;
26 ($launch)()
27 }
28 AcceleratedTileKind::Mma => {
29 type $T = MmaMatmul<Strided, Strided, Option<Strided>>;
30 ($launch)()
31 }
32 }
33 };
34}
35
36#[allow(clippy::result_large_err, clippy::too_many_arguments)]
37pub fn launch<R: Runtime, const N_SPATIAL: usize>(
38 strategy: &Strategy,
39 client: &ComputeClient<R>,
40 out_grad: MatmulInputHandle<R>,
41 weights: MatmulInputHandle<R>,
42 in_grad: TensorHandle<R>,
43 args: ConvolutionArgs<N_SPATIAL>,
44 dtypes: MatmulElems,
45) -> Result<(), ConvSetupError> {
46 launch_ref(
47 strategy,
48 client,
49 &out_grad.as_ref(),
50 &weights.as_ref(),
51 &in_grad.as_ref(),
52 args,
53 dtypes,
54 )
55}
56
57#[allow(clippy::result_large_err, clippy::too_many_arguments)]
66pub fn launch_ref<R: Runtime, const N_SPATIAL: usize>(
67 strategy: &Strategy,
68 client: &ComputeClient<R>,
69 out_grad: &MatmulInputHandleRef<'_, R>,
70 weights: &MatmulInputHandleRef<'_, R>,
71 in_grad: &TensorHandleRef<'_, R>,
72 args: ConvolutionArgs<N_SPATIAL>,
73 dtypes: MatmulElems,
74) -> Result<(), ConvSetupError> {
75 let backprop = BackwardsData::new(client, out_grad, weights, in_grad, args, dtypes);
76
77 match strategy {
78 Strategy::Simple {
79 read_strategy,
80 tile_kind,
81 } => with_tile_kind!(tile_kind, Accelerated, || match read_strategy {
82 ReadingStrategy::Cyclic => backprop.launch::<SimpleSyncCyclicConv<Accelerated>>(),
83 ReadingStrategy::Strided => backprop.launch::<SimpleSyncStridedConv<Accelerated>>(),
84 ReadingStrategy::Tilewise => backprop.launch::<SimpleSyncTilewiseConv<Accelerated>>(),
85 ReadingStrategy::AsyncCyclic => backprop.launch::<SimpleAsyncCyclicConv<Accelerated>>(),
86 ReadingStrategy::AsyncStrided =>
87 backprop.launch::<SimpleAsyncStridedConv<Accelerated>>(),
88 ReadingStrategy::Tma => Err(ConvSetupError::Matmul(MatmulSetupError::InvalidConfig(
89 Box::new("Data backprop doesn't yet work with current TMA tiling strategy")
90 ))),
91 }),
92 }
93}
94
95#[derive(new)]
96struct BackwardsData<'a, R: Runtime, const N_SPATIAL: usize> {
97 client: &'a ComputeClient<R>,
98 out_grad: &'a MatmulInputHandleRef<'a, R>,
99 weights: &'a MatmulInputHandleRef<'a, R>,
100 in_grad: &'a TensorHandleRef<'a, R>,
101 args: ConvolutionArgs<N_SPATIAL>,
102 dtypes: MatmulElems,
103}
104
105impl<'a, R: Runtime, const N_SPATIAL: usize> BackwardsData<'a, R, N_SPATIAL> {
106 fn launch<Alg: Algorithm>(self) -> Result<(), ConvSetupError>
107 where
108 Alg::Args: ConcreteArgs<Alg::Routine>,
109 {
110 let ConvolutionArgs {
111 stride,
112 padding,
113 dilation,
114 } = self.args;
115
116 let dimensionality = match N_SPATIAL {
117 1 => Dimensionality::Dim1,
118 2 => Dimensionality::Dim2,
119 3 => Dimensionality::Dim3,
120 other => unimplemented!("Unsupported dimensionality {other}"),
121 };
122
123 launch_with_algorithm::<R, Alg>(
124 self.client,
125 self.out_grad,
126 self.weights,
127 self.in_grad,
128 (&stride, &padding, &dilation),
129 dimensionality,
130 &BlueprintStrategy::Inferred(Default::default()),
131 self.dtypes,
132 )
133 }
134}
135
136#[allow(clippy::too_many_arguments)]
137fn launch_with_algorithm<R: Runtime, Alg: Algorithm>(
138 client: &ComputeClient<R>,
139 out_grad: &MatmulInputHandleRef<'_, R>,
140 weights: &MatmulInputHandleRef<'_, R>,
141 in_grad: &TensorHandleRef<'_, R>,
142 (stride, padding, dilation): (&[usize], &[usize], &[usize]),
143 dimensionality: Dimensionality,
144 blueprint_strategy: &BlueprintStrategy<RuntimeArgs, Alg::Routine>,
145 dtypes: MatmulElems,
146) -> Result<(), ConvSetupError>
147where
148 Alg::Args: ConcreteArgs<Alg::Routine>,
149{
150 let rank = in_grad.shape.len();
151 let dim_c = rank - 1;
152
153 let n = in_grad.shape[0];
154 let c = in_grad.shape[dim_c];
155
156 let out_c = out_grad.shape()[dim_c];
157
158 let in_shape = &in_grad.shape[1..dim_c];
159 let kernel_shape = &weights.shape()[1..dim_c];
160 let out_shape = &out_grad.shape()[1..dim_c];
161
162 let op = ConvolutionOperation::BackwardData;
163
164 let out_grad_data = Alg::into_tensor_handle(client, out_grad.data(), dtypes.lhs_global, op)?;
165 let weights_data = Alg::into_tensor_handle(client, weights.data(), dtypes.rhs_global, op)?;
166
167 let mut out_grad = *out_grad;
168 let mut weights = *weights;
169
170 *out_grad.data_mut() = out_grad_data.as_ref();
171 *weights.data_mut() = weights_data.as_ref();
172
173 let address_type = out_grad
174 .required_address_type()
175 .max(weights.required_address_type())
176 .max(in_grad.required_address_type());
177
178 let problem = ConvolutionProblem {
179 m: n * in_shape.iter().product::<usize>(),
180 n: c,
181 k: out_c * kernel_shape.iter().product::<usize>(),
182
183 lhs_strides: out_grad.data().strides.into(),
184 rhs_strides: weights.data().strides.into(),
185 lhs_layout: MatrixLayout::RowMajor,
186 rhs_layout: MatrixLayout::RowMajor,
187 kernel_size: kernel_shape.iter().map(|it| *it as u32).collect(),
188 stride: stride.iter().map(|it| *it as u32).collect(),
189 padding: padding.iter().map(|it| *it as i32).collect(),
190 dilation: dilation.iter().map(|it| *it as u32).collect(),
191
192 batches: n,
193 in_shape: in_shape.into(),
194 out_shape: out_shape.into(),
195 channels: c,
196 out_channels: out_c,
197
198 padded_channels: out_c,
199 operation: op,
200
201 dimensionality,
202 global_dtypes: dtypes.as_global_elems(),
203 address_type,
204 };
205
206 launch_kernel::<R, Alg>(
207 client,
208 &out_grad,
209 &weights,
210 in_grad,
211 problem,
212 blueprint_strategy,
213 dtypes,
214 )
215}
216
217#[allow(clippy::result_large_err, clippy::too_many_arguments)]
218pub fn launch_kernel<R: Runtime, Alg: Algorithm>(
219 client: &ComputeClient<R>,
220 out_grad: &MatmulInputHandleRef<'_, R>,
221 weights: &MatmulInputHandleRef<'_, R>,
222 in_grad: &TensorHandleRef<'_, R>,
223 problem: ConvolutionProblem,
224 blueprint_strategy: &BlueprintStrategy<RuntimeArgs, Alg::Routine>,
225 dtypes: MatmulElems,
226) -> Result<(), ConvSetupError>
227where
228 Alg::Args: ConcreteArgs<Alg::Routine>,
229{
230 let line_sizes = AvailableLineSizes::from_type_sizes(
233 client,
234 out_grad.data().elem_size,
235 weights.data().elem_size,
236 in_grad.elem_size,
237 )
238 .filter_lhs_with_tensor(
239 out_grad.data().strides,
240 out_grad.data().shape,
241 MatrixLayout::RowMajor,
242 )
243 .filter_rhs_with_tensor(
244 weights.data().strides,
245 weights.data().shape,
246 MatrixLayout::RowMajor,
247 )
248 .filter_out_with_tensor(in_grad.strides, in_grad.shape);
249
250 let line_sizes = Alg::filter_line_sizes(line_sizes).pick_max()?;
251
252 launch_kernel_concrete::<R, Alg::Args, Alg::Routine>(
253 client,
254 out_grad,
255 weights,
256 in_grad,
257 problem,
258 line_sizes,
259 blueprint_strategy,
260 &dtypes,
261 )
262}