1#![allow(missing_docs)]
2
3use alloc::vec::Vec;
4use burn_backend::{
5 DType, Distribution, Shape, Slice, SliceOps, calculate_matmul_output,
6 ops::{
7 conv::{
8 calculate_conv_output_shape, calculate_conv_transpose_output_shape,
9 calculate_pool_output_shape,
10 },
11 unfold::calculate_unfold_shape,
12 },
13 quantization::QuantScheme,
14 tensor::IndexingUpdateOp,
15};
16
17use crate::{ScalarIr, TensorId, TensorIr};
18
19use super::operation::*;
20
21impl CreationOpIr {
22 pub fn create(shape: Shape, dtype: DType, new_id: impl FnOnce() -> TensorId) -> Self {
23 let out = TensorIr::uninit(new_id(), shape, dtype);
24
25 CreationOpIr { out }
26 }
27}
28
29impl InitOperationIr {
30 pub fn create(shape: Shape, dtype: DType, new_id: impl FnOnce() -> TensorId) -> Self {
31 let out = TensorIr::uninit(new_id(), shape, dtype);
32
33 InitOperationIr { out }
34 }
35}
36
37impl RandomOpIr {
38 pub fn create(
39 shape: Shape,
40 dtype: DType,
41 distribution: Distribution,
42 new_id: impl FnOnce() -> TensorId,
43 ) -> Self {
44 let out = TensorIr::uninit(new_id(), shape, dtype);
45
46 RandomOpIr { out, distribution }
47 }
48}
49
50impl FullOpIr {
51 pub fn create(
52 shape: Shape,
53 dtype: DType,
54 value: ScalarIr,
55 new_id: impl FnOnce() -> TensorId,
56 ) -> Self {
57 let out = TensorIr::uninit(new_id(), shape, dtype);
59
60 FullOpIr { out, value }
61 }
62}
63
64impl CastOpIr {
65 pub fn create(input: TensorIr, dtype: DType, new_id: impl FnOnce() -> TensorId) -> Self {
66 let out = TensorIr::uninit(new_id(), input.shape.clone(), dtype);
67 CastOpIr { input, out }
68 }
69}
70
71impl ShapeOpIr {
72 pub fn expand(input: TensorIr, shape: Shape, new_id: impl FnOnce() -> TensorId) -> Self {
73 let shape = input.shape.expand(shape).unwrap();
74 Self::create(input, shape, new_id)
75 }
76
77 pub fn reshape(input: TensorIr, shape: Shape, new_id: impl FnOnce() -> TensorId) -> Self {
78 let shape = input.shape.reshape(shape).unwrap();
79 Self::create(input, shape, new_id)
80 }
81
82 fn create(input: TensorIr, shape: Shape, new_id: impl FnOnce() -> TensorId) -> Self {
83 let out = TensorIr::uninit(new_id(), shape, input.dtype);
84 ShapeOpIr { input, out }
85 }
86}
87
88impl From<MatmulOpIr> for BinaryOpIr {
91 fn from(value: MatmulOpIr) -> Self {
92 Self {
93 lhs: value.lhs,
94 rhs: value.rhs,
95 out: value.out,
96 }
97 }
98}
99
100impl From<ReduceOpIr> for UnaryOpIr {
101 fn from(value: ReduceOpIr) -> Self {
102 Self {
103 input: value.input,
104 out: value.out,
105 }
106 }
107}
108
109#[derive(Debug)]
110#[allow(missing_docs)]
111pub enum IrError {
112 DTypeMismatch,
113}
114
115fn dtype_compat(lhs: &DType, rhs: &DType) -> bool {
116 let lhs_qfloat = matches!(lhs, DType::QFloat(_));
117 let rhs_qfloat = matches!(rhs, DType::QFloat(_));
118 if lhs_qfloat && (rhs_qfloat || rhs.is_float())
119 || lhs.is_float() && (rhs_qfloat || rhs.is_float())
120 {
121 true
122 } else {
123 lhs == rhs
124 }
125}
126
127fn output_check<'a, I>(inputs: I, compat: impl Fn(&DType, &DType) -> bool) -> Result<DType, IrError>
128where
129 I: IntoIterator<Item = &'a DType>,
130{
131 let mut iter = inputs.into_iter();
132 let first = iter.next().unwrap();
133 for d in iter {
134 if !compat(first, d) {
135 return Err(IrError::DTypeMismatch);
136 }
137 }
138 Ok(*first)
139}
140
141fn output_dtype<'a, I: IntoIterator<Item = &'a DType>>(inputs: I) -> Result<DType, IrError> {
142 output_check(inputs, |a, b| a == b)
143}
144
145fn output_dtype_mixed<'a, I: IntoIterator<Item = &'a DType>>(inputs: I) -> Result<DType, IrError> {
146 output_check(inputs, dtype_compat)
147}
148
149macro_rules! impl_ir_create {
153 (@create_fn $op:ident { $( $field:ident : $ty:ty ),* $(,)? } , $shape:expr, $dtype:expr) => {
154 #[doc = "Create a new operation IR from the given inputs."]
155 #[doc = "`new_id` should generate a unique `TensorId` for the uninitialized output tensor."]
156 #[allow(clippy::too_many_arguments)]
157 pub fn create($( $field : $ty ),*, new_id: impl FnOnce() -> crate::TensorId) -> $op {
158 let shape = $shape;
159 let dtype = $dtype;
160 let out = TensorIr::uninit(new_id(), shape, dtype);
161 $op { $( $field ),*, out }
162 }
163 };
164
165 (
167 $op:ident { $( $field:ident : $ty:ty ),* $(,)? },
168 shape = $shape:expr,
169 dtype = $dtype:expr
170 ) => {
171 impl $op {
172 impl_ir_create!(@create_fn $op { $( $field : $ty ),* }, $shape, $dtype);
173 }
174 };
175
176 (
178 $op:ident { $( $field:ident : $ty:ty ),* $(,)? },
179 shape = $shape:expr,
180 dtype = $dtype:expr,
181 $fn_name:ident ( $extra:ident : $extra_ty:ty )
182 ) => {
183 impl $op {
184 impl_ir_create!(@create_fn $op { $( $field : $ty ),* }, $shape, $dtype);
185
186 #[doc = "Create a new operation IR from the given inputs and the given output dtype."]
187 #[allow(clippy::too_many_arguments)]
188 pub fn $fn_name($( $field : $ty ),*, $extra: $extra_ty, new_id: impl FnOnce() -> crate::TensorId) -> Self {
189 let shape = $shape;
190 let _ = $dtype; let out = TensorIr::uninit(new_id(), shape, $extra);
192 $op { $( $field ),*, out }
193 }
194 }
195 };
196}
197
198impl_ir_create!(
199 UnaryOpIr { input: TensorIr },
200 shape = input.shape.clone(),
201 dtype = input.dtype,
202 create_comparison(bool_dtype: DType)
204);
205
206impl_ir_create!(
207 BinaryOpIr {
208 lhs: TensorIr,
209 rhs: TensorIr
210 },
211 shape = lhs.shape.broadcast(&rhs.shape).unwrap(),
212 dtype = output_dtype([&lhs.dtype, &rhs.dtype]).unwrap(),
213 create_comparison(bool_dtype: DType)
215);
216
217impl_ir_create!(
218 ScalarOpIr {
219 lhs: TensorIr,
220 rhs: ScalarIr
221 },
222 shape = lhs.shape.clone(),
223 dtype = lhs.dtype,
224 create_comparison(bool_dtype: DType)
226);
227
228impl_ir_create!(
229 MatmulOpIr {
230 lhs: TensorIr,
231 rhs: TensorIr
232 },
233 shape = calculate_matmul_output(&lhs.shape, &rhs.shape).unwrap(),
234 dtype = output_dtype_mixed([&lhs.dtype, &rhs.dtype]).unwrap(),
235 create_mixed(out_dtype: DType)
237);
238
239impl_ir_create!(
240 SwapDimsOpIr {
241 input: TensorIr,
242 dim1: usize,
243 dim2: usize
244 },
245 shape = input.shape.clone().swapped(dim1, dim2).unwrap(),
246 dtype = input.dtype
247);
248
249impl_ir_create!(
250 PermuteOpIr { input: TensorIr, axes: Vec<usize> },
251 shape = input.shape.clone().permuted(&axes).unwrap(),
252 dtype = input.dtype
253);
254
255impl_ir_create!(
256 RepeatDimOpIr {
257 tensor: TensorIr,
258 dim: usize,
259 times: usize
260 },
261 shape = tensor.shape.clone().repeat(dim, times).unwrap(),
262 dtype = tensor.dtype
263);
264
265impl_ir_create!(
266 FlipOpIr { input: TensorIr, axes: Vec<usize> },
267 shape = input.shape.clone(), dtype = input.dtype
269);
270
271impl_ir_create!(
272 CatOpIr { tensors: Vec<TensorIr>, dim: usize },
273 shape = Shape::cat(tensors.iter().map(|t| &t.shape), dim).unwrap(),
274 dtype = output_dtype(tensors.iter().map(|t| &t.dtype)).unwrap()
275);
276
277#[cfg(feature = "distributed")]
278impl_ir_create!(
279 AllReduceOpIr { tensor: TensorIr },
280 shape = tensor.shape.clone(),
281 dtype = tensor.dtype
282);
283
284impl_ir_create!(
285 GatherOpIr {
286 tensor: TensorIr,
287 dim: usize,
288 indices: TensorIr
289 },
290 shape = indices.shape.clone(), dtype = tensor.dtype
292);
293
294impl_ir_create!(
295 ScatterOpIr {
296 tensor: TensorIr,
297 dim: usize,
298 indices: TensorIr,
299 value: TensorIr,
300 update: IndexingUpdateOp
301 },
302 shape = tensor.shape.clone(), dtype = output_dtype([&tensor.dtype, &value.dtype]).unwrap()
304);
305
306impl_ir_create!(
307 ScatterNdOpIr {
308 data: TensorIr,
309 indices: TensorIr,
310 values: TensorIr,
311 reduction: IndexingUpdateOp
312 },
313 shape = data.shape.clone(),
314 dtype = output_dtype([&data.dtype, &values.dtype]).unwrap()
315);
316
317impl GatherNdOpIr {
318 pub fn create(
320 data: TensorIr,
321 indices: TensorIr,
322 new_id: impl FnOnce() -> crate::TensorId,
323 ) -> Self {
324 let m = indices.shape.num_dims();
325 let k = indices.shape[m - 1];
326 let mut dims = indices.shape.as_slice()[..m - 1].to_vec();
327 dims.extend_from_slice(&data.shape.as_slice()[k..]);
328 let shape = Shape::from(dims);
329 let dtype = data.dtype;
330 let out = TensorIr::uninit(new_id(), shape, dtype);
331 GatherNdOpIr { data, indices, out }
332 }
333}
334
335impl_ir_create!(
336 ReduceOpIr { input: TensorIr },
337 shape = [1].into(),
338 dtype = input.dtype
339);
340
341fn reduce_output_shape(mut output_shape: Shape, axis: usize, accumulator_len: usize) -> Shape {
342 assert!(output_shape.rank() > axis);
343 output_shape[axis] = accumulator_len;
344 output_shape
345}
346
347impl_ir_create!(
348 ReduceDimOpIr {
349 input: TensorIr,
350 axis: usize,
351 accumulator_len: usize,
352 },
353 shape = reduce_output_shape(input.shape.clone(), axis, accumulator_len),
354 dtype = input.dtype,
355 create_arg(ind_dtype: DType)
357);
358
359impl_ir_create!(
360 DimOpIr {
361 input: TensorIr,
362 axis: usize
363 },
364 shape = input.shape.clone(), dtype = input.dtype
366);
367
368impl_ir_create!(
369 SelectOpIr {
370 tensor: TensorIr,
371 dim: usize,
372 indices: TensorIr
373 },
374 shape = {
376 let mut s = tensor.shape.clone();
377 s[dim] = indices.shape[0];
378 s
379 },
380 dtype = tensor.dtype
381);
382
383impl_ir_create!(
384 SelectAssignOpIr {
385 tensor: TensorIr,
386 dim: usize,
387 indices: TensorIr,
388 value: TensorIr,
389 update: IndexingUpdateOp
390 },
391 shape = tensor.shape.clone(),
393 dtype = output_dtype([&tensor.dtype, &value.dtype]).unwrap()
394);
395
396impl_ir_create!(
397 SliceOpIr {
398 tensor: TensorIr,
399 ranges: Vec<Slice>,
400 },
401 shape = tensor.shape.clone().slice(&ranges).unwrap(),
402 dtype = tensor.dtype
403);
404
405impl_ir_create!(
406 SliceAssignOpIr {
407 tensor: TensorIr,
408 ranges: Vec<Slice>,
409 value: TensorIr
410 },
411 shape = tensor.shape.clone(),
413 dtype = output_dtype([&tensor.dtype, &value.dtype]).unwrap()
414);
415
416impl_ir_create!(
417 MaskWhereOpIr {
418 tensor: TensorIr,
419 mask: TensorIr,
420 value: TensorIr
421 },
422 shape = Shape::broadcast_many([&tensor.shape, &mask.shape, &value.shape]).unwrap(),
423 dtype = output_dtype([&tensor.dtype, &value.dtype]).unwrap()
424);
425
426impl_ir_create!(
427 MaskFillOpIr {
428 tensor: TensorIr,
429 mask: TensorIr,
430 value: ScalarIr
431 },
432 shape = tensor.shape.broadcast(&mask.shape).unwrap(),
433 dtype = tensor.dtype
434);
435
436impl_ir_create!(
437 ClampOpIr {
438 tensor: TensorIr,
439 min: ScalarIr,
440 max: ScalarIr
441 },
442 shape = tensor.shape.clone(),
443 dtype = tensor.dtype
444);
445
446impl_ir_create!(
447 AvgPool1dOpIr {
448 x: TensorIr,
449 kernel_size: usize,
450 stride: usize,
451 padding: usize,
452 count_include_pad: bool,
453 ceil_mode: bool
454 },
455 shape = calculate_pool_output_shape(
456 &x.shape,
457 &[kernel_size],
458 &[stride],
459 &[padding],
460 &[1],
461 ceil_mode
462 )
463 .unwrap(),
464 dtype = x.dtype
465);
466
467impl_ir_create!(
468 AvgPool1dBackwardOpIr {
469 x: TensorIr,
470 grad: TensorIr,
471 kernel_size: usize,
472 stride: usize,
473 padding: usize,
474 count_include_pad: bool,
475 ceil_mode: bool
476 },
477 shape = x.shape.clone(),
478 dtype = x.dtype
479);
480
481impl_ir_create!(
482 AvgPool2dOpIr {
483 x: TensorIr,
484 kernel_size: [usize; 2],
485 stride: [usize; 2],
486 padding: [usize; 2],
487 count_include_pad: bool,
488 ceil_mode: bool
489 },
490 shape = calculate_pool_output_shape(
491 &x.shape,
492 &kernel_size,
493 &stride,
494 &padding,
495 &[1, 1],
496 ceil_mode
497 )
498 .unwrap(),
499 dtype = x.dtype
500);
501
502impl_ir_create!(
503 AvgPool2dBackwardOpIr {
504 x: TensorIr,
505 grad: TensorIr,
506 kernel_size: [usize; 2],
507 stride: [usize; 2],
508 padding: [usize; 2],
509 count_include_pad: bool,
510 ceil_mode: bool
511 },
512 shape = x.shape.clone(),
513 dtype = x.dtype
514);
515
516impl_ir_create!(
517 MaxPool1dOpIr {
518 x: TensorIr,
519 kernel_size: usize,
520 stride: usize,
521 padding: usize,
522 dilation: usize,
523 ceil_mode: bool
524 },
525 shape = calculate_pool_output_shape(
526 &x.shape,
527 &[kernel_size],
528 &[stride],
529 &[padding],
530 &[dilation],
531 ceil_mode
532 )
533 .unwrap(),
534 dtype = x.dtype
535);
536
537impl_ir_create!(
538 MaxPool2dOpIr {
539 x: TensorIr,
540 kernel_size: [usize; 2],
541 stride: [usize; 2],
542 padding: [usize; 2],
543 dilation: [usize; 2],
544 ceil_mode: bool
545 },
546 shape = calculate_pool_output_shape(
547 &x.shape,
548 &kernel_size,
549 &stride,
550 &padding,
551 &dilation,
552 ceil_mode
553 )
554 .unwrap(),
555 dtype = x.dtype
556);
557
558impl_ir_create!(
559 MaxPool1dWithIndicesBackwardOpIr {
560 x: TensorIr,
561 grad: TensorIr,
562 indices: TensorIr,
563 kernel_size: usize,
564 stride: usize,
565 padding: usize,
566 dilation: usize,
567 ceil_mode: bool
568 },
569 shape = x.shape.clone(),
570 dtype = x.dtype
571);
572
573impl_ir_create!(
574 MaxPool2dWithIndicesBackwardOpIr {
575 x: TensorIr,
576 grad: TensorIr,
577 indices: TensorIr,
578 kernel_size: [usize; 2],
579 stride: [usize; 2],
580 padding: [usize; 2],
581 dilation: [usize; 2],
582 ceil_mode: bool
583 },
584 shape = x.shape.clone(),
585 dtype = x.dtype
586);
587
588impl_ir_create!(
589 AdaptiveAvgPool1dOpIr {
590 x: TensorIr,
591 output_size: usize
592 },
593 shape = Shape::new([x.shape[0], x.shape[1], output_size]),
594 dtype = x.dtype
595);
596
597impl_ir_create!(
598 AdaptiveAvgPool2dOpIr {
599 x: TensorIr,
600 output_size: [usize; 2]
601 },
602 shape = Shape::new([x.shape[0], x.shape[1], output_size[0], output_size[1]]),
603 dtype = x.dtype
604);
605
606impl_ir_create!(
607 AdaptiveAvgPool1dBackwardOpIr {
608 x: TensorIr,
609 grad: TensorIr,
610 },
611 shape = x.shape.clone(),
612 dtype = x.dtype
613);
614
615impl_ir_create!(
616 AdaptiveAvgPool2dBackwardOpIr {
617 x: TensorIr,
618 grad: TensorIr,
619 },
620 shape = x.shape.clone(),
621 dtype = x.dtype
622);
623
624impl_ir_create!(
625 InterpolateOpIr {
626 x: TensorIr,
627 output_size: [usize; 2],
628 options: InterpolateOptionsIr
629 },
630 shape = Shape::new([x.shape[0], x.shape[1], output_size[0], output_size[1]]),
631 dtype = x.dtype
632);
633
634impl_ir_create!(
635 InterpolateBackwardOpIr {
636 x: TensorIr,
637 grad: TensorIr,
638 output_size: [usize; 2],
639 options: InterpolateOptionsIr
640 },
641 shape = x.shape.clone(),
642 dtype = x.dtype
643);
644
645impl_ir_create!(
646 GridSample2dOpIr {
647 tensor: TensorIr,
648 grid: TensorIr,
649 options: GridSampleOptionsIr
650 },
651 shape = Shape::new([
655 tensor.shape[0],
656 tensor.shape[1],
657 grid.shape[1],
658 grid.shape[2]
659 ]),
660 dtype = tensor.dtype
661);
662
663impl_ir_create!(
664 LinearOpIr {
665 x: TensorIr,
666 weight: TensorIr,
667 bias: Option<TensorIr>
668 },
669 shape = {
670 let n = x.shape.num_dims();
672 let mut dims: Vec<usize> = (0..n).map(|i| x.shape[i]).collect();
673 dims[n - 1] = weight.shape[1];
674 Shape::from(dims)
675 },
676 dtype = output_dtype(
677 [
678 Some(&x.dtype),
679 Some(&weight.dtype),
680 bias.as_ref().map(|b| &b.dtype),
681 ]
682 .iter()
683 .filter_map(|&d| d),
684 )
685 .unwrap()
686);
687
688impl_ir_create!(
689 LinearXBackwardOpIr {
690 weight: TensorIr,
691 output_grad: TensorIr,
692 },
693 shape = {
694 let n = output_grad.shape.num_dims();
698 let mut dims: Vec<usize> = (0..n).map(|i| output_grad.shape[i]).collect();
699 dims[n - 1] = weight.shape[0];
700 Shape::from(dims)
701 },
702 dtype = output_grad.dtype
703);
704
705impl_ir_create!(
706 LinearWeightBackwardOpIr {
707 x: TensorIr,
708 output_grad: TensorIr,
709 },
710 shape = {
711 let d_input = x.shape[x.shape.num_dims() - 1];
713 let d_output = output_grad.shape[output_grad.shape.num_dims() - 1];
714 Shape::from(alloc::vec![d_input, d_output])
715 },
716 dtype = output_grad.dtype
717);
718
719impl_ir_create!(
720 LinearBiasBackwardOpIr {
721 output_grad: TensorIr,
722 },
723 shape = {
724 let d_output = output_grad.shape[output_grad.shape.num_dims() - 1];
726 Shape::from(alloc::vec![d_output])
727 },
728 dtype = output_grad.dtype
729);
730
731impl_ir_create!(
732 Conv1dOpIr {
733 x: TensorIr,
734 weight: TensorIr,
735 bias: Option<TensorIr>,
736 options: Conv1dOptionsIr
737 },
738 shape = calculate_conv_output_shape(
739 &x.shape,
740 &weight.shape,
741 &options.stride,
742 &options.padding,
743 &options.dilation,
744 )
745 .unwrap(),
746 dtype = output_dtype(
747 [
748 Some(&x.dtype),
749 Some(&weight.dtype),
750 bias.as_ref().map(|b| &b.dtype),
751 ]
752 .iter()
753 .filter_map(|&d| d),
754 )
755 .unwrap()
756);
757
758impl_ir_create!(
759 Conv1dXBackwardOpIr {
760 x: TensorIr,
761 weight: TensorIr,
762 output_grad: TensorIr,
763 options: Conv1dOptionsIr
764 },
765 shape = x.shape.clone(),
766 dtype = output_grad.dtype
767);
768
769impl_ir_create!(
770 Conv1dWeightBackwardOpIr {
771 x: TensorIr,
772 weight: TensorIr,
773 output_grad: TensorIr,
774 options: Conv1dOptionsIr
775 },
776 shape = weight.shape.clone(),
777 dtype = output_grad.dtype
778);
779
780impl_ir_create!(
781 Conv1dBiasBackwardOpIr {
782 x: TensorIr,
783 bias: TensorIr,
784 output_grad: TensorIr,
785 },
786 shape = bias.shape.clone(),
787 dtype = output_grad.dtype
788);
789
790impl_ir_create!(
791 Conv2dOpIr {
792 x: TensorIr,
793 weight: TensorIr,
794 bias: Option<TensorIr>,
795 options: Conv2dOptionsIr
796 },
797 shape = calculate_conv_output_shape(
798 &x.shape,
799 &weight.shape,
800 &options.stride,
801 &options.padding,
802 &options.dilation,
803 )
804 .unwrap(),
805 dtype = output_dtype(
806 [
807 Some(&x.dtype),
808 Some(&weight.dtype),
809 bias.as_ref().map(|b| &b.dtype),
810 ]
811 .iter()
812 .filter_map(|&d| d),
813 )
814 .unwrap()
815);
816
817impl_ir_create!(
818 Conv2dXBackwardOpIr {
819 x: TensorIr,
820 weight: TensorIr,
821 output_grad: TensorIr,
822 options: Conv2dOptionsIr
823 },
824 shape = x.shape.clone(),
825 dtype = output_grad.dtype
826);
827
828impl_ir_create!(
829 Conv2dWeightBackwardOpIr {
830 x: TensorIr,
831 weight: TensorIr,
832 output_grad: TensorIr,
833 options: Conv2dOptionsIr
834 },
835 shape = weight.shape.clone(),
836 dtype = output_grad.dtype
837);
838
839impl_ir_create!(
840 Conv2dBiasBackwardOpIr {
841 x: TensorIr,
842 bias: TensorIr,
843 output_grad: TensorIr,
844 },
845 shape = bias.shape.clone(),
846 dtype = output_grad.dtype
847);
848
849impl_ir_create!(
850 Conv3dOpIr {
851 x: TensorIr,
852 weight: TensorIr,
853 bias: Option<TensorIr>,
854 options: Conv3dOptionsIr
855 },
856 shape = calculate_conv_output_shape(
857 &x.shape,
858 &weight.shape,
859 &options.stride,
860 &options.padding,
861 &options.dilation,
862 )
863 .unwrap(),
864 dtype = output_dtype(
865 [
866 Some(&x.dtype),
867 Some(&weight.dtype),
868 bias.as_ref().map(|b| &b.dtype),
869 ]
870 .iter()
871 .filter_map(|&d| d),
872 )
873 .unwrap()
874);
875
876impl_ir_create!(
877 Conv3dXBackwardOpIr {
878 x: TensorIr,
879 weight: TensorIr,
880 output_grad: TensorIr,
881 options: Conv3dOptionsIr
882 },
883 shape = x.shape.clone(),
884 dtype = output_grad.dtype
885);
886
887impl_ir_create!(
888 Conv3dWeightBackwardOpIr {
889 x: TensorIr,
890 weight: TensorIr,
891 output_grad: TensorIr,
892 options: Conv3dOptionsIr
893 },
894 shape = weight.shape.clone(),
895 dtype = output_grad.dtype
896);
897
898impl_ir_create!(
899 Conv3dBiasBackwardOpIr {
900 x: TensorIr,
901 bias: TensorIr,
902 output_grad: TensorIr,
903 },
904 shape = bias.shape.clone(),
905 dtype = output_grad.dtype
906);
907
908impl_ir_create!(
909 DeformConv2dOpIr {
910 x: TensorIr,
911 offset: TensorIr,
912 weight: TensorIr,
913 mask: Option<TensorIr>,
914 bias: Option<TensorIr>,
915 options: DeformableConv2dOptionsIr
916 },
917 shape = calculate_conv_output_shape(
918 &x.shape,
919 &weight.shape,
920 &options.stride,
921 &options.padding,
922 &options.dilation,
923 )
924 .unwrap(),
925 dtype = output_dtype(
926 [
927 Some(&x.dtype),
928 Some(&offset.dtype),
929 Some(&weight.dtype),
930 mask.as_ref().map(|m| &m.dtype),
931 bias.as_ref().map(|b| &b.dtype),
932 ]
933 .iter()
934 .filter_map(|&d| d),
935 )
936 .unwrap()
937);
938
939impl_ir_create!(
940 ConvTranspose1dOpIr {
941 x: TensorIr,
942 weight: TensorIr,
943 bias: Option<TensorIr>,
944 options: ConvTranspose1dOptionsIr
945 },
946 shape = calculate_conv_transpose_output_shape(
947 &x.shape,
948 &weight.shape,
949 &options.stride,
950 &options.padding,
951 &options.padding_out,
952 &options.dilation,
953 options.groups,
954 )
955 .unwrap(),
956 dtype = output_dtype(
957 [
958 Some(&x.dtype),
959 Some(&weight.dtype),
960 bias.as_ref().map(|b| &b.dtype),
961 ]
962 .iter()
963 .filter_map(|&d| d),
964 )
965 .unwrap()
966);
967
968impl_ir_create!(
969 ConvTranspose2dOpIr {
970 x: TensorIr,
971 weight: TensorIr,
972 bias: Option<TensorIr>,
973 options: ConvTranspose2dOptionsIr
974 },
975 shape = calculate_conv_transpose_output_shape(
976 &x.shape,
977 &weight.shape,
978 &options.stride,
979 &options.padding,
980 &options.padding_out,
981 &options.dilation,
982 options.groups,
983 )
984 .unwrap(),
985 dtype = output_dtype(
986 [
987 Some(&x.dtype),
988 Some(&weight.dtype),
989 bias.as_ref().map(|b| &b.dtype),
990 ]
991 .iter()
992 .filter_map(|&d| d),
993 )
994 .unwrap()
995);
996
997impl_ir_create!(
998 ConvTranspose3dOpIr {
999 x: TensorIr,
1000 weight: TensorIr,
1001 bias: Option<TensorIr>,
1002 options: ConvTranspose3dOptionsIr
1003 },
1004 shape = calculate_conv_transpose_output_shape(
1005 &x.shape,
1006 &weight.shape,
1007 &options.stride,
1008 &options.padding,
1009 &options.padding_out,
1010 &options.dilation,
1011 options.groups,
1012 )
1013 .unwrap(),
1014 dtype = output_dtype(
1015 [
1016 Some(&x.dtype),
1017 Some(&weight.dtype),
1018 bias.as_ref().map(|b| &b.dtype),
1019 ]
1020 .iter()
1021 .filter_map(|&d| d),
1022 )
1023 .unwrap()
1024);
1025
1026impl_ir_create!(
1027 UnfoldOpIr {
1028 input: TensorIr,
1029 dim: usize,
1030 size: usize,
1031 step: usize
1032 },
1033 shape = calculate_unfold_shape(input.shape.clone(), dim, size, step),
1034 dtype = input.dtype
1035);
1036
1037impl_ir_create!(
1038 CrossOpIr {
1039 lhs: TensorIr,
1040 rhs: TensorIr,
1041 dim: usize
1042 },
1043 shape = lhs.shape.broadcast(&rhs.shape).unwrap(),
1044 dtype = output_dtype([&lhs.dtype, &rhs.dtype]).unwrap()
1045);
1046
1047impl_ir_create!(
1048 QuantizeOpIr {
1049 tensor: TensorIr,
1050 qparams: QuantizationParametersIr,
1051 scheme: QuantScheme
1052 },
1053 shape = tensor.shape.clone(),
1054 dtype = DType::QFloat(scheme)
1055);
1056
1057impl_ir_create!(
1058 AttentionOpIr {
1059 query: TensorIr,
1060 key: TensorIr,
1061 value: TensorIr,
1062 mask: Option<TensorIr>,
1063 attn_bias: Option<TensorIr>,
1064 options: AttentionOptionsIr,
1065 },
1066 shape = Shape::new([query.shape[0], query.shape[1], query.shape[2], value.shape[3]]),
1067 dtype = query.dtype
1068);
1069
1070impl_ir_create!(
1071 CtcLossOpIr {
1072 log_probs: TensorIr,
1073 targets: TensorIr,
1074 input_lengths: TensorIr,
1075 target_lengths: TensorIr,
1076 blank: usize,
1077 },
1078 shape = Shape::new([log_probs.shape[1]]),
1079 dtype = log_probs.dtype
1080);
1081
1082impl_ir_create!(
1083 CtcLossBackwardOpIr {
1084 log_probs: TensorIr,
1085 targets: TensorIr,
1086 input_lengths: TensorIr,
1087 target_lengths: TensorIr,
1088 grad_loss: TensorIr,
1089 blank: usize,
1090 },
1091 shape = log_probs.shape.clone(),
1092 dtype = log_probs.dtype
1093);
1094
1095impl DequantizeOpIr {
1096 pub fn create(input: TensorIr, dtype: DType, new_id: impl FnOnce() -> TensorId) -> Self {
1097 let out = TensorIr::uninit(new_id(), input.shape.clone(), dtype);
1098
1099 DequantizeOpIr { input, out }
1100 }
1101}
1102
1103impl ReduceDimWithIndicesOpIr {
1106 pub fn create(
1107 tensor: TensorIr,
1108 dim: usize,
1109 dtype_indices: DType,
1110 mut new_id: impl FnMut() -> TensorId,
1111 ) -> Self {
1112 let mut shape = tensor.shape.clone();
1113 shape[dim] = 1;
1114 let out = TensorIr::uninit(new_id(), shape.clone(), tensor.dtype);
1115 let out_indices = TensorIr::uninit(new_id(), shape.clone(), dtype_indices);
1116
1117 ReduceDimWithIndicesOpIr {
1118 tensor,
1119 dim,
1120 out,
1121 out_indices,
1122 }
1123 }
1124}
1125
1126impl DeformConv2dBackwardOpIr {
1127 #[allow(clippy::too_many_arguments)]
1128 pub fn create(
1129 x: TensorIr,
1130 offset: TensorIr,
1131 weight: TensorIr,
1132 mask: Option<TensorIr>,
1133 bias: Option<TensorIr>,
1134 out_grad: TensorIr,
1135 options: DeformableConv2dOptionsIr,
1136 mut new_id: impl FnMut() -> TensorId,
1137 ) -> Self {
1138 let dtype = output_dtype(
1139 [
1140 Some(&x.dtype),
1141 Some(&weight.dtype),
1142 mask.as_ref().map(|m| &m.dtype),
1143 bias.as_ref().map(|b| &b.dtype),
1144 ]
1145 .iter()
1146 .filter_map(|&d| d),
1147 )
1148 .unwrap();
1149
1150 let input_grad = TensorIr::uninit(new_id(), x.shape.clone(), dtype);
1151 let offset_grad = TensorIr::uninit(new_id(), offset.shape.clone(), dtype);
1152 let weight_grad = TensorIr::uninit(new_id(), weight.shape.clone(), dtype);
1153 let mask_grad = mask
1154 .as_ref()
1155 .map(|t| TensorIr::uninit(new_id(), t.shape.clone(), dtype));
1156 let bias_grad = bias
1157 .as_ref()
1158 .map(|t| TensorIr::uninit(new_id(), t.shape.clone(), dtype));
1159
1160 DeformConv2dBackwardOpIr {
1161 x,
1162 offset,
1163 weight,
1164 mask,
1165 bias,
1166 out_grad,
1167 options,
1168 input_grad,
1169 offset_grad,
1170 weight_grad,
1171 mask_grad,
1172 bias_grad,
1173 }
1174 }
1175}
1176
1177impl MaxPool1dWithIndicesOpIr {
1178 #[allow(clippy::too_many_arguments)]
1179 pub fn create(
1180 x: TensorIr,
1181 kernel_size: usize,
1182 stride: usize,
1183 padding: usize,
1184 dilation: usize,
1185 ceil_mode: bool,
1186 dtype_indices: DType,
1187 mut new_id: impl FnMut() -> TensorId,
1188 ) -> Self {
1189 let shape = calculate_pool_output_shape(
1190 &x.shape,
1191 &[kernel_size],
1192 &[stride],
1193 &[padding],
1194 &[dilation],
1195 ceil_mode,
1196 )
1197 .unwrap();
1198 let out = TensorIr::uninit(new_id(), shape.clone(), x.dtype);
1199 let out_indices = TensorIr::uninit(new_id(), shape, dtype_indices);
1200
1201 MaxPool1dWithIndicesOpIr {
1202 x,
1203 kernel_size,
1204 stride,
1205 padding,
1206 dilation,
1207 ceil_mode,
1208 out,
1209 out_indices,
1210 }
1211 }
1212}
1213
1214impl MaxPool2dWithIndicesOpIr {
1215 #[allow(clippy::too_many_arguments)]
1216 pub fn create(
1217 x: TensorIr,
1218 kernel_size: [usize; 2],
1219 stride: [usize; 2],
1220 padding: [usize; 2],
1221 dilation: [usize; 2],
1222 ceil_mode: bool,
1223 dtype_indices: DType,
1224 mut new_id: impl FnMut() -> TensorId,
1225 ) -> Self {
1226 let shape = calculate_pool_output_shape(
1227 &x.shape,
1228 &kernel_size,
1229 &stride,
1230 &padding,
1231 &dilation,
1232 ceil_mode,
1233 )
1234 .unwrap();
1235 let out = TensorIr::uninit(new_id(), shape.clone(), x.dtype);
1236 let out_indices = TensorIr::uninit(new_id(), shape, dtype_indices);
1237
1238 MaxPool2dWithIndicesOpIr {
1239 x,
1240 kernel_size,
1241 stride,
1242 padding,
1243 dilation,
1244 ceil_mode,
1245 out,
1246 out_indices,
1247 }
1248 }
1249}