1use super::{
2 adaptive_avgpool::{
3 adaptive_avg_pool2d, adaptive_avg_pool2d_backward, adaptive_avg_pool3d,
4 adaptive_avg_pool3d_backward,
5 },
6 avgpool::{avg_pool2d, avg_pool2d_backward},
7 conv::{conv_transpose2d, conv_transpose3d, conv2d, conv3d},
8 deform_conv::{backward::deform_conv2d_backward, deform_conv2d},
9 interpolate::{
10 bicubic_interpolate, bilinear_interpolate, lanczos3_interpolate, nearest_interpolate,
11 },
12 maxpool::{max_pool2d, max_pool2d_backward, max_pool2d_with_indices},
13};
14use crate::ops::interpolate::nearest_interpolate_backward;
15#[cfg(feature = "simd")]
16use crate::ops::simd::{
17 avgpool::try_avg_pool2d_simd, conv::try_conv2d_simd, maxpool::try_max_pool2d_simd,
18};
19use crate::{
20 NdArray, SharedArray, execute_with_int_dtype, execute_with_int_out_dtype, tensor::NdArrayTensor,
21};
22use burn_backend::{
23 TensorMetadata,
24 ops::{attention::attention_fallback, conv::pad_asymmetric_conv_input, *},
25 tensor::FloatTensor,
26};
27use burn_std::IntDType;
28
29macro_rules! module_op {
30 (inp($($x:tt),+), opt($($opt:tt),*), $element:ident, $op:expr) => {{
33 #[allow(unused_parens, unreachable_patterns)]
34 match ($($x),+) {
35 ($(NdArrayTensor::F32($x)),+) => {
36 type $element = f32;
37 $op(
38 $($x.into_shared()),+
39 $(, $opt.map(|o| match o { NdArrayTensor::F32(val) => val.into_shared(), _ => panic!("Optional argument type mismatch") }))*
40 )
41 }
42 ($(NdArrayTensor::F64($x)),+) => {
43 type $element = f64;
44 $op(
45 $($x.into_shared()),+
46 $(, $opt.map(|o| match o { NdArrayTensor::F64(val) => val.into_shared(), _ => panic!("Optional argument type mismatch") }))*
47 )
48 }
49 _ => panic!("Data type mismatch"),
50 }
51 }};
52}
53
54impl ModuleOps<Self> for NdArray {
55 fn conv2d(
56 x: NdArrayTensor,
57 weight: NdArrayTensor,
58 bias: Option<NdArrayTensor>,
59 options: ConvOptions<2>,
60 ) -> NdArrayTensor {
61 let (x, options) = pad_asymmetric_conv_input::<NdArray, 2>(x, options);
62 module_op!(inp(x, weight), opt(bias), E, |x, weight, bias| {
63 #[cfg(feature = "simd")]
64 let (x, weight, bias) = match try_conv2d_simd(x, weight, bias, options.clone()) {
65 Ok(out) => return out.into(),
66 Err(args) => args,
67 };
68 conv2d::<E>(x, weight, bias, options).into()
69 })
70 }
71
72 fn deform_conv2d(
73 x: FloatTensor<Self>,
74 offset: FloatTensor<Self>,
75 weight: FloatTensor<Self>,
76 mask: Option<FloatTensor<Self>>,
77 bias: Option<FloatTensor<Self>>,
78 options: DeformConvOptions<2>,
79 ) -> FloatTensor<Self> {
80 module_op!(
81 inp(x, offset, weight),
82 opt(mask, bias),
83 E,
84 |x, offset, weight, mask, bias| deform_conv2d::<E>(
85 x, offset, weight, mask, bias, options
86 )
87 .into()
88 )
89 }
90
91 fn deform_conv2d_backward(
92 x: FloatTensor<Self>,
93 offset: FloatTensor<Self>,
94 weight: FloatTensor<Self>,
95 mask: Option<FloatTensor<Self>>,
96 bias: Option<FloatTensor<Self>>,
97 output_grad: FloatTensor<Self>,
98 options: DeformConvOptions<2>,
99 ) -> DeformConv2dBackward<Self> {
100 module_op!(
101 inp(x, offset, weight, output_grad),
102 opt(mask, bias),
103 E,
104 |x, offset, weight, output_grad, mask, bias| {
105 let (x, offset, weight, mask, bias) = deform_conv2d_backward::<E>(
106 x,
107 offset,
108 weight,
109 mask,
110 bias,
111 output_grad,
112 options,
113 );
114 DeformConv2dBackward::new(
115 x.into(),
116 offset.into(),
117 weight.into(),
118 mask.map(|m| m.into()),
119 bias.map(|b| b.into()),
120 )
121 }
122 )
123 }
124
125 fn conv_transpose2d(
126 x: FloatTensor<Self>,
127 weight: FloatTensor<Self>,
128 bias: Option<FloatTensor<Self>>,
129 options: ConvTransposeOptions<2>,
130 ) -> FloatTensor<Self> {
131 module_op!(inp(x, weight), opt(bias), E, |x, weight, bias| {
132 conv_transpose2d::<E>(x, weight, bias, options).into()
133 })
134 }
135
136 fn avg_pool2d(
137 x: FloatTensor<Self>,
138 kernel_size: [usize; 2],
139 stride: [usize; 2],
140 padding: [usize; 2],
141 count_include_pad: bool,
142 ceil_mode: bool,
143 ) -> FloatTensor<Self> {
144 module_op!(inp(x), opt(), E, |x| {
145 #[cfg(feature = "simd")]
146 let x = match if ceil_mode {
147 Err(x)
149 } else {
150 try_avg_pool2d_simd(x, kernel_size, stride, padding, count_include_pad)
151 } {
152 Ok(out) => return out.into(),
153 Err(x) => x,
154 };
155 avg_pool2d::<E>(
156 x,
157 kernel_size,
158 stride,
159 padding,
160 count_include_pad,
161 ceil_mode,
162 )
163 .into()
164 })
165 }
166
167 fn avg_pool2d_backward(
168 x: FloatTensor<Self>,
169 grad: FloatTensor<Self>,
170 kernel_size: [usize; 2],
171 stride: [usize; 2],
172 padding: [usize; 2],
173 count_include_pad: bool,
174 ceil_mode: bool,
175 ) -> FloatTensor<Self> {
176 module_op!(inp(x, grad), opt(), E, |x, grad| avg_pool2d_backward::<E>(
177 x,
178 grad,
179 kernel_size,
180 stride,
181 padding,
182 count_include_pad,
183 ceil_mode
184 )
185 .into())
186 }
187
188 fn max_pool2d(
189 x: FloatTensor<Self>,
190 kernel_size: [usize; 2],
191 stride: [usize; 2],
192 padding: [usize; 2],
193 dilation: [usize; 2],
194 ceil_mode: bool,
195 ) -> FloatTensor<Self> {
196 module_op!(inp(x), opt(), E, |x| {
197 #[cfg(feature = "simd")]
198 let x = match if ceil_mode {
199 Err(x)
201 } else {
202 try_max_pool2d_simd(x, kernel_size, stride, padding, dilation)
203 } {
204 Ok(out) => return out.into(),
205 Err(x) => x,
206 };
207 max_pool2d::<E>(x, kernel_size, stride, padding, dilation, ceil_mode).into()
208 })
209 }
210
211 fn max_pool2d_with_indices(
212 x: FloatTensor<Self>,
213 kernel_size: [usize; 2],
214 stride: [usize; 2],
215 padding: [usize; 2],
216 dilation: [usize; 2],
217 ceil_mode: bool,
218 indices_dtype: IntDType,
219 ) -> MaxPool2dWithIndices<Self> {
220 execute_with_int_out_dtype!(indices_dtype, I, {
221 module_op!(inp(x), opt(), E, |x| {
222 let (output, indices) = max_pool2d_with_indices::<E, I>(
223 x,
224 kernel_size,
225 stride,
226 padding,
227 dilation,
228 ceil_mode,
229 );
230 MaxPool2dWithIndices::new(output.into(), indices.into())
231 })
232 })
233 }
234
235 fn max_pool2d_with_indices_backward(
236 x: FloatTensor<Self>,
237 kernel_size: [usize; 2],
238 stride: [usize; 2],
239 padding: [usize; 2],
240 dilation: [usize; 2],
241 ceil_mode: bool,
242 output_grad: FloatTensor<Self>,
243 indices: NdArrayTensor,
244 ) -> MaxPool2dBackward<Self> {
245 execute_with_int_dtype!(indices, IntElem, |idx_s: SharedArray<IntElem>| {
246 module_op!(inp(x, output_grad), opt(), E, |x, output_grad| {
247 let output = max_pool2d_backward::<E, IntElem>(
248 x,
249 kernel_size,
250 stride,
251 padding,
252 dilation,
253 ceil_mode,
254 output_grad,
255 idx_s,
256 );
257 MaxPool2dBackward::new(output.into())
258 })
259 })
260 }
261
262 fn adaptive_avg_pool2d(x: FloatTensor<Self>, output_size: [usize; 2]) -> FloatTensor<Self> {
263 module_op!(inp(x), opt(), E, |x| adaptive_avg_pool2d::<E>(
264 x,
265 output_size
266 )
267 .into())
268 }
269
270 fn adaptive_avg_pool2d_backward(
271 x: FloatTensor<Self>,
272 grad: FloatTensor<Self>,
273 ) -> FloatTensor<Self> {
274 module_op!(inp(x, grad), opt(), E, |x, grad| {
275 adaptive_avg_pool2d_backward::<E>(x, grad).into()
276 })
277 }
278
279 fn adaptive_avg_pool3d(x: FloatTensor<Self>, output_size: [usize; 3]) -> FloatTensor<Self> {
280 module_op!(inp(x), opt(), E, |x| adaptive_avg_pool3d::<E>(
281 x,
282 output_size
283 )
284 .into())
285 }
286
287 fn adaptive_avg_pool3d_backward(
288 x: FloatTensor<Self>,
289 grad: FloatTensor<Self>,
290 ) -> FloatTensor<Self> {
291 module_op!(inp(x, grad), opt(), E, |x, grad| {
292 adaptive_avg_pool3d_backward::<E>(x, grad).into()
293 })
294 }
295
296 fn interpolate(
297 x: FloatTensor<Self>,
298 output_size: [usize; 2],
299 options: InterpolateOptions,
300 ) -> FloatTensor<Self> {
301 match options.mode {
302 InterpolateMode::Nearest => {
303 module_op!(inp(x), opt(), E, |x| nearest_interpolate::<E>(
304 x,
305 output_size
306 )
307 .into())
308 }
309 InterpolateMode::NearestExact => {
310 panic!("nearest exact interpolation is not supported for ndarray backend")
311 }
312 InterpolateMode::Bilinear => {
313 let align_corners = options.align_corners;
314 module_op!(inp(x), opt(), E, |x| bilinear_interpolate::<E>(
315 x,
316 output_size,
317 align_corners
318 )
319 .into())
320 }
321 InterpolateMode::Bicubic => {
322 let align_corners = options.align_corners;
323 module_op!(inp(x), opt(), E, |x| bicubic_interpolate::<E>(
324 x,
325 output_size,
326 align_corners
327 )
328 .into())
329 }
330 InterpolateMode::Lanczos3 => {
331 let align_corners = options.align_corners;
332 module_op!(inp(x), opt(), E, |x| lanczos3_interpolate::<E>(
333 x,
334 output_size,
335 align_corners
336 )
337 .into())
338 }
339 }
340 }
341
342 fn interpolate_backward(
343 x: FloatTensor<Self>,
344 grad: FloatTensor<Self>,
345 output_size: [usize; 2],
346 options: InterpolateOptions,
347 ) -> FloatTensor<Self> {
348 match options.mode {
349 InterpolateMode::Nearest => module_op!(inp(x, grad), opt(), E, |x, grad| {
350 nearest_interpolate_backward::<E>(x, grad, output_size).into()
351 }),
352 InterpolateMode::NearestExact => {
353 panic!("nearest exact interpolation backward is not supported for ndarray backend")
354 }
355 InterpolateMode::Bilinear => {
356 panic!("bilinear interpolation backward is not supported for ndarray backend")
357 }
358 InterpolateMode::Bicubic => {
359 panic!("bicubic interpolation backward is not supported for ndarray backend")
360 }
361 InterpolateMode::Lanczos3 => {
362 panic!("lanczos3 interpolation backward is not supported for ndarray backend")
363 }
364 }
365 }
366
367 fn conv3d(
368 x: FloatTensor<Self>,
369 weight: FloatTensor<Self>,
370 bias: Option<FloatTensor<Self>>,
371 options: ConvOptions<3>,
372 ) -> FloatTensor<Self> {
373 module_op!(inp(x, weight), opt(bias), E, |x, weight, bias| conv3d::<E>(
374 x, weight, bias, options
375 )
376 .into())
377 }
378
379 fn conv_transpose3d(
380 x: FloatTensor<Self>,
381 weight: FloatTensor<Self>,
382 bias: Option<FloatTensor<Self>>,
383 options: ConvTransposeOptions<3>,
384 ) -> FloatTensor<Self> {
385 module_op!(inp(x, weight), opt(bias), E, |x, weight, bias| {
386 conv_transpose3d::<E>(x, weight, bias, options).into()
387 })
388 }
389
390 fn attention(
391 query: FloatTensor<Self>,
392 key: FloatTensor<Self>,
393 value: FloatTensor<Self>,
394 mask: Option<burn_backend::tensor::BoolTensor<Self>>,
395 attn_bias: Option<FloatTensor<Self>>,
396 options: AttentionModuleOptions,
397 ) -> FloatTensor<Self> {
398 attention_fallback::<Self>(query, key, value, mask, attn_bias, options)
399 }
400}