rudnn/convolution/kernels/backward_data/
args.rs1use ruda_kernel::dsl as kernel_dsl;
2use ruda_kernel::dsl::Runtime;
3use ruda_kernel::dsl::client::ComputeClient;
4use ruda_kernel::dsl::prelude::*;
5use ruda_kernel::library::tensor::launch::ViewArg;
6use ruda_kernel::library::tensor::layout::VirtualLayoutLaunch;
7use ruda_kernel::library::tensor::layout::chain::Chain;
8use ruda_kernel::library::tensor::layout::chain::ChainLaunch;
9use ruda_kernel::dsl::zspace::shape;
10use ruda_kernel::dsl::zspace::strides;
11use rublas::kernel_ir::{
12 components::global::memory::{GlobalLayoutConfig, NoopLayout, NoopLayoutLaunch},
13 definition::{Blueprint, MatmulElems, TilingBlueprint},
14 launch::*,
15 routines::Routine,
16};
17use ruda_kernel::tiling::launch::tma::remap_storage_for_tma;
18use ruda_kernel::tiling::{InputBinding, MatrixLayout};
19use enumset::EnumSet;
20
21use crate::convolution::components::{
22 ConvolutionParams, ConvolutionProblem,
23 global::{
24 args::{RuntimeArgs, RuntimeArgsLaunch},
25 layout::{
26 Im2colLayout, Im2colLayoutLaunch, NhwcCheck, NhwcLayout, NhwcLayoutLaunch, OutLayout,
27 OutLayoutLaunch, TmaIm2colLayout, TmaIm2colLayoutLaunch, WeightLayout,
28 WeightLayoutLaunch,
29 },
30 },
31};
32
33pub trait ConcreteArgs<A: Routine<RuntimeArgs>>:
34 MatmulArgs<
35 Input<Vector<Lhs, LhsSize>, Vector<Rhs, RhsSize>, Vector<Acc, AccSize>>: ConcreteInputsFactory<A>,
36 Output<Vector<Acc, AccSize>>: ConcreteOutputFactory<A>,
37 Config = RuntimeArgs,
38 >
39{
40 fn adjust_problem<R: Runtime>(
41 client: &ComputeClient<R>,
42 problem: ConvolutionProblem,
43 selection: &A::Blueprint,
44 dtypes: &MatmulElems,
45 ) -> ConvolutionProblem;
46}
47
48impl<A: Routine<RuntimeArgs>> ConcreteArgs<A> for TensorArgs<RuntimeArgs> {
49 fn adjust_problem<R: Runtime>(
50 client: &ComputeClient<R>,
51 mut problem: ConvolutionProblem,
52 _blueprint: &A::Blueprint,
53 dtypes: &MatmulElems,
54 ) -> ConvolutionProblem {
55 let load_width = client.properties().hardware.load_width;
56 let channel_align = load_width as usize / dtypes.lhs_global.size_bits();
57 let padded_channels = problem.out_channels.next_multiple_of(channel_align);
58 let shape_k = problem.kernel_size.iter().product::<u32>() as usize * padded_channels;
59
60 problem.k = shape_k;
61 problem.padded_channels = padded_channels;
62
63 problem
64 }
65}
66
67impl<A: Routine<RuntimeArgs, Blueprint = TilingBlueprint>> ConcreteArgs<A>
68 for TensorMapArgs<RuntimeArgs>
69{
70 fn adjust_problem<R: Runtime>(
71 _client: &ComputeClient<R>,
72 mut problem: ConvolutionProblem,
73 blueprint: &TilingBlueprint,
74 _dtypes: &MatmulElems,
75 ) -> ConvolutionProblem {
76 let channel_align = blueprint.tiling_scheme.tile_size.k() as usize;
77 let padded_channels = problem.out_channels.next_multiple_of(channel_align);
78 let shape_k = problem.kernel_size.iter().product::<u32>() as usize * padded_channels;
79
80 problem.k = shape_k;
81 problem.padded_channels = padded_channels;
82
83 problem
84 }
85}
86
87pub trait ConcreteInputsFactory<A: Routine<RuntimeArgs>>: LaunchArg {
90 #[allow(clippy::too_many_arguments)]
91 fn create<R: Runtime>(
92 out_grad: InputBinding<R>,
93 weights: InputBinding<R>,
94 blueprint: &A::Blueprint,
95 problem: &ConvolutionProblem,
96 dtypes: &MatmulElems,
97 ) -> (Self::RuntimeArg<R>, RuntimeArgsLaunch<R>);
98}
99
100pub trait ConcreteOutputFactory<A: Routine<RuntimeArgs>>: LaunchArg {
103 fn create<R: Runtime>(
104 out: TensorBinding<R>,
105 blueprint: &A::Blueprint,
106 problem: &ConvolutionProblem,
107 ) -> Self::RuntimeArg<R>;
108}
109
110impl<Lhs: RudaPrimitive, Rhs: RudaPrimitive, EO: RudaPrimitive, A: Routine<RuntimeArgs>>
111 ConcreteInputsFactory<A> for TensorInputs<Lhs, Rhs, EO>
112{
113 fn create<R: Runtime>(
114 out_grad: InputBinding<R>,
115 weights: InputBinding<R>,
116 blueprint: &A::Blueprint,
117 problem: &ConvolutionProblem,
118 _dtypes: &MatmulElems,
119 ) -> (Self::RuntimeArg<R>, RuntimeArgsLaunch<R>) {
120 type LhsLayout = Chain<NhwcLayout, Im2colLayout>;
121 type RhsLayout = Chain<NhwcLayout, WeightLayout>;
122
123 let padded_channels = problem.padded_channels as u32;
124 let params = ConvolutionParams::from_problem(problem);
125
126 let layout_lhs =
127 Im2colLayoutLaunch::from_args(problem, params, blueprint.lhs_global_layout_config());
128 let layout_rhs =
129 WeightLayoutLaunch::from_args(problem, blueprint.rhs_global_layout_config());
130
131 let layout_lhs = {
132 let mut checks = EnumSet::empty();
133 if problem.should_check_spatial_bounds() {
134 checks.insert(NhwcCheck::Spatial);
135 }
136 if problem.should_check_channel() {
137 checks.insert(NhwcCheck::Channel);
138 }
139 let global = NhwcLayoutLaunch::checked(checks);
140 ChainLaunch::new(global, layout_lhs)
141 };
142 let layout_rhs = {
143 let mut checks = EnumSet::empty();
144 if problem.should_check_channel() {
145 checks.insert(NhwcCheck::Batch);
146 }
147 let global = NhwcLayoutLaunch::checked(checks);
148 ChainLaunch::new(global, layout_rhs)
149 };
150
151 let inputs = TensorInputsLaunch::new(
152 VirtualLayoutLaunch::new::<NoopLayout>(NoopLayoutLaunch::new()),
153 ViewArg::new_tensor::<LhsLayout>(out_grad.into_data().into_tensor_arg(), layout_lhs),
154 VirtualLayoutLaunch::new::<NoopLayout>(NoopLayoutLaunch::new()),
155 ViewArg::new_tensor::<RhsLayout>(weights.into_data().into_tensor_arg(), layout_rhs),
156 ComptimeOptionArgs::None,
157 ComptimeOptionArgs::None,
158 );
159
160 let runtime_args = RuntimeArgsLaunch::new(
161 problem.k as u32,
162 problem.out_channels as u32,
163 padded_channels,
164 problem.operation,
165 );
166
167 (inputs, runtime_args)
168 }
169}
170
171impl<EG: RudaPrimitive, A: Routine<RuntimeArgs>> ConcreteOutputFactory<A> for TensorOutput<EG> {
172 fn create<R: Runtime>(
173 out: TensorBinding<R>,
174 blueprint: &A::Blueprint,
175 problem: &ConvolutionProblem,
176 ) -> Self::RuntimeArg<R> {
177 type Layout = Chain<NhwcLayout, OutLayout>;
178
179 let global = NhwcLayoutLaunch::unchecked();
180 let layout = OutLayoutLaunch::from_args(problem, blueprint.out_global_layout_config());
181 let layout = ChainLaunch::new(global, layout);
182 let view = ViewArg::new_tensor::<Layout>(out.into_tensor_arg(), layout);
183 let batch = VirtualLayoutLaunch::new::<NoopLayout>(NoopLayoutLaunch::new());
184 TensorOutputLaunch::new(view, batch)
185 }
186}
187
188impl<
189 Lhs: RudaPrimitive,
190 Rhs: RudaPrimitive,
191 EO: RudaPrimitive,
192 A: Routine<RuntimeArgs, Blueprint = TilingBlueprint>,
193> ConcreteInputsFactory<A> for TensorMapInputs<Lhs, Rhs, EO>
194{
195 fn create<R: Runtime>(
196 out_grad: InputBinding<R>,
197 weights: InputBinding<R>,
198 blueprint: &TilingBlueprint,
199 problem: &ConvolutionProblem,
200 dtypes: &MatmulElems,
201 ) -> (Self::RuntimeArg<R>, RuntimeArgsLaunch<R>) {
202 type LhsLayout = TmaIm2colLayout;
203 type RhsLayout = WeightLayout;
204
205 let tiling_scheme = blueprint.tiling_scheme;
206 let stage_m = tiling_scheme.elements_per_stage_along_m();
207 let stage_n = tiling_scheme.elements_per_stage_along_n();
208 let stage_k = tiling_scheme.elements_per_stage_along_k();
209 let tile_size_k = tiling_scheme.tile_size.k;
210
211 let mut stage_size_rhs = shape![1; problem.dimensionality.num_dims()];
212 stage_size_rhs.insert(0, stage_k as usize);
213 stage_size_rhs.push(stage_n as usize);
214
215 let lhs_elem = remap_storage_for_tma(dtypes.lhs_stage);
216
217 let mut elem_stride = strides![1; 2 + problem.stride.len()];
218
219 for (i, stride) in problem.stride.iter().enumerate() {
220 elem_stride[i + 1] = *stride as usize;
221 }
222
223 let lhs = TensorMapArg::new(
224 Im2colArgs {
225 pixel_box_lower_corner: calculate_lower_corner(problem),
226 pixel_box_upper_corner: calculate_upper_corner(problem),
227 channels_per_pixel: tile_size_k,
228 pixels_per_column: stage_m,
229 },
230 out_grad.into_data().into_tensor_arg(),
231 lhs_elem,
232 )
233 .with_elem_stride(elem_stride);
234
235 let rhs = TensorMapArg::new(
236 TiledArgs {
237 tile_size: stage_size_rhs,
238 },
239 weights.into_data().into_tensor_arg(),
240 dtypes.rhs_global,
241 );
242
243 let padded_channels = problem.padded_channels as u32;
244 let shape_k = problem.k as u32;
245
246 let stages_lhs = A::num_stages().lhs;
250 let stages_size_k = blueprint.tiling_scheme.elements_per_stage_along_k() * stages_lhs;
251 let check_kernel = !shape_k.is_multiple_of(stages_size_k);
252 let lhs_layout = TmaIm2colLayoutLaunch::from_args(problem, check_kernel);
253 let rhs_layout = WeightLayoutLaunch::from_args(
254 problem,
255 GlobalLayoutConfig {
256 check_row_bounds: false,
257 check_col_bounds: false,
258 matrix_layout: MatrixLayout::default(),
259 },
260 );
261
262 let inputs = TensorMapInputsLaunch::new(
263 ViewArg::new_tensor_map_im2col::<LhsLayout, _, _>(lhs, lhs_layout),
264 ViewArg::new_tensor_map_tiled::<RhsLayout>(rhs, rhs_layout),
265 ComptimeOptionArgs::None,
266 ComptimeOptionArgs::None,
267 );
268
269 let runtime_args = RuntimeArgsLaunch::new(
270 shape_k,
271 problem.out_channels as u32,
272 padded_channels,
273 problem.operation,
274 );
275
276 (inputs, runtime_args)
277 }
278}
279
280#[allow(clippy::needless_range_loop)]
281fn calculate_lower_corner(problem: &ConvolutionProblem) -> Vec<i32> {
282 let mut out = vec![0; problem.padding.len()];
283 for i in 0..problem.padding.len() {
284 out[i] =
285 problem.padding[i] - (problem.kernel_size[i] as i32 - 1) * problem.dilation[i] as i32;
286 }
287 out
288}
289
290#[allow(clippy::needless_range_loop)]
291fn calculate_upper_corner(problem: &ConvolutionProblem) -> Vec<i32> {
292 let mut out = vec![0; problem.padding.len()];
293 for i in 0..problem.padding.len() {
294 out[i] = problem.padding[i]
295 - (problem.kernel_size[i] as i32 - 1) * problem.dilation[i] as i32
296 + problem.in_shape[i] as i32
297 - problem.out_shape[i] as i32;
298 }
299 out
300}