| Torch Operator Name | Eager Mode Operator | Map Description & Graph Fusion Description | HBIR Operator Name | BPU Support Constraints |
|---|---|---|---|---|
| torch.acos | horizon.nn.Acos | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.acosh | horizon.nn.Acosh | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.add torch.Tensor.add | torch.nn.quantized.FloatFunctional OR horizon.nn.quantized.FloatFunctional | if alpha == 1: func.func @forward(%arg0, %arg1){ %0 = "hbir.add"(%arg0, %arg1) return %0 } | hbir.add | lhs: Type: int8, int16, int32, if type is int32, this hbir.add op must be fusible to a Conv op Shape: [*] rhs: Same as lhs output: Same as lhs |
| if alpha != 1: func.func @forward(%arg0, %arg1){ %0 = "hbir.constant"() %1 = "hbir.mul"(%arg1, %0) %2 = "hbir.add"(%arg0, %1) return %2 } | hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | ||
| hbir.add | lhs: Type: int8, int16, int32, if type is int32, this hbir.add op must be fusible to a Conv op Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| torch.argmax torch.Tensor.argmax | None | func.func @forward(%arg0){ %0 = "hbir.reduce_argmax"(%arg0) return %0 } | hbir.reduce_argmax | input: Type: int8, int16 Shape: [*] output: Same as input, but output can be of type int32 or int64, as long as the size of the reduced axis can be represented using an int16 number |
| torch.argmin torch.Tensor.argmin | None | func.func @forward(%arg0){ %0 = "hbir.reduce_argmin"(%arg0) return %0 } | hbir.reduce_argmin | TBD |
| torch.asin | horizon.nn.Asin | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.asinh | horizon.nn.Asinh | if qat: func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "hbir.max"(%arg0, %0) %2 = "hbir.clip"(%1) %3 = "qnt.quantize"(%2) %4 = "hbir.constant"() %5 = "b30.lut"(%3, %4) %6 = "qnt.dequantize"(%5) %7 = "qnt.const_fake_quant"(%6) return %7 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| hbir.max | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| hbir.clip | input: Type: int8, int16 Shape: [*] output: Same as input | |||
| torch.atan | horizon.nn.Atan | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.atanh | horizon.nn.Atan | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.ceil | horizon.nn.Ceil | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.clamp torch.clip torch.Tensor.clamp torch.Tensor.clip | if isinstance(args, scalar): func.func @forward(%arg0, %arg1, %arg2){ %0 = "hbir.clip"(%arg0) return %0 } | hbir.clip | input: Type: int8, int16 Shape: [*] output: Same as input | |
| if isinstance(args, Tensor): func.func @forward(%arg0, %arg1, %arg2){ %0 = "hbir.max"(%arg0, %arg1) %1 = "hbir.min"(%0, %arg2) return %1 } | hbir.max | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | ||
| hbir.min | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| torch.cat torch.concat torch.concatenate | torch.nn.quantized.FloatFunctional OR horizon.nn.quantized.FloatFunctional | func.func @forward(%arg0){ %0 = "hbir.concat"(%arg0) return %0 } | hbir.concat | inputs: Arg Number: inputs number ∈ [1, 1024] Dim: all dims < 131072 size < 2G output: same as inputs |
| torch.cos | horizon.nn.Cos | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.cosh | horizon.nn.Cosh | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.div | horizon.nn.Div | if qat: func.func @forward(%arg0, %arg1){ %0 = "qnt.quantize"(%arg1) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) %5 = "hbir.mul"(%arg0, %4) %6 = "qnt.const_fake_quant"(%5) return %6 } else: func.func @forward(%arg0, %arg1){ %0 = "hbir.div"(%arg0, %arg1) return %0 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| torch.eq torch.Tensor.eq | func.func @forward(%arg0, %arg1){ %0 = "hbir.equal"(%arg0, %arg1) return %0 } | hbir.equal | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Type: bool8 | |
| torch.gt torch.greater torch.Tensor.gt torch.Tensor.greater | func.func @forward(%arg0, %arg1){ %0 = "hbir.greater"(%arg0, %arg1) return %0 } | hbir.greater | TBD | |
| torch.lt torch.less torch.Tensor.lt torch.Tensor.less | func.func @forward(%arg0, %arg1){ %0 = "hbir.less"(%arg0, %arg1) return %0 } | hbir.less | TBD | |
| torch.erf | horizon.nn.Erf | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.exp | horizon.nn.Exp | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.Tensor.expand | func.func @forward(%arg0){ %0 = "hbir.reshape"(%arg0) %1 = "hbir.concat"(%0, %0, %0) return %1 } | hbir.reshape | inputs: no limits output: same as inputs | |
| hbir.concat | inputs: Arg Number: inputs number ∈ [1, 1024] Dim: all dims < 131072 size < 2G output: same as inputs | |||
| torch.flatten torch.Tensor.flatten | None | func.func @forward(%arg0){ %0 = "hbir.reshape"(%arg0) return %0 } | hbir.reshape | inputs: no limits output: same as inputs |
| torch.floor | horizon.nn.Floor | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.remainder | horizon.nn.Remainder | func.func @forward(%arg0, %arg1) { %0 = "hbir.mod"(%arg0, %arg1) return %0 } | hbir.mod | TBD |
| torch.gather torch.Tensor.gather | func.func @forward(%arg0, %arg1){ %0 = "hbir.gather"(%arg0, %arg1) return %0 } | hbir.gather | Unsupported | |
| torch.index_select torch.Tensor.index_select | None | func.func @forward(%arg0){ %0 = "hbir.index"(%arg0) return %0 } | hbir.index | TBD |
| torch.log | horizon.nn.HardLog | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.Tensor.masked_fill | None | func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "hbir.constant"() %2 = "hbir.where"(%0, %1, %arg0) return %2 } | hbir.where | TBD |
| torch.matmul | horizon.nn.quantized.FloatFunctional | func.func @forward(%arg0, %arg1){ %0 = "hbir.matmul"(%arg0, %arg1) return %0 } | hbir.matmul | lhs: Type: int8, int16; lhs and rhs cannot both be int16 Shape: [*,M,C] Dim: * ∈ [1, 4096], M,C ∈ [1, 8192] rhs: Type: int8, int16; lhs and rhs cannot both be int16 Shape: [*,C,N] Dim: * ∈ [1, 4096]; C,N ∈ [1, 8192] output: Type: int8, int16, int32 Shape: [*,M,N] Other constraints: same as lhs |
| torch.max torch.Tensor.max | if dim is None: func.func @forward(%arg0){ %0 = "hbir.reduce_max"(%arg0) return %0 } | hbir.reduce_max | input: Type: int8, int16 Shape: [*] output: Same as input | |
| if dim is not None: func.func @forward(%arg0){ %0 = "hbir.reduce_max"(%arg0) %1 = "hbir.reduce_argmax"(%arg0) return %0 } | hbir.reduce_max | input: Type: int8, int16 Shape: [*] output: Same as input | ||
| hbir.reduce_argmax | input: Type: int8, int16 Shape: [*] output: Same as input, but output can be of type int32 or int64, as long as the size of the reduced axis can be represented using an int16 number | |||
| if give two tensors: func.func @forward(%arg0, %arg1){ %0 = "hbir.max"(%arg0, %arg1) return %0 } | hbir.max | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | ||
| torch.mean | horizon.nn.quantized.FloatFunctional | func.func @forward(%arg0){ %0 = "hbir.reduce_mean"(%arg0) return %0 } | hbir.reduce_mean | input: Type: int8, int16 Shape: [*] Dim: reduce axis dim size ∈ [1, 16384] output: Same as input |
| torch.min torch.Tensor.min | if dim is None: func.func @forward(%arg0){ %0 = "hbir.reduce_min"(%arg0) return %0 } | hbir.reduce_min | input: Type: int8, int16 Shape: [*] output: Same as input | |
| if dim is not None: func.func @forward(%arg0){ %0 = "hbir.reduce_min"(%arg0) %1 = "hbir.reduce_argmin"(%arg0) return %0 } | hbir.reduce_min | input: Type: int8, int16 Shape: [*] output: Same as input | ||
| hbir.reduce_argmin | TBD | |||
| if give two tensors: func.func @forward(%arg0, %arg1){ %0 = "hbir.min"(%arg0, %arg1) return %0 } | hbir.min | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | ||
| torch.mul torch.Tensor.mul | torch.nn.quantized.FloatFunctional or horizon.nn.quantized.FloatFunctional | func.func @forward(%arg0, %arg1){ %0 = "hbir.mul"(%arg0, %arg1) return %0 } | hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs |
| torch.neg torch.negative torch.Tensor.neg torch.Tensor.negative | None | func.func @forward(%arg0){ %0 = "hbir.neg"(%arg0) return %0 } | hbir.neg | TBD |
| torch.permute torch.Tensor.permute | func.func @forward(%arg0){ %0 = "hbir.transpose"(%arg0) return %0 } | hbir.transpose | inputs: no limits output: same as inputs | |
| torch.pow | horizon.nn.Pow | if exponent == 2: func.func @forward(%arg0){ %0 = "hbir.mul"(%arg0, %arg0) return %0 } | hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs |
| if exponent != 2 and float: func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "hbir.pow"(%arg0, %0) return %1 } | hbir.pow | TBD | ||
| if exponent != 2 and qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 | ||
| torch.reciprocal | horizon.nn.Reciprocal | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.remainder | horizon.nn.Remainder | func.func @forward(%arg0, %arg1) { %0 = "hbir.mod"(%arg0, %arg1) return %0 } | hbir.mod | TBD |
| torch.repeat torch.Tensor.repeat | func.func @forward(%arg0){ %0 = "hbir.tile"(%arg0) return %0 } | hbir.tile | inputs: no limits output: same as inputs | |
| torch.reshape torch.Tensor.reshape torch.view torch.Tensor.view | None | func.func @forward(%arg0){ %0 = "hbir.reshape"(%arg0) return %0 } | hbir.reshape | inputs: no limits output: same as inputs |
| torch.scatter torch.Tensor.scatter | horizon.nn.Scatter | func.func @forward(%arg0, %arg1, %arg2){ %0 = "hbir.scatter_elements"(%arg0, %arg1, %arg2) return %0 } | hbir.scatter_elements | TBD |
| torch.sign torch.Tensor.sign | None | func.func @forward(%arg0){ %0 = "hbir.sign"(%arg0) return %0 } | hbir.sign | TBD |
| torch.sin | horizon.nn.Sin | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.sinh | horizon.nn.Sinh | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.split | func.func @forward(%arg0){ %0 = "hbir.slice"(%arg0) %1 = "hbir.slice"(%arg0) %2 = "hbir.slice"(%arg0) %3 = "hbir.slice"(%arg0) return %0, %1, %2, %3 } | hbir.slice | input: Dim: all dims < 2097152 output: Same as input | |
| torch.sqrt | horizon.nn.Sqrt | if qat: func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "hbir.max"(%arg0, %0) %2 = "hbir.clip"(%1) %3 = "qnt.quantize"(%2) %4 = "hbir.constant"() %5 = "b30.lut"(%3, %4) %6 = "qnt.dequantize"(%5) %7 = "qnt.const_fake_quant"(%6) return %7 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| hbir.max | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| hbir.clip | input: Type: int8, int16 Shape: [*] output: Same as input | |||
| torch.squeeze torch.Tensor.squeeze | func.func @forward(%arg0){ %0 = "hbir.reshape"(%arg0) return %0 } | hbir.reshape | inputs: no limits output: same as inputs | |
| torch.sub | horizon.nn.quantized.FloatFunctional | if alpha == 1: func.func @forward(%arg0, %arg1){ %0 = "hbir.sub"(%arg0, %arg1) return %0 } | hbir.sub | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs |
| if alpha != 1: func.func @forward(%arg0, %arg1){ %0 = "hbir.constant"() %1 = "hbir.mul"(%arg1, %0) %2 = "hbir.sub"(%arg0, %1) return %2 } | hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | ||
| hbir.sub | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| torch.sum | horizon.nn.quantized.FloatFunctional | func.func @forward(%arg0){ %0 = "hbir.reduce_sum"(%arg0) return %0 } | hbir.reduce_sum | input: Type: int8, int16 Shape: [*] Dim: reduce axis dim size ∈ [1, 16384] output: Same as input |
| torch.tan | horizon.nn.Tan | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.tanh | horizon.nn.Tanh | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.to torch.float | None | func.func @forward(%arg0){ %0 = "hbir.cast"(%arg0) return %0 } | hbir.cast | TBD |
| torch.topk torch.Tensor.topk | func.func @forward(%arg0){ %values, %indices = "hbir.topk"(%arg0) return %values, %indices } | hbir.topk | Unsupported | |
| torch.transpose torch.Tensor.transpose | func.func @forward(%arg0){ %0 = "hbir.transpose"(%arg0) return %0 } | hbir.transpose | inputs: no limits output: same as inputs | |
| torch.tril | None | func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "hbir.constant"() %2 = "hbir.where"(%0, %arg0, 1) return %2 } | hbir.where | TBD |
| torch.triu | None | func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "hbir.constant"() %2 = "hbir.where"(%0, %arg0, 1) return %2 } | hbir.where | TBD |
| torch.unsqueeze torch.Tensor.unsqueeze | func.func @forward(%arg0){ %0 = "hbir.reshape"(%arg0) return %0 } | hbir.reshape | inputs: no limits output: same as inputs | |
| torch.where torch.Tensor.where | horizon.nn.Where | func.func @forward(%arg0, %arg1){ %0 = "hbir.constant"() %1 = "hbir.where"(%0, %arg0, %arg1) return %1 } | hbir.where | TBD |
| torch.zeros_like torch.ones_like torch.full_like torch.rand_like | None | func.func @forward(%arg0){ %0 = "hbir.constant"() return %0 } | hbir.constant | None |
| torch.nn.functional.adaptive_avg_pool1d torch.nn.AdaptiveAvgPool1d | torch.nn.AdaptiveAvgPool1d | func.func @forward(%arg0){ %0 = "hbir.reshape"(%arg0) %1 = "hbir.avg_pool2d"(%0) %2 = "hbir.reshape"(%1) return %2 } | hbir.reshape | inputs: no limits output: same as inputs |
| hbir.avg_pool2d | input: Type: int8, int16 Shape: [*,H,W,C] output: Same as input kernel: Shape: [KH,KW] Dim: KH, KW ∈ [1, 256] stride: Shape: [SH,SW] Dim: SH, SW ∈ [1, 256] pad: Shape: [PN,PH,PW,PC] PN,PH,PW,PC ∈ [-3, 256] | |||
| torch.nn.functional.adaptive_avg_pool2d torch.nn.AdaptiveAvgPool2d | torch.nn.AdaptiveAvgPool2d | func.func @forward(%arg0){ %0 = "hbir.transpose"(%arg0) %1 = "hbir.avg_pool2d"(%0) %2 = "hbir.transpose"(%1) return %2 } | hbir.transpose | inputs: no limits output: same as inputs |
| hbir.avg_pool2d | input: Type: int8, int16 Shape: [*,H,W,C] output: Same as input kernel: Shape: [KH,KW] Dim: KH, KW ∈ [1, 256] stride: Shape: [SH,SW] Dim: SH, SW ∈ [1, 256] pad: Shape: [PN,PH,PW,PC] PN,PH,PW,PC ∈ [-3, 256] | |||
| torch.nn.functional.affine_grid | func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "hbir.transpose"(%arg0) %2 = "hbir.matmul"(%0, %1) %3 = "hbir.reshape"(%2) return %3 } | hbir.transpose | inputs: no limits output: same as inputs | |
| hbir.matmul | lhs: Type: int8, int16; lhs and rhs cannot both be int16 Shape: [*,M,C] Dim: * ∈ [1, 4096], M,C ∈ [1, 8192] rhs: Type: int8, int16; lhs and rhs cannot both be int16 Shape: [*,C,N] Dim: * ∈ [1, 4096]; C,N ∈ [1, 8192] output: Type: int8, int16, int32 Shape: [*,M,N] Other constraints: same as lhs | |||
| hbir.reshape | inputs: no limits output: same as inputs | |||
| torch.nn.functional.avg_pool2d torch.nn.AvgPool2d | func.func @forward(%arg0){ %0 = "hbir.transpose"(%arg0) %1 = "hbir.avg_pool2d"(%0) %2 = "hbir.transpose"(%1) return %2 } | hbir.transpose | inputs: no limits output: same as inputs | |
| hbir.avg_pool2d | input: Type: int8, int16 Shape: [*,H,W,C] output: Same as input kernel: Shape: [KH,KW] Dim: KH, KW ∈ [1, 256] stride: Shape: [SH,SW] Dim: SH, SW ∈ [1, 256] pad: Shape: [PN,PH,PW,PC] PN,PH,PW,PC ∈ [-3, 256] | |||
| torch.nn.functional.dropout torch.nn.Dropout torch.nn.functional.dropout2d torch.nn.Dropout2d | torch.nn.Dropout | func.func @forward(%arg0){ return %arg0 } | TBD | TBD |
| torch.nn.Embedding | None | func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "hbir.reshape"(%arg0) %2 = "hbir.gather_nd"(%0, %1) %3 = "hbir.reshape"(%2) return %3 } | hbir.gather_nd | TBD |
| hbir.reshape | inputs: no limits output: same as inputs | |||
| torch.nn.functional.gelu torch.nn.GELU | torch.nn.GELU | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.nn.functional.glu torch.nn.GLU | torch.nn.GLU | module { func.func @forward(%arg0){ %0 = "qnt.const_fake_quant"(%arg0) %1 = "hbir.slice"(%0) %2 = "hbir.slice"(%0) %3 = "qnt.quantize"(%2) %4 = "hbir.constant"() %5 = "b25.lut"(%3, %4) %6 = "qnt.dequantize"(%5) %7 = "qnt.const_fake_quant"(%6) %8 = "hbir.mul"(%1, %7) %9 = "qnt.const_fake_quant"(%8) return %9 } } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| hbir.slice | input: Dim: all dims < 2097152 output: Same as input | |||
| hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| torch.nn.functional.grid_sample | func.func @forward(%arg0, %arg1){ %0 = "hbir.transpose"(%arg0) %1 = "hbir.grid_sample"(%0, %arg1) %2 = "hbir.transpose"(%1) return %2 } | hbir.transpose | inputs: no limits output: same as inputs | |
| hbir.grid_sample | input: Type: int8 Shape: [*,H,W,C] Dim: H,W ∈ [1, 1024]; H\*W ≤ 720\*1024; other dims ∈ [1, 65536] grid: Type: int16 Shape: [*,H,W,2] output: Same as input except Dim constraints | |||
| torch.nn.functional.hardsigmoid torch.nn.HardSigmoid | torch.nn.HardSigmoid | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.nn.functional.interpolate torch.nn.Upsample torch.nn.UpsamplingNearest2d torch.nn.UpsamplingBilinear2d | func.func @forward(%arg0){ %0 = "hbir.transpose"(%arg0) %1 = "hbir.resize2d"(%0) %2 = "hbir.transpose"(%1) return %2 } | hbir.transpose | inputs: no limits output: same as inputs | |
| hbir.resize2d | input: Type: int8 Shape: [*,H,W,C] output: Same as input | |||
| torch.nn.functional.leaky_relu torch.nn.LeakyReLU | torch.nn.LeakyReLU | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.nn.functional.pad torch.nn.ConstantPad1d torch.nn.ConstantPad2d torch.nn.ConstantPad3d torch.nn.ReplicationPad1d torch.nn.ReplicationPad2d torch.nn.ReplicationPad3d torch.nn.ZeroPad2d | func.func @forward(%arg0){ %0 = "hbir.pad"(%arg0) return %0 } | hbir.pad | input: Type: int64, uint64 and f64 are not supported when expansionMode is 'constant' else no constraints Dim: all dims < 737280 when expansionMode is not 'constant' else no constraints output: Same as input | |
| torch.nn.functional.pixel_shuffle torch.nn.PixelShuffle | func.func @forward(%arg0){ %0 = "hbir.reshape"(%arg0) %1 = "hbir.transpose"(%0) %2 = "hbir.reshape"(%1) return %2 } | hbir.reshape | inputs: no limits output: same as inputs | |
| hbir.transpose | inputs: no limits output: same as inputs | |||
| torch.nn.functional.pixel_unshuffle torch.nn.PixelUnshuffle | func.func @forward(%arg0){ %0 = "hbir.reshape"(%arg0) %1 = "hbir.transpose"(%0) %2 = "hbir.reshape"(%1) return %2 } | hbir.reshape | inputs: no limits output: same as inputs | |
| hbir.transpose | inputs: no limits output: same as inputs | |||
| torch.nn.functional.relu torch.nn.ReLU | torch.nn.ReLU | func.func @forward(%arg0){ %0 = "hbir.relu"(%arg0) return %0 } | hbir.relu | input: Type: int8, int16, int32 Shape: [*] output: Same as input |
| torch.nn.functional.relu6(fused) torch.nn.ReLU6(fused) | torch.nn.ReLU6 | func.func @forward(%arg0){ %0 = "hbir.clip"(%arg0) return %0 } | hbir.clip | input: Type: int8, int16 Shape: [*] output: Same as input |
| torch.nn.functional.silu torch.nn.SiLU | torch.nn.SiLU | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.nn.functional.softmax torch.nn.Softmax | torch.nn.Softmax | if float: func.func @forward(%arg0) { %0 = "hbir.softmax"(%arg0) return %0 } | hbir.softmax | Unsupported |
| if qat: func.func @forward(%arg0){ %0 = "hbir.cast_type"(%arg0) %1 = "hbir.reduce_max"(%0) %2 = "hbir.reduce_argmax"(%0) %3 = "hbir.sub"(%0, %1) %4 = "qnt.const_fake_quant"(%3) %5 = "qnt.quantize"(%4) %6 = "hbir.constant"() %7 = "b30.lut"(%5, %6) %8 = "qnt.dequantize"(%7) %9 = "qnt.const_fake_quant"(%8) %10 = "hbir.reduce_sum"(%9) %11 = "qnt.const_fake_quant"(%10) %12 = "qnt.quantize"(%11) %13 = "hbir.constant"() %14 = "b30.lut"(%12, %13) %15 = "qnt.dequantize"(%14) %16 = "qnt.const_fake_quant"(%15) %17 = "hbir.mul"(%9, %16) %18 = "qnt.const_fake_quant"(%17) return %18 } | hbir.reduce_max | input: Type: int8, int16 Shape: [*] output: Same as input | ||
| hbir.reduce_argmax | input: Type: int8, int16 Shape: [*] output: Same as input, but output can be of type int32 or int64, as long as the size of the reduced axis can be represented using an int16 number | |||
| hbir.sub | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 | |||
| hbir.reduce_sum | input: Type: int8, int16 Shape: [*] Dim: reduce axis dim size ∈ [1, 16384] output: Same as input | |||
| hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| torch.nn.functional.softplus torch.nn.Softplus | None | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.nn.Conv2d | if float: func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "hbir.constant"() %2 = "hbir.transpose"(%arg0) %3 = "hbir.transpose"(%0) %4 = "hbir.conv2d"(%2, %3, %1) %5 = "hbir.transpose"(%4) return %5 } | hbir.transpose | inputs: no limits output: same as inputs | |
| hbir.conv2d | input: Type: int8, int16; input and weight cannot both be int16 Shape: [*,H,W,C] Dim: * ∈ [1, 4096]; H,W,C ∈ [1, 65536] weight: Type: int8, int16; input and weight cannot both be int16 Shape: [N,KH,KW,C] Dim: C ∈ [1, 8192]; KH,KW ∈ [1, 31]; N ∈ [1, 65536] if fout is the last layer of conv else [1, 8192] Size: KH\*KW\*C ∈ [1, 65536] bias: Type: f32 output: Type: int8, int16, int32 Other constraints: same as fin stride: Shape: [SH,SW] Dim: SH,SW ∈ [1, 256]; SH,SW ∈ {1} if dilation > 1 pad: Shape: [PN,PH,PW,PC] Dim: PN,PH,PW,PC ∈ [-1, 256] groupNum: fin.c is divisible by group number dilation: Shape: [DH,DW] Dim: DH,DW ∈ [1, 18] others: Don't support even stride when conv is a depthwise conv For each group, fin.c ∈ [1, 8192], KH\*KW\*fin.c ∈ [1, 65535], fin.c = C when group = 1 | |||
| if qat: func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "qnt.const_fake_quant"(%0) %2 = "hbir.constant"() %3 = "hbir.transpose"(%arg0) %4 = "hbir.transpose"(%1) %5 = "hbir.conv2d"(%3, %4, %2) %6 = "hbir.transpose"(%5) %7 = "qnt.const_fake_quant"(%6) return %7 } | hbir.transpose | inputs: no limits output: same as inputs | ||
| hbir.conv2d | input: Type: int8, int16; input and weight cannot both be int16 Shape: [*,H,W,C] Dim: * ∈ [1, 4096]; H,W,C ∈ [1, 65536] weight: Type: int8, int16; input and weight cannot both be int16 Shape: [N,KH,KW,C] Dim: C ∈ [1, 8192]; KH,KW ∈ [1, 31]; N ∈ [1, 65536] if fout is the last layer of conv else [1, 8192] Size: KH\*KW\*C ∈ [1, 65536] bias: Type: f32 output: Type: int8, int16, int32 Other constraints: same as fin stride: Shape: [SH,SW] Dim: SH,SW ∈ [1, 256]; SH,SW ∈ {1} if dilation > 1 pad: Shape: [PN,PH,PW,PC] Dim: PN,PH,PW,PC ∈ [-1, 256] groupNum: fin.c is divisible by group number dilation: Shape: [DH,DW] Dim: DH,DW ∈ [1, 18] others: Don't support even stride when conv is a depthwise conv For each group, fin.c ∈ [1, 8192], KH\*KW\*fin.c ∈ [1, 65535], fin.c = C when group = 1 | |||
| torch.nn.ConvTranspose2d | if float: func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "hbir.constant"() %2 = "hbir.transpose"(%arg0) %3 = "hbir.transpose"(%0) %4 = "hbir.conv2dtranspose"(%2, %3, %1) %5 = "hbir.transpose"(%4) return %5 } | hbir.transpose | inputs: no limits output: same as inputs | |
| hbir.conv2dtranspose | input: Type: int8, int16; input and weight cannot both be int16 Shape: [*,H,W,C] Dim: * ∈ [1, 128]; H,W ∈ [1, 65536]; C ∈ [1, 2048] weight: Type: int8, int16; input and weight cannot both be int16 Shape: [N,KH,KW,C] Dim: N,C ∈ [1, 2048]; KH,KW ∈ [1, 14] Size: KH\*KW\*C ∈ [1, 65536] bias: Type: f32 output: Same as input, the type additionally supports int32 stride: Shape: [SH,SW] Dim: SH,SW ∈ [1, 14]; SH < KH; SW < KW; pad: Shape: [PN,PH,PW,PC] Dim: PN,PH,PW,PC ∈ [0, 256] dilation: Shape: [DH,DW] Dim: DH,DW ∈ {1} | |||
| if qat: func.func @forward(%arg0){ %0 = "hbir.constant"() %1 = "qnt.const_fake_quant"(%0) %2 = "hbir.reshape"(%1) %3 = "hbir.transpose"(%2) %4 = "hbir.reshape"(%3) %5 = "hbir.constant"() %6 = "hbir.transpose"(%arg0) %7 = "hbir.transpose"(%4) %8 = "hbir.conv2dtranspose"(%6, %7, %5) %9 = "hbir.transpose"(%8) %10 = "qnt.const_fake_quant"(%9) return %10 } | hbir.transpose | inputs: no limits output: same as inputs | ||
| hbir.conv2dtranspose | input: Type: int8, int16; input and weight cannot both be int16 Shape: [*,H,W,C] Dim: * ∈ [1, 128]; H,W ∈ [1, 65536]; C ∈ [1, 2048] weight: Type: int8, int16; input and weight cannot both be int16 Shape: [N,KH,KW,C] Dim: N,C ∈ [1, 2048]; KH,KW ∈ [1, 14] Size: KH\*KW\*C ∈ [1, 65536] bias: Type: f32 output: Same as input, the type additionally supports int32 stride: Shape: [SH,SW] Dim: SH,SW ∈ [1, 14]; SH < KH; SW < KW; pad: Shape: [PN,PH,PW,PC] Dim: PN,PH,PW,PC ∈ [0, 256] dilation: Shape: [DH,DW] Dim: DH,DW ∈ {1} | |||
| torch.nn.Identity | func.func @forward(%arg0){ return %arg0 } | TBD | TBD | |
| torch.nn.LayerNorm | if float: func.func @forward(%arg0){ %0 = "hbir.layernorm"(%arg0) return %0 } | hbir.layernorm | TBD | |
| if qat: func.func @forward(%arg0){ %0 = "hbir.cast_type"(%arg0) %1 = "hbir.reduce_mean"(%0) %2 = "qnt.const_fake_quant"(%1) %3 = "hbir.sub"(%0, %2) %4 = "qnt.const_fake_quant"(%3) %5 = "hbir.mul"(%4, %4) %6 = "qnt.const_fake_quant"(%5) %7 = "hbir.reduce_mean"(%6) %8 = "qnt.const_fake_quant"(%7) %9 = "qnt.quantize"(%8) %10 = "hbir.constant"() %11 = "b30.lut"(%9, %10) %12 = "qnt.dequantize"(%11) %13 = "qnt.const_fake_quant"(%12) %14 = "hbir.mul"(%4, %13) %15 = "qnt.const_fake_quant"(%14) %16 = "hbir.constant"() %17 = "qnt.const_fake_quant"(%16) %18 = "hbir.mul"(%15, %17) %19 = "qnt.const_fake_quant"(%18) %20 = "hbir.constant"() %21 = "qnt.const_fake_quant"(%20) %22 = "hbir.add"(%19, %21) %23 = "qnt.const_fake_quant"(%22) return %23 } | hbir.reduce_mean | input: Type: int8, int16 Shape: [*] Dim: reduce axis dim size ∈ [1, 16384] output: Same as input | ||
| hbir.sub | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 | |||
| hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| hbir.add | lhs: Type: int8, int16, int32, if type is int32, this hbir.add op must be fusible to a Conv op Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| horizon.nn.LayerNorm | if float and dim is None: func.func @forward(%arg0){ %0 = "hbir.layernorm"(%arg0) return %0 } | hbir.layernorm | TBD | |
| if float and dim is not None: func.func @forward(%arg0){ %0 = "hbir.reduce_mean"(%arg0) %1 = "hbir.sub"(%arg0, %0) %2 = "hbir.mul"(%1, %1) %3 = "hbir.reduce_mean"(%2) %4 = "hbir.rsqrt"(%3) %5 = "hbir.mul"(%1, %4) %6 = "hbir.constant"() %7 = "hbir.mul"(%5, %6) %8 = "hbir.constant"() %9 = "hbir.add"(%7, %8) return %9 } | hbir.reduce_mean | input: Type: int8, int16 Shape: [*] Dim: reduce axis dim size ∈ [1, 16384] output: Same as input | ||
| hbir.sub | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| hbir.rsqrt | TBD | |||
| hbir.add | lhs: Type: int8, int16, int32, if type is int32, this hbir.add op must be fusible to a Conv op Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| if qat: func.func @forward(%arg0){ %0 = "hbir.cast_type"(%arg0) %1 = "hbir.reduce_mean"(%0) %2 = "qnt.const_fake_quant"(%1) %3 = "hbir.sub"(%0, %2) %4 = "qnt.const_fake_quant"(%3) %5 = "hbir.mul"(%4, %4) %6 = "qnt.const_fake_quant"(%5) %7 = "hbir.reduce_mean"(%6) %8 = "qnt.const_fake_quant"(%7) %9 = "qnt.quantize"(%8) %10 = "hbir.constant"() %11 = "b30.lut"(%9, %10) %12 = "qnt.dequantize"(%11) %13 = "qnt.const_fake_quant"(%12) %14 = "hbir.mul"(%4, %13) %15 = "qnt.const_fake_quant"(%14) %16 = "hbir.constant"() %17 = "qnt.const_fake_quant"(%16) %18 = "hbir.mul"(%15, %17) %19 = "qnt.const_fake_quant"(%18) %20 = "hbir.constant"() %21 = "qnt.const_fake_quant"(%20) %22 = "hbir.add"(%19, %21) %23 = "qnt.const_fake_quant"(%22) return %23 } | hbir.reduce_mean | input: Type: int8, int16 Shape: [*] Dim: reduce axis dim size ∈ [1, 16384] output: Same as input | ||
| hbir.sub | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 | |||
| hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| hbir.add | lhs: Type: int8, int16, int32, if type is int32, this hbir.add op must be fusible to a Conv op Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| torch.nn.MaxPool2d | func.func @forward(%arg0){ %0 = "hbir.transpose"(%arg0) %1 = "hbir.max_pool2d"(%0) %2 = "hbir.transpose"(%1) return %2 } | hbir.transpose | inputs: no limits output: same as inputs | |
| hbir.max_pool2d | input: Type: int8, int16 Shape: [*,H,W,C] output: Same as input kernel: Shape: [KH,KW] Dim: KH, KW ∈ [1, 256] stride: Shape: [SH,SW] Dim: SH, SW ∈ [1, 256] pad: Shape: [PN,PH,PW,PC] PN,PH,PW,PC ∈ [-3, 256] | |||
| torch.nn.MultiheadAttention | None | func.func @forward(%arg0, %arg1, %arg2, %arg3, %arg4){ %0 = "hbir.transpose"(%arg0) %1 = "hbir.transpose"(%arg1) %2 = "hbir.transpose"(%arg2) %3 = "hbir.constant"() %4 = "hbir.constant"() %5 = "hbir.linear"(%0, %3, %4) %6 = "hbir.constant"() %7 = "hbir.constant"() %8 = "hbir.linear"(%1, %6, %7) %9 = "hbir.constant"() %10 = "hbir.constant"() %11 = "hbir.linear"(%2, %9, %10) %12 = "hbir.constant"() %13 = "hbir.concat"(%8, %12) %14 = "hbir.constant"() %15 = "hbir.concat"(%11, %14) %16 = "hbir.pad"(%arg4) %17 = "hbir.pad"(%arg3) %18 = "hbir.reshape"(%5) %19 = "hbir.transpose"(%18) %20 = "hbir.reshape"(%13) %21 = "hbir.transpose"(%20) %22 = "hbir.reshape"(%15) %23 = "hbir.transpose"(%22) %24 = "hbir.constant"() %25 = "hbir.concat"(%21, %24) %26 = "hbir.constant"() %27 = "hbir.concat"(%23, %26) %28 = "hbir.pad"(%16) %29 = "hbir.pad"(%17) %30 = "hbir.reshape"(%28) %31 = "hbir.reshape"(%29) %32 = "hbir.logical_or"(%30, %31) %33 = "hbir.constant"() %34 = "hbir.constant"() %35 = "hbir.where"(%32, %34, %33) %36 = "hbir.constant"() %37 = "hbir.mul"(%19, %36) %38 = "hbir.transpose"(%25) %39 = "hbir.matmul"(%37, %38) %40 = "hbir.tile"(%35) %41 = "hbir.reshape"(%40) %42 = "hbir.add"(%39, %41) %43 = "hbir.softmax"(%42) %44 = "hbir.matmul"(%43, %27) %45 = "hbir.transpose"(%44) %46 = "hbir.reshape"(%45) %47 = "hbir.constant"() %48 = "hbir.constant"() %49 = "hbir.linear"(%46, %47, %48) %50 = "hbir.reshape"(%43) %51 = "hbir.reduce_mean"(%50) %52 = "hbir.transpose"(%49) return %52, %51 } | hbir.transpose | inputs: no limits output: same as inputs |
| hbir.linear | input: Type: int8 Shape: [*,C_in] Dim: *, C_in ∈ [1, 65536] weight: Type: int8 Shape: [C_out, C_in] Dim: C_in,C_out ∈ [1, 8192]; C_in\*C_out ∈ [1, 65536] bias: Type: f32 output: Type: int8, int16, int32 Other constraints: same as input | |||
| hbir.pad | input: Type: int64, uint64 and f64 are not supported when expansionMode is 'constant' else no constraints Dim: all dims < 737280 when expansionMode is not 'constant' else no constraints output: Same as input | |||
| hbir.reshape | inputs: no limits output: same as inputs | |||
| hbir.concat | inputs: Arg Number: inputs number ∈ [1, 1024] Dim: all dims < 131072 size < 2G output: same as inputs | |||
| hbir.logical_or | TBD | |||
| hbir.where | TBD | |||
| hbir.mul | lhs: Type: int8, int16 Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| hbir.matmul | lhs: Type: int8, int16; lhs and rhs cannot both be int16 Shape: [*,M,C] Dim: * ∈ [1, 4096], M,C ∈ [1, 8192] rhs: Type: int8, int16; lhs and rhs cannot both be int16 Shape: [*,C,N] Dim: * ∈ [1, 4096]; C,N ∈ [1, 8192] output: Type: int8, int16, int32 Shape: [*,M,N] Other constraints: same as lhs | |||
| hbir.tile | inputs: no limits output: same as inputs | |||
| hbir.add | lhs: Type: int8, int16, int32, if type is int32, this hbir.add op must be fusible to a Conv op Shape: [*] rhs: Same as lhs output: Same as lhs | |||
| hbir.softmax | Unsupported | |||
| hbir.reduce_mean | input: Type: int8, int16 Shape: [*] Dim: reduce axis dim size ∈ [1, 16384] output: Same as input | |||
| torch.nn.functional.selu torch.nn.SELU | torch.nn.SELU | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.nn.functional.sigmoid torch.nn.Sigmoid | torch.nn.Sigmoid | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.nn.Softplus | None | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.tanh torch.nn.Tanh | torch.nn.Tanh | if qat: func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 } | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 |
| torch.quantization.DeQuantStub | if float: func.func @forward(%arg0){ return %arg0 } | TBD | TBD | |
| if qat: func.func @forward(%arg0){ %0 = "qnt.barrier"(%arg0) return %0 } | qnt.barrier | TBD | ||
| torch.quantization.QuantStub | iffloat: func.func @forward(%arg0){ return %arg0 } | TBD | TBD | |
| if qat: func.func @forward(%arg0){ %0 = "qnt.const_fake_quant"(%arg0) return %0 } | qnt.const_fake_quant | TBD | ||
| horizon.nn.AnchorGenerator | func.func @forward(%arg0){ %0 = "hbir.constant"() return %0 } | hbir.constant | None | |
| horizon.nn.BaseGridGenerator | func.func @forward(%arg0){ %0 = "hbir.constant"() return %0 } | hbir.constant | None | |
| horizon.nn.GridSample | None | func.func @forward(%arg0, %arg1){ %0 = "hbir.transpose"(%arg0) %1 = "hbir.warp"(%0, %arg1) %2 = "hbir.transpose"(%1) return %2 } | hbir.warp | input: Type: int8 Shape: [*,H,W,C] Dim: H,W ∈ [1, 1024]; H\*W ≤ 720\*1024; other dims ∈ [1, 65536] grid: Type: int16 Shape: [*,H,W,2] output: Same as input except Dim constraints |
| hbir.transpose | inputs: no limits output: same as inputs | |||
| horizon.nn.SegmentLUT | func.func @forward(%arg0){ %0 = "qnt.quantize"(%arg0) %1 = "hbir.constant"() %2 = "b30.lut"(%0, %1) %3 = "qnt.dequantize"(%2) %4 = "qnt.const_fake_quant"(%3) return %4 | b30.lut | inputs: Type: int8, int16 outputs: If input is int8, output is int8; if input is int16, output is int8/int16 | |
| horizon.nn.functional.filter | func.func @forward(%arg0){ %0 = "hbir.transpose"(%arg0) %maxValue, %maxIndex, %filterCoord, %filterData = "hbir.filter"(%0) return %maxValue, %maxIndex, %filterCoord, %filterData } | hbir.transpose | inputs: no limits output: same as inputs | |
| hbir.filter | TBD | |||
| torch.Tensor.getitem | if use as slice: func.func @forward(%arg0){ %0 = "hbir.slice"(%arg0) %1 = "hbir.select"(%0) %2 = "hbir.reshape"(%1) return %2 } | hbir.slice | input: Dim: all dims < 2097152 output: Same as input | |
| hbir.select | TBD | |||
| hbir.reshape | inputs: no limits output: same as inputs | |||
| if use as index: func.func @forward(%arg0){ %0 = "hbir.select"(%arg0) %1 = "hbir.reshape"(%0) return %1 } | hbir.select | TBD | ||
| hbir.reshape | inputs: no limits output: same as inputs | |||
| torch.Tensor.setitem | horizon.nn.SetItem | func.func @forward(%arg0, %arg1){ %0 = "hbir.constant"() %1 = "hbir.reshape"(%arg1) %2 = "hbir.scatter_nd"(%arg0, %0, %1) return %2 } | hbir.scatter_nd | TBD |
| hbir.reshape | inputs: no limits output: same as inputs | |||
| torch.Tensor.clone torch.Tensor.contiguous torch.Tensor.detach | func.func @forward(%arg0){ return %arg0 } | TBD | TBD |