Skip to main content

rudnn/convolution/kernels/backward_data/
launch.rs

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