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, *},
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 module_op!(inp(x, weight), opt(bias), E, |x, weight, bias| {
62 #[cfg(feature = "simd")]
63 let (x, weight, bias) = match try_conv2d_simd(x, weight, bias, options.clone()) {
64 Ok(out) => return out.into(),
65 Err(args) => args,
66 };
67 conv2d::<E>(x, weight, bias, options).into()
68 })
69 }
70
71 fn deform_conv2d(
72 x: FloatTensor<Self>,
73 offset: FloatTensor<Self>,
74 weight: FloatTensor<Self>,
75 mask: Option<FloatTensor<Self>>,
76 bias: Option<FloatTensor<Self>>,
77 options: DeformConvOptions<2>,
78 ) -> FloatTensor<Self> {
79 module_op!(
80 inp(x, offset, weight),
81 opt(mask, bias),
82 E,
83 |x, offset, weight, mask, bias| deform_conv2d::<E>(
84 x, offset, weight, mask, bias, options
85 )
86 .into()
87 )
88 }
89
90 fn deform_conv2d_backward(
91 x: FloatTensor<Self>,
92 offset: FloatTensor<Self>,
93 weight: FloatTensor<Self>,
94 mask: Option<FloatTensor<Self>>,
95 bias: Option<FloatTensor<Self>>,
96 output_grad: FloatTensor<Self>,
97 options: DeformConvOptions<2>,
98 ) -> DeformConv2dBackward<Self> {
99 module_op!(
100 inp(x, offset, weight, output_grad),
101 opt(mask, bias),
102 E,
103 |x, offset, weight, output_grad, mask, bias| {
104 let (x, offset, weight, mask, bias) = deform_conv2d_backward::<E>(
105 x,
106 offset,
107 weight,
108 mask,
109 bias,
110 output_grad,
111 options,
112 );
113 DeformConv2dBackward::new(
114 x.into(),
115 offset.into(),
116 weight.into(),
117 mask.map(|m| m.into()),
118 bias.map(|b| b.into()),
119 )
120 }
121 )
122 }
123
124 fn conv_transpose2d(
125 x: FloatTensor<Self>,
126 weight: FloatTensor<Self>,
127 bias: Option<FloatTensor<Self>>,
128 options: ConvTransposeOptions<2>,
129 ) -> FloatTensor<Self> {
130 module_op!(inp(x, weight), opt(bias), E, |x, weight, bias| {
131 conv_transpose2d::<E>(x, weight, bias, options).into()
132 })
133 }
134
135 fn avg_pool2d(
136 x: FloatTensor<Self>,
137 kernel_size: [usize; 2],
138 stride: [usize; 2],
139 padding: [usize; 2],
140 count_include_pad: bool,
141 ceil_mode: bool,
142 ) -> FloatTensor<Self> {
143 module_op!(inp(x), opt(), E, |x| {
144 #[cfg(feature = "simd")]
145 let x = match if ceil_mode {
146 Err(x)
148 } else {
149 try_avg_pool2d_simd(x, kernel_size, stride, padding, count_include_pad)
150 } {
151 Ok(out) => return out.into(),
152 Err(x) => x,
153 };
154 avg_pool2d::<E>(
155 x,
156 kernel_size,
157 stride,
158 padding,
159 count_include_pad,
160 ceil_mode,
161 )
162 .into()
163 })
164 }
165
166 fn avg_pool2d_backward(
167 x: FloatTensor<Self>,
168 grad: FloatTensor<Self>,
169 kernel_size: [usize; 2],
170 stride: [usize; 2],
171 padding: [usize; 2],
172 count_include_pad: bool,
173 ceil_mode: bool,
174 ) -> FloatTensor<Self> {
175 module_op!(inp(x, grad), opt(), E, |x, grad| avg_pool2d_backward::<E>(
176 x,
177 grad,
178 kernel_size,
179 stride,
180 padding,
181 count_include_pad,
182 ceil_mode
183 )
184 .into())
185 }
186
187 fn max_pool2d(
188 x: FloatTensor<Self>,
189 kernel_size: [usize; 2],
190 stride: [usize; 2],
191 padding: [usize; 2],
192 dilation: [usize; 2],
193 ceil_mode: bool,
194 ) -> FloatTensor<Self> {
195 module_op!(inp(x), opt(), E, |x| {
196 #[cfg(feature = "simd")]
197 let x = match if ceil_mode {
198 Err(x)
200 } else {
201 try_max_pool2d_simd(x, kernel_size, stride, padding, dilation)
202 } {
203 Ok(out) => return out.into(),
204 Err(x) => x,
205 };
206 max_pool2d::<E>(x, kernel_size, stride, padding, dilation, ceil_mode).into()
207 })
208 }
209
210 fn max_pool2d_with_indices(
211 x: FloatTensor<Self>,
212 kernel_size: [usize; 2],
213 stride: [usize; 2],
214 padding: [usize; 2],
215 dilation: [usize; 2],
216 ceil_mode: bool,
217 indices_dtype: IntDType,
218 ) -> MaxPool2dWithIndices<Self> {
219 execute_with_int_out_dtype!(indices_dtype, I, {
220 module_op!(inp(x), opt(), E, |x| {
221 let (output, indices) = max_pool2d_with_indices::<E, I>(
222 x,
223 kernel_size,
224 stride,
225 padding,
226 dilation,
227 ceil_mode,
228 );
229 MaxPool2dWithIndices::new(output.into(), indices.into())
230 })
231 })
232 }
233
234 fn max_pool2d_with_indices_backward(
235 x: FloatTensor<Self>,
236 kernel_size: [usize; 2],
237 stride: [usize; 2],
238 padding: [usize; 2],
239 dilation: [usize; 2],
240 ceil_mode: bool,
241 output_grad: FloatTensor<Self>,
242 indices: NdArrayTensor,
243 ) -> MaxPool2dBackward<Self> {
244 execute_with_int_dtype!(indices, IntElem, |idx_s: SharedArray<IntElem>| {
245 module_op!(inp(x, output_grad), opt(), E, |x, output_grad| {
246 let output = max_pool2d_backward::<E, IntElem>(
247 x,
248 kernel_size,
249 stride,
250 padding,
251 dilation,
252 ceil_mode,
253 output_grad,
254 idx_s,
255 );
256 MaxPool2dBackward::new(output.into())
257 })
258 })
259 }
260
261 fn adaptive_avg_pool2d(x: FloatTensor<Self>, output_size: [usize; 2]) -> FloatTensor<Self> {
262 module_op!(inp(x), opt(), E, |x| adaptive_avg_pool2d::<E>(
263 x,
264 output_size
265 )
266 .into())
267 }
268
269 fn adaptive_avg_pool2d_backward(
270 x: FloatTensor<Self>,
271 grad: FloatTensor<Self>,
272 ) -> FloatTensor<Self> {
273 module_op!(inp(x, grad), opt(), E, |x, grad| {
274 adaptive_avg_pool2d_backward::<E>(x, grad).into()
275 })
276 }
277
278 fn adaptive_avg_pool3d(x: FloatTensor<Self>, output_size: [usize; 3]) -> FloatTensor<Self> {
279 module_op!(inp(x), opt(), E, |x| adaptive_avg_pool3d::<E>(
280 x,
281 output_size
282 )
283 .into())
284 }
285
286 fn adaptive_avg_pool3d_backward(
287 x: FloatTensor<Self>,
288 grad: FloatTensor<Self>,
289 ) -> FloatTensor<Self> {
290 module_op!(inp(x, grad), opt(), E, |x, grad| {
291 adaptive_avg_pool3d_backward::<E>(x, grad).into()
292 })
293 }
294
295 fn interpolate(
296 x: FloatTensor<Self>,
297 output_size: [usize; 2],
298 options: InterpolateOptions,
299 ) -> FloatTensor<Self> {
300 match options.mode {
301 InterpolateMode::Nearest => {
302 module_op!(inp(x), opt(), E, |x| nearest_interpolate::<E>(
303 x,
304 output_size
305 )
306 .into())
307 }
308 InterpolateMode::NearestExact => {
309 panic!("nearest exact interpolation is not supported for ndarray backend")
310 }
311 InterpolateMode::Bilinear => {
312 let align_corners = options.align_corners;
313 module_op!(inp(x), opt(), E, |x| bilinear_interpolate::<E>(
314 x,
315 output_size,
316 align_corners
317 )
318 .into())
319 }
320 InterpolateMode::Bicubic => {
321 let align_corners = options.align_corners;
322 module_op!(inp(x), opt(), E, |x| bicubic_interpolate::<E>(
323 x,
324 output_size,
325 align_corners
326 )
327 .into())
328 }
329 InterpolateMode::Lanczos3 => {
330 let align_corners = options.align_corners;
331 module_op!(inp(x), opt(), E, |x| lanczos3_interpolate::<E>(
332 x,
333 output_size,
334 align_corners
335 )
336 .into())
337 }
338 }
339 }
340
341 fn interpolate_backward(
342 x: FloatTensor<Self>,
343 grad: FloatTensor<Self>,
344 output_size: [usize; 2],
345 options: InterpolateOptions,
346 ) -> FloatTensor<Self> {
347 match options.mode {
348 InterpolateMode::Nearest => module_op!(inp(x, grad), opt(), E, |x, grad| {
349 nearest_interpolate_backward::<E>(x, grad, output_size).into()
350 }),
351 InterpolateMode::NearestExact => {
352 panic!("nearest exact interpolation backward is not supported for ndarray backend")
353 }
354 InterpolateMode::Bilinear => {
355 panic!("bilinear interpolation backward is not supported for ndarray backend")
356 }
357 InterpolateMode::Bicubic => {
358 panic!("bicubic interpolation backward is not supported for ndarray backend")
359 }
360 InterpolateMode::Lanczos3 => {
361 panic!("lanczos3 interpolation backward is not supported for ndarray backend")
362 }
363 }
364 }
365
366 fn conv3d(
367 x: FloatTensor<Self>,
368 weight: FloatTensor<Self>,
369 bias: Option<FloatTensor<Self>>,
370 options: ConvOptions<3>,
371 ) -> FloatTensor<Self> {
372 module_op!(inp(x, weight), opt(bias), E, |x, weight, bias| conv3d::<E>(
373 x, weight, bias, options
374 )
375 .into())
376 }
377
378 fn conv_transpose3d(
379 x: FloatTensor<Self>,
380 weight: FloatTensor<Self>,
381 bias: Option<FloatTensor<Self>>,
382 options: ConvTransposeOptions<3>,
383 ) -> FloatTensor<Self> {
384 module_op!(inp(x, weight), opt(bias), E, |x, weight, bias| {
385 conv_transpose3d::<E>(x, weight, bias, options).into()
386 })
387 }
388
389 fn attention(
390 query: FloatTensor<Self>,
391 key: FloatTensor<Self>,
392 value: FloatTensor<Self>,
393 mask: Option<burn_backend::tensor::BoolTensor<Self>>,
394 attn_bias: Option<FloatTensor<Self>>,
395 options: AttentionModuleOptions,
396 ) -> FloatTensor<Self> {
397 attention_fallback::<Self>(query, key, value, mask, attn_bias, options)
398 }
399
400 fn rfft(
401 _signal: FloatTensor<Self>,
402 _dim: usize,
403 _n: Option<usize>,
404 ) -> (FloatTensor<Self>, FloatTensor<Self>) {
405 todo!("rfft is not supported for ndarray")
406 }
407
408 fn irfft(
409 _spectrum_re: FloatTensor<Self>,
410 _spectrum_im: FloatTensor<Self>,
411 _dim: usize,
412 _n: Option<usize>,
413 ) -> FloatTensor<Self> {
414 todo!("irfft is not supported for ndarray")
415 }
416}