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