1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
5pub enum Fp8Format {
6 E4M3,
7 E5M2,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum AggregationType {
13 Sum,
14 Mean,
15 Max,
16 Min,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
20pub enum TensorOp {
21 Add,
23 Sub,
24 Mul,
25 Div,
26 Neg,
27 MatMul,
28 Linear,
29 Conv2D,
30 Embedding,
31
32 ReLU,
34 GeLU,
35 SiLU,
36 Sigmoid,
37 Softmax,
38 Tanh,
39 LeakyReLU,
40 ELU,
41 Mish,
42 HardSwish,
43 HardSigmoid,
44
45 LayerNorm,
47 RMSNorm,
48 BatchNorm,
49 GroupNorm,
50 InstanceNorm,
51
52 Reshape,
54 Transpose,
55 Concat,
56 Split,
57 Gather,
58 Scatter,
59 Squeeze,
60 Unsqueeze,
61 Permute,
62 Expand,
63 Slice,
64 Pad,
65 Tile,
66
67 Constant,
69 Zeros,
70 Ones,
71 Arange,
72 Full,
73
74 Attention,
76 MultiHeadAttention,
77 MultiQueryAttention,
78 GroupedQueryAttention,
79 FlashAttention,
80 SlidingWindowAttention,
81 CrossAttention,
82 PagedAttention,
83
84 MoEDispatch,
86 MoECombine,
87
88 Conv1D,
90 Conv3D,
91 ConvTranspose2D,
92 DepthwiseConv2D,
93 DilatedConv2D,
94
95 MaxPool2D,
97 AvgPool2D,
98 AdaptiveAvgPool2D,
99 GlobalAvgPool,
100
101 LSTMCell,
103 GRUCell,
104 RNNCell,
105
106 Einsum,
108 FFT,
109 IFFT,
110 SVD,
111 Eig,
112 Solve,
113 TopK,
114 Sort,
115 Cumsum,
116 Where,
117 Clamp,
118
119 SparseMatMul,
121 SparseEmbedding,
122
123 Quantize,
125 Dequantize,
126 QuantizeInt4,
127 DequantizeInt4,
128 QuantizeFp8,
129 DequantizeFp8,
130
131 UNetDownBlock,
133 UNetUpBlock,
134 TimestepEmbedding,
135
136 GNNMessagePassing,
138 GNNGlobalPooling,
139
140 Checkpoint,
142 Offload,
143 GradAccumulate,
144
145 GradMatMul,
147 GradReLU,
148 GradSoftmax,
149 GradLayerNorm,
150 GradAttention,
151 GradConv2D,
152 GradLinear,
153 GradGeLU,
154
155 ParallelSplit,
157 ParallelAllReduce,
158 PipelineSend,
159 PipelineReceive,
160
161 FusedMatMulBiasReLU,
163 FusedMatMulBias,
164 FusedLinearGeLU,
165 FusedAttentionLayerNorm,
166 FusedLinearSiLU,
167 FusedConvBatchNormReLU,
168}
169
170impl TensorOp {
171 pub fn name(&self) -> &'static str {
172 match self {
173 Self::Add => "tensor.add",
175 Self::Sub => "tensor.sub",
176 Self::Mul => "tensor.mul",
177 Self::Div => "tensor.div",
178 Self::Neg => "tensor.neg",
179 Self::MatMul => "tensor.matmul",
180 Self::Linear => "tensor.linear",
181 Self::Conv2D => "tensor.conv2d",
182 Self::Embedding => "tensor.embedding",
183 Self::ReLU => "tensor.relu",
185 Self::GeLU => "tensor.gelu",
186 Self::SiLU => "tensor.silu",
187 Self::Sigmoid => "tensor.sigmoid",
188 Self::Softmax => "tensor.softmax",
189 Self::Tanh => "tensor.tanh",
190 Self::LeakyReLU => "tensor.leaky_relu",
191 Self::ELU => "tensor.elu",
192 Self::Mish => "tensor.mish",
193 Self::HardSwish => "tensor.hard_swish",
194 Self::HardSigmoid => "tensor.hard_sigmoid",
195 Self::LayerNorm => "tensor.layernorm",
197 Self::RMSNorm => "tensor.rmsnorm",
198 Self::BatchNorm => "tensor.batchnorm",
199 Self::GroupNorm => "tensor.groupnorm",
200 Self::InstanceNorm => "tensor.instancenorm",
201 Self::Reshape => "tensor.reshape",
203 Self::Transpose => "tensor.transpose",
204 Self::Concat => "tensor.concat",
205 Self::Split => "tensor.split",
206 Self::Gather => "tensor.gather",
207 Self::Scatter => "tensor.scatter",
208 Self::Squeeze => "tensor.squeeze",
209 Self::Unsqueeze => "tensor.unsqueeze",
210 Self::Permute => "tensor.permute",
211 Self::Expand => "tensor.expand",
212 Self::Slice => "tensor.slice",
213 Self::Pad => "tensor.pad",
214 Self::Tile => "tensor.tile",
215 Self::Constant => "tensor.constant",
217 Self::Zeros => "tensor.zeros",
218 Self::Ones => "tensor.ones",
219 Self::Arange => "tensor.arange",
220 Self::Full => "tensor.full",
221 Self::Attention => "tensor.attention",
223 Self::MultiHeadAttention => "tensor.multi_head_attention",
224 Self::MultiQueryAttention => "tensor.multi_query_attention",
225 Self::GroupedQueryAttention => "tensor.grouped_query_attention",
226 Self::FlashAttention => "tensor.flash_attention",
227 Self::SlidingWindowAttention => "tensor.sliding_window_attention",
228 Self::CrossAttention => "tensor.cross_attention",
229 Self::PagedAttention => "tensor.paged_attention",
230 Self::MoEDispatch => "tensor.moe_dispatch",
232 Self::MoECombine => "tensor.moe_combine",
233 Self::Conv1D => "tensor.conv1d",
235 Self::Conv3D => "tensor.conv3d",
236 Self::ConvTranspose2D => "tensor.conv_transpose2d",
237 Self::DepthwiseConv2D => "tensor.depthwise_conv2d",
238 Self::DilatedConv2D => "tensor.dilated_conv2d",
239 Self::MaxPool2D => "tensor.maxpool2d",
241 Self::AvgPool2D => "tensor.avgpool2d",
242 Self::AdaptiveAvgPool2D => "tensor.adaptive_avgpool2d",
243 Self::GlobalAvgPool => "tensor.global_avgpool",
244 Self::LSTMCell => "tensor.lstm_cell",
246 Self::GRUCell => "tensor.gru_cell",
247 Self::RNNCell => "tensor.rnn_cell",
248 Self::Einsum => "tensor.einsum",
250 Self::FFT => "tensor.fft",
251 Self::IFFT => "tensor.ifft",
252 Self::SVD => "tensor.svd",
253 Self::Eig => "tensor.eig",
254 Self::Solve => "tensor.solve",
255 Self::TopK => "tensor.topk",
256 Self::Sort => "tensor.sort",
257 Self::Cumsum => "tensor.cumsum",
258 Self::Where => "tensor.where",
259 Self::Clamp => "tensor.clamp",
260 Self::SparseMatMul => "tensor.sparse_matmul",
262 Self::SparseEmbedding => "tensor.sparse_embedding",
263 Self::Quantize => "tensor.quantize",
265 Self::Dequantize => "tensor.dequantize",
266 Self::QuantizeInt4 => "tensor.quantize_int4",
267 Self::DequantizeInt4 => "tensor.dequantize_int4",
268 Self::QuantizeFp8 => "tensor.quantize_fp8",
269 Self::DequantizeFp8 => "tensor.dequantize_fp8",
270 Self::UNetDownBlock => "tensor.unet_down_block",
272 Self::UNetUpBlock => "tensor.unet_up_block",
273 Self::TimestepEmbedding => "tensor.timestep_embedding",
274 Self::GNNMessagePassing => "tensor.gnn_message_passing",
276 Self::GNNGlobalPooling => "tensor.gnn_global_pooling",
277 Self::Checkpoint => "tensor.checkpoint",
279 Self::Offload => "tensor.offload",
280 Self::GradAccumulate => "tensor.grad_accumulate",
281 Self::GradMatMul => "tensor.grad_matmul",
283 Self::GradReLU => "tensor.grad_relu",
284 Self::GradSoftmax => "tensor.grad_softmax",
285 Self::GradLayerNorm => "tensor.grad_layernorm",
286 Self::GradAttention => "tensor.grad_attention",
287 Self::GradConv2D => "tensor.grad_conv2d",
288 Self::GradLinear => "tensor.grad_linear",
289 Self::GradGeLU => "tensor.grad_gelu",
290 Self::ParallelSplit => "tensor.parallel_split",
292 Self::ParallelAllReduce => "tensor.parallel_allreduce",
293 Self::PipelineSend => "tensor.pipeline_send",
294 Self::PipelineReceive => "tensor.pipeline_receive",
295 Self::FusedMatMulBiasReLU => "tensor.fused_matmul_bias_relu",
297 Self::FusedMatMulBias => "tensor.fused_matmul_bias",
298 Self::FusedLinearGeLU => "tensor.fused_linear_gelu",
299 Self::FusedAttentionLayerNorm => "tensor.fused_attention_layernorm",
300 Self::FusedLinearSiLU => "tensor.fused_linear_silu",
301 Self::FusedConvBatchNormReLU => "tensor.fused_conv_batchnorm_relu",
302 }
303 }
304
305 pub fn from_name(name: &str) -> Option<Self> {
306 match name {
307 "tensor.add" => Some(Self::Add),
308 "tensor.sub" => Some(Self::Sub),
309 "tensor.mul" => Some(Self::Mul),
310 "tensor.div" => Some(Self::Div),
311 "tensor.neg" => Some(Self::Neg),
312 "tensor.matmul" => Some(Self::MatMul),
313 "tensor.linear" => Some(Self::Linear),
314 "tensor.conv2d" => Some(Self::Conv2D),
315 "tensor.embedding" => Some(Self::Embedding),
316 "tensor.relu" => Some(Self::ReLU),
317 "tensor.gelu" => Some(Self::GeLU),
318 "tensor.silu" => Some(Self::SiLU),
319 "tensor.sigmoid" => Some(Self::Sigmoid),
320 "tensor.softmax" => Some(Self::Softmax),
321 "tensor.tanh" => Some(Self::Tanh),
322 "tensor.leaky_relu" => Some(Self::LeakyReLU),
323 "tensor.elu" => Some(Self::ELU),
324 "tensor.mish" => Some(Self::Mish),
325 "tensor.hard_swish" => Some(Self::HardSwish),
326 "tensor.hard_sigmoid" => Some(Self::HardSigmoid),
327 "tensor.layernorm" => Some(Self::LayerNorm),
328 "tensor.rmsnorm" => Some(Self::RMSNorm),
329 "tensor.batchnorm" => Some(Self::BatchNorm),
330 "tensor.groupnorm" => Some(Self::GroupNorm),
331 "tensor.instancenorm" => Some(Self::InstanceNorm),
332 "tensor.reshape" => Some(Self::Reshape),
333 "tensor.transpose" => Some(Self::Transpose),
334 "tensor.concat" => Some(Self::Concat),
335 "tensor.split" => Some(Self::Split),
336 "tensor.gather" => Some(Self::Gather),
337 "tensor.scatter" => Some(Self::Scatter),
338 "tensor.squeeze" => Some(Self::Squeeze),
339 "tensor.unsqueeze" => Some(Self::Unsqueeze),
340 "tensor.permute" => Some(Self::Permute),
341 "tensor.expand" => Some(Self::Expand),
342 "tensor.slice" => Some(Self::Slice),
343 "tensor.pad" => Some(Self::Pad),
344 "tensor.tile" => Some(Self::Tile),
345 "tensor.constant" => Some(Self::Constant),
346 "tensor.zeros" => Some(Self::Zeros),
347 "tensor.ones" => Some(Self::Ones),
348 "tensor.arange" => Some(Self::Arange),
349 "tensor.full" => Some(Self::Full),
350 "tensor.attention" => Some(Self::Attention),
351 "tensor.multi_head_attention" => Some(Self::MultiHeadAttention),
352 "tensor.multi_query_attention" => Some(Self::MultiQueryAttention),
353 "tensor.grouped_query_attention" => Some(Self::GroupedQueryAttention),
354 "tensor.flash_attention" => Some(Self::FlashAttention),
355 "tensor.sliding_window_attention" => Some(Self::SlidingWindowAttention),
356 "tensor.cross_attention" => Some(Self::CrossAttention),
357 "tensor.paged_attention" => Some(Self::PagedAttention),
358 "tensor.moe_dispatch" => Some(Self::MoEDispatch),
359 "tensor.moe_combine" => Some(Self::MoECombine),
360 "tensor.conv1d" => Some(Self::Conv1D),
361 "tensor.conv3d" => Some(Self::Conv3D),
362 "tensor.conv_transpose2d" => Some(Self::ConvTranspose2D),
363 "tensor.depthwise_conv2d" => Some(Self::DepthwiseConv2D),
364 "tensor.dilated_conv2d" => Some(Self::DilatedConv2D),
365 "tensor.maxpool2d" => Some(Self::MaxPool2D),
366 "tensor.avgpool2d" => Some(Self::AvgPool2D),
367 "tensor.adaptive_avgpool2d" => Some(Self::AdaptiveAvgPool2D),
368 "tensor.global_avgpool" => Some(Self::GlobalAvgPool),
369 "tensor.lstm_cell" => Some(Self::LSTMCell),
370 "tensor.gru_cell" => Some(Self::GRUCell),
371 "tensor.rnn_cell" => Some(Self::RNNCell),
372 "tensor.einsum" => Some(Self::Einsum),
373 "tensor.fft" => Some(Self::FFT),
374 "tensor.ifft" => Some(Self::IFFT),
375 "tensor.svd" => Some(Self::SVD),
376 "tensor.eig" => Some(Self::Eig),
377 "tensor.solve" => Some(Self::Solve),
378 "tensor.topk" => Some(Self::TopK),
379 "tensor.sort" => Some(Self::Sort),
380 "tensor.cumsum" => Some(Self::Cumsum),
381 "tensor.where" => Some(Self::Where),
382 "tensor.clamp" => Some(Self::Clamp),
383 "tensor.sparse_matmul" => Some(Self::SparseMatMul),
384 "tensor.sparse_embedding" => Some(Self::SparseEmbedding),
385 "tensor.quantize" => Some(Self::Quantize),
386 "tensor.dequantize" => Some(Self::Dequantize),
387 "tensor.quantize_int4" => Some(Self::QuantizeInt4),
388 "tensor.dequantize_int4" => Some(Self::DequantizeInt4),
389 "tensor.quantize_fp8" => Some(Self::QuantizeFp8),
390 "tensor.dequantize_fp8" => Some(Self::DequantizeFp8),
391 "tensor.unet_down_block" => Some(Self::UNetDownBlock),
392 "tensor.unet_up_block" => Some(Self::UNetUpBlock),
393 "tensor.timestep_embedding" => Some(Self::TimestepEmbedding),
394 "tensor.gnn_message_passing" => Some(Self::GNNMessagePassing),
395 "tensor.gnn_global_pooling" => Some(Self::GNNGlobalPooling),
396 "tensor.checkpoint" => Some(Self::Checkpoint),
397 "tensor.offload" => Some(Self::Offload),
398 "tensor.grad_accumulate" => Some(Self::GradAccumulate),
399 "tensor.grad_matmul" => Some(Self::GradMatMul),
400 "tensor.grad_relu" => Some(Self::GradReLU),
401 "tensor.grad_softmax" => Some(Self::GradSoftmax),
402 "tensor.grad_layernorm" => Some(Self::GradLayerNorm),
403 "tensor.grad_attention" => Some(Self::GradAttention),
404 "tensor.grad_conv2d" => Some(Self::GradConv2D),
405 "tensor.grad_linear" => Some(Self::GradLinear),
406 "tensor.grad_gelu" => Some(Self::GradGeLU),
407 "tensor.parallel_split" => Some(Self::ParallelSplit),
408 "tensor.parallel_allreduce" => Some(Self::ParallelAllReduce),
409 "tensor.pipeline_send" => Some(Self::PipelineSend),
410 "tensor.pipeline_receive" => Some(Self::PipelineReceive),
411 "tensor.fused_matmul_bias_relu" => Some(Self::FusedMatMulBiasReLU),
412 "tensor.fused_matmul_bias" => Some(Self::FusedMatMulBias),
413 "tensor.fused_linear_gelu" => Some(Self::FusedLinearGeLU),
414 "tensor.fused_attention_layernorm" => Some(Self::FusedAttentionLayerNorm),
415 "tensor.fused_linear_silu" => Some(Self::FusedLinearSiLU),
416 "tensor.fused_conv_batchnorm_relu" => Some(Self::FusedConvBatchNormReLU),
417 _ => None,
418 }
419 }
420
421 pub fn num_inputs(&self) -> (usize, usize) {
422 match self {
423 Self::Neg
425 | Self::ReLU
426 | Self::GeLU
427 | Self::SiLU
428 | Self::Sigmoid
429 | Self::Tanh
430 | Self::LeakyReLU
431 | Self::ELU
432 | Self::Mish
433 | Self::HardSwish
434 | Self::HardSigmoid
435 | Self::Reshape
436 | Self::Transpose
437 | Self::Squeeze
438 | Self::Unsqueeze
439 | Self::Permute
440 | Self::Expand
441 | Self::Slice
442 | Self::Pad
443 | Self::Tile
444 | Self::Quantize
445 | Self::Dequantize
446 | Self::QuantizeInt4
447 | Self::DequantizeInt4
448 | Self::QuantizeFp8
449 | Self::DequantizeFp8
450 | Self::Offload
451 | Self::Checkpoint
452 | Self::GradReLU
453 | Self::GradGeLU
454 | Self::Softmax
455 | Self::Cumsum
456 | Self::Sort
457 | Self::TopK
458 | Self::FFT
459 | Self::IFFT
460 | Self::SVD
461 | Self::Eig
462 | Self::GlobalAvgPool
463 | Self::AdaptiveAvgPool2D
464 | Self::GNNGlobalPooling => (1, 1),
465
466 Self::Add
468 | Self::Sub
469 | Self::Mul
470 | Self::Div
471 | Self::MatMul
472 | Self::SparseMatMul
473 | Self::GradMatMul
474 | Self::Embedding
475 | Self::SparseEmbedding
476 | Self::Conv2D
477 | Self::Conv1D
478 | Self::Conv3D
479 | Self::ConvTranspose2D
480 | Self::DepthwiseConv2D
481 | Self::DilatedConv2D
482 | Self::MaxPool2D
483 | Self::AvgPool2D
484 | Self::Solve
485 | Self::GradConv2D
486 | Self::Concat => (2, 2),
487
488 Self::Linear
490 | Self::FusedMatMulBias
491 | Self::FusedLinearGeLU
492 | Self::FusedMatMulBiasReLU
493 | Self::FusedLinearSiLU
494 | Self::Where
495 | Self::Clamp
496 | Self::GradLinear => (3, 3),
497
498 Self::Attention
500 | Self::MultiHeadAttention
501 | Self::MultiQueryAttention
502 | Self::GroupedQueryAttention
503 | Self::FlashAttention
504 | Self::SlidingWindowAttention
505 | Self::CrossAttention
506 | Self::GradAttention => (3, 4),
507 Self::PagedAttention => (3, 5),
508 Self::FusedAttentionLayerNorm => (3, 5),
509
510 Self::LayerNorm
512 | Self::RMSNorm
513 | Self::GroupNorm
514 | Self::InstanceNorm
515 | Self::GradLayerNorm => (2, 3),
516 Self::BatchNorm | Self::FusedConvBatchNormReLU => (3, 5),
517
518 Self::LSTMCell | Self::GRUCell | Self::RNNCell => (2, 2),
520
521 Self::GNNMessagePassing => (2, 3),
523
524 Self::UNetDownBlock | Self::UNetUpBlock => (2, 3),
526 Self::TimestepEmbedding => (1, 1),
527
528 Self::MoEDispatch => (2, 3),
530 Self::MoECombine => (2, 3),
531
532 Self::Constant | Self::Zeros | Self::Ones | Self::Arange | Self::Full => (0, 0),
534
535 Self::Einsum => (1, usize::MAX),
537
538 Self::GradAccumulate
540 | Self::GradSoftmax
541 | Self::ParallelSplit
542 | Self::ParallelAllReduce
543 | Self::PipelineSend
544 | Self::PipelineReceive
545 | Self::Gather
546 | Self::Scatter
547 | Self::Split => (1, usize::MAX),
548 }
549 }
550
551 pub fn flops_formula(&self) -> &'static str {
553 match self {
554 Self::MatMul | Self::SparseMatMul => "2*M*N*K",
555 Self::Linear => "2*M*N*K + N (bias)",
556 Self::Add | Self::Sub | Self::Mul | Self::Div => "N (element count)",
557 Self::ReLU
558 | Self::Sigmoid
559 | Self::Tanh
560 | Self::LeakyReLU
561 | Self::ELU
562 | Self::HardSigmoid => "N",
563 Self::GeLU | Self::SiLU | Self::Mish | Self::HardSwish => "~8*N",
564 Self::Softmax => "5*N (exp + sum + div)",
565 Self::LayerNorm | Self::RMSNorm | Self::GroupNorm | Self::InstanceNorm => "7*N",
566 Self::BatchNorm => "5*N",
567 Self::Conv2D | Self::DepthwiseConv2D | Self::DilatedConv2D => "2*Cout*Cin*Kh*Kw*Oh*Ow",
568 Self::Conv1D => "2*Cout*Cin*K*Oout",
569 Self::Conv3D => "2*Cout*Cin*Kd*Kh*Kw*Od*Oh*Ow",
570 Self::Attention
571 | Self::MultiHeadAttention
572 | Self::GroupedQueryAttention
573 | Self::MultiQueryAttention
574 | Self::FlashAttention
575 | Self::SlidingWindowAttention
576 | Self::CrossAttention => "2*B*H*(S^2*D + S*D^2)",
577 Self::LSTMCell => "4*(input_size+hidden)*hidden*2",
578 Self::GRUCell => "3*(input_size+hidden)*hidden*2",
579 Self::RNNCell => "(input_size+hidden)*hidden*2",
580 Self::FFT | Self::IFFT => "5*N*log2(N)",
581 Self::Einsum => "depends on equation",
582 Self::MaxPool2D | Self::AvgPool2D | Self::AdaptiveAvgPool2D | Self::GlobalAvgPool => {
583 "N (comparisons or additions)"
584 }
585 Self::Reshape
586 | Self::Transpose
587 | Self::Squeeze
588 | Self::Unsqueeze
589 | Self::Permute
590 | Self::Expand
591 | Self::Slice
592 | Self::Pad
593 | Self::Tile
594 | Self::Concat
595 | Self::Split
596 | Self::Gather
597 | Self::Scatter => "0 (no compute)",
598 _ => "varies",
599 }
600 }
601
602 #[inline]
604 pub fn is_zero_flop(&self) -> bool {
605 matches!(
606 self,
607 Self::Reshape
608 | Self::Transpose
609 | Self::Squeeze
610 | Self::Unsqueeze
611 | Self::Permute
612 | Self::Expand
613 | Self::Slice
614 | Self::Pad
615 | Self::Tile
616 | Self::Concat
617 | Self::Split
618 | Self::Gather
619 | Self::Scatter
620 | Self::Constant
621 | Self::Zeros
622 | Self::Ones
623 | Self::Arange
624 | Self::Full
625 | Self::Checkpoint
626 | Self::Offload
627 | Self::PipelineSend
628 | Self::PipelineReceive
629 | Self::ParallelSplit
630 | Self::ParallelAllReduce
631 )
632 }
633
634 #[inline]
636 pub fn is_activation(&self) -> bool {
637 matches!(
638 self,
639 Self::ReLU
640 | Self::GeLU
641 | Self::SiLU
642 | Self::Sigmoid
643 | Self::Tanh
644 | Self::LeakyReLU
645 | Self::ELU
646 | Self::Mish
647 | Self::HardSwish
648 | Self::HardSigmoid
649 )
650 }
651
652 #[inline]
654 pub fn is_attention(&self) -> bool {
655 matches!(
656 self,
657 Self::Attention
658 | Self::MultiHeadAttention
659 | Self::MultiQueryAttention
660 | Self::GroupedQueryAttention
661 | Self::FlashAttention
662 | Self::SlidingWindowAttention
663 | Self::CrossAttention
664 | Self::PagedAttention
665 )
666 }
667
668 #[inline]
670 pub fn is_convolution(&self) -> bool {
671 matches!(
672 self,
673 Self::Conv1D
674 | Self::Conv2D
675 | Self::Conv3D
676 | Self::ConvTranspose2D
677 | Self::DepthwiseConv2D
678 | Self::DilatedConv2D
679 )
680 }
681
682 #[inline]
684 pub fn is_normalisation(&self) -> bool {
685 matches!(
686 self,
687 Self::LayerNorm
688 | Self::RMSNorm
689 | Self::BatchNorm
690 | Self::GroupNorm
691 | Self::InstanceNorm
692 )
693 }
694
695 #[inline]
697 pub fn is_fused(&self) -> bool {
698 matches!(
699 self,
700 Self::FusedMatMulBiasReLU
701 | Self::FusedMatMulBias
702 | Self::FusedLinearGeLU
703 | Self::FusedAttentionLayerNorm
704 | Self::FusedLinearSiLU
705 | Self::FusedConvBatchNormReLU
706 )
707 }
708
709 #[inline]
711 pub fn is_gradient(&self) -> bool {
712 matches!(
713 self,
714 Self::GradMatMul
715 | Self::GradReLU
716 | Self::GradSoftmax
717 | Self::GradLayerNorm
718 | Self::GradAttention
719 | Self::GradConv2D
720 | Self::GradLinear
721 | Self::GradGeLU
722 )
723 }
724}
725
726#[cfg(test)]
727mod tests {
728 use super::*;
729
730 #[test]
731 fn test_op_name_roundtrip() {
732 for op in &[
733 TensorOp::MatMul,
734 TensorOp::ReLU,
735 TensorOp::Attention,
736 TensorOp::Softmax,
737 ] {
738 let name = op.name();
739 let recovered = TensorOp::from_name(name).unwrap();
740 assert_eq!(op, &recovered);
741 }
742 }
743
744 #[test]
745 fn test_all_ops_have_names() {
746 let ops = vec![
747 TensorOp::Add,
748 TensorOp::Sub,
749 TensorOp::Mul,
750 TensorOp::Div,
751 TensorOp::MatMul,
752 TensorOp::Linear,
753 TensorOp::ReLU,
754 TensorOp::GeLU,
755 TensorOp::Softmax,
756 TensorOp::LayerNorm,
757 TensorOp::Attention,
758 ];
759 for op in ops {
760 assert!(!op.name().is_empty());
761 assert!(TensorOp::from_name(op.name()).is_some());
762 }
763 }
764}