// Copyright 2026 The TensorFlow Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================== // RUN: litert-opt %s -split-input-file -tfl-raise-custom-ops="test-raise-tf-targets=tf.FakeQuantWithMinMaxVarsPerChannel,tf.FakeQuantWithMinMaxVars" -tfl-prepare-tf | FileCheck --dump-input=always %s // RUN: litert-opt %s -split-input-file -tfl-raise-custom-ops="test-raise-tf-targets=tf.FakeQuantWithMinMaxVarsPerChannel,tf.FakeQuantWithMinMaxVars" -tfl-prepare-tf=use-fake-quant-num-bits=true | FileCheck --check-prefix LOBIT --dump-input=always %s // CHECK-LABEL: fakeQuantPerChannelForActivation func.func @fakeQuantPerChannelForActivation(%arg0: tensor<8x4xf32>) -> (tensor<8x4xf32>) { %arg1 = arith.constant dense<[0.0, -1.0, 1.0, 0.0]> : tensor<4xf32> %arg2 = arith.constant dense<[255.0, 254.0, 256.0, 1.0e-9]> : tensor<4xf32> %0 = "tf.FakeQuantWithMinMaxVarsPerChannel"(%arg0, %arg1, %arg2) {num_bits = 5, narrow_range = false} : (tensor<8x4xf32>, tensor<4xf32>, tensor<4xf32>) -> tensor<8x4xf32> func.return %0 : tensor<8x4xf32> // CHECK: %[[fq:.*]] = "tf.FakeQuantWithMinMaxVarsPerChannel"(%arg0, %cst, %cst_0) // CHECK: %[[q:.*]] = "tfl.quantize"(%[[fq]]) <{qtype = tensor<8x4x!quant.uniform>}> // CHECK: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) // CHECK: return %[[dq]] } // ----- // CHECK-LABEL: fakeQuantForActivation func.func @fakeQuantForActivation(tensor<8xf32>) -> (tensor<8xf32>) { ^bb0(%arg0: tensor<8xf32>): %arg1 = arith.constant dense<0.0> : tensor %arg2 = arith.constant dense<255.0> : tensor %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %arg1, %arg2) {num_bits = 5, narrow_range = false} : (tensor<8xf32>, tensor, tensor) -> tensor<8xf32> func.return %0 : tensor<8xf32> // CHECK: %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst, %cst_0) // CHECK: %1 = "tfl.quantize"(%0) <{qtype = tensor<8x!quant.uniform>}> // CHECK: %2 = "tfl.dequantize"(%1) // CHECK: return %2 } // ----- // CHECK-LABEL: fakeQuantForActivationNoDuplication func.func @fakeQuantForActivationNoDuplication(tensor<8xf32>) -> (tensor<8x!quant.uniform>) { ^bb0(%arg0: tensor<8xf32>): %arg1 = arith.constant dense<0.0> : tensor %arg2 = arith.constant dense<255.0> : tensor %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %arg1, %arg2) {num_bits = 5, narrow_range = false} : (tensor<8xf32>, tensor, tensor) -> tensor<8xf32> %1 = "tfl.quantize"(%0) {qtype = tensor<8x!quant.uniform>} : (tensor<8xf32>) -> tensor<8x!quant.uniform> func.return %1 : tensor<8x!quant.uniform> // CHECK: %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst, %cst_0) <{narrow_range = false, num_bits = 5 : i64}> // CHECK: %1 = "tfl.quantize"(%0) <{qtype = tensor<8x!quant.uniform>}> // CHECK: return %1 } // ----- // CHECK-LABEL: WrappedFakeQuantFolded func.func @WrappedFakeQuantFolded() -> tensor<8xf32> { %in = arith.constant dense<0.0> : tensor<8xf32> %min = arith.constant dense<0.0> : tensor %max = arith.constant dense<255.0> : tensor %mini = "tf.Identity"(%min) : (tensor) -> tensor %maxi = "tf.Identity"(%max) : (tensor) -> tensor %rst = "tfl.custom_tf"(%in, %mini, %maxi) ({ ^bb0(%arg1: tensor<8xf32>, %arg2: tensor, %arg3: tensor): %2 = "tf.FakeQuantWithMinMaxVars"(%arg1, %arg2, %arg3) {num_bits = 5, narrow_range = false} : (tensor<8xf32>, tensor, tensor) -> tensor<8xf32> "tfl.yield"(%2) : (tensor<8xf32>) -> () }) {num_bits = 5, narrow_range = false} : (tensor<8xf32>, tensor, tensor) -> tensor<8xf32> func.return %rst : tensor<8xf32> // CHECK: %[[CONSTANT:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<8xf32>}> // CHECK: %[[QUANTIZE:.*]] = "tfl.quantize"(%[[CONSTANT]]) <{qtype = tensor<8x!quant.uniform>}> // CHECK: %[[DEQUANTIZE:.*]] = "tfl.dequantize"(%[[QUANTIZE]]) // CHECK: return %[[DEQUANTIZE]] : tensor<8xf32> } // ----- // CHECK-LABEL: fakeQuantFolded func.func @fakeQuantFolded() -> (tensor<8xf32>) { %in = arith.constant dense<0.0> : tensor<8xf32> %min = arith.constant dense<0.0> : tensor %max = arith.constant dense<255.0> : tensor %mini = "tf.Identity"(%min) : (tensor) -> tensor %maxi = "tf.Identity"(%max) : (tensor) -> tensor %rst = "tf.FakeQuantWithMinMaxVars"(%in, %mini, %maxi) {num_bits = 5, narrow_range = false} : (tensor<8xf32>, tensor, tensor) -> tensor<8xf32> func.return %rst : tensor<8xf32> // CHECK: %[[CONSTANT:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<8xf32>}> // CHECK: %[[QUANTIZE:.*]] = "tfl.quantize"(%[[CONSTANT]]) <{qtype = tensor<8x!quant.uniform>}> // CHECK: %[[DEQUANTIZE:.*]] = "tfl.dequantize"(%[[QUANTIZE]]) // CHECK: return %[[DEQUANTIZE]] : tensor<8xf32> } // ----- // CHECK-LABEL: fakeQuantFoldedWithoutIdentity func.func @fakeQuantFoldedWithoutIdentity() -> (tensor<8xf32>) { %in = arith.constant dense<0.0> : tensor<8xf32> %min = arith.constant dense<0.0> : tensor %max = arith.constant dense<255.0> : tensor %rst = "tf.FakeQuantWithMinMaxVars"(%in, %min, %max) {num_bits = 5, narrow_range = false} : (tensor<8xf32>, tensor, tensor) -> tensor<8xf32> func.return %rst : tensor<8xf32> // CHECK: %[[CONSTANT:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<8xf32>}> // CHECK: %[[QUANTIZE:.*]] = "tfl.quantize"(%[[CONSTANT]]) <{qtype = tensor<8x!quant.uniform>}> // CHECK: %[[DEQUANTIZE:.*]] = "tfl.dequantize"(%[[QUANTIZE]]) // CHECK: return %[[DEQUANTIZE]] : tensor<8xf32> } // ----- // CHECK-LABEL: fakeQuantFoldedWithCast func.func @fakeQuantFoldedWithCast() -> (tensor<8xf32>) { %in = arith.constant dense<0.0> : tensor<8xf32> %min = arith.constant dense<0.0> : tensor %max = arith.constant dense<255.0> : tensor %mini = "tf.Identity"(%min) : (tensor) -> tensor %maxi = "tf.Identity"(%max) : (tensor) -> tensor %minc = "tf.Cast"(%mini) : (tensor) -> tensor %maxc = "tf.Cast"(%maxi) : (tensor) -> tensor %rst = "tf.FakeQuantWithMinMaxVars"(%in, %minc, %maxc) {num_bits = 5, narrow_range = false} : (tensor<8xf32>, tensor, tensor) -> tensor<8xf32> func.return %rst : tensor<8xf32> // CHECK: %[[CONSTANT:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<8xf32>}> // CHECK: %[[QUANTIZE:.*]] = "tfl.quantize"(%[[CONSTANT]]) <{qtype = tensor<8x!quant.uniform>}> // CHECK: %[[DEQUANTIZE:.*]] = "tfl.dequantize"(%[[QUANTIZE]]) // CHECK: return %[[DEQUANTIZE]] : tensor<8xf32> } // ----- // CHECK-LABEL: fakeQuantNotFolded func.func @fakeQuantNotFolded(tensor<8xf32>, tensor, tensor) -> (tensor<8xf32>) { ^bb0(%arg0: tensor<8xf32>, %arg3: tensor, %arg4: tensor): %1 = "tf.FakeQuantWithMinMaxVars"(%arg0, %arg3, %arg4) {num_bits = 5, narrow_range = false} : (tensor<8xf32>, tensor, tensor) -> tensor<8xf32> func.return %1 : tensor<8xf32> // CHECK: %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %arg1, %arg2) // CHECK: return %0 : tensor<8xf32> } // ----- // CHECK-LABEL: fakeQuantFollowedByTranspose func.func @fakeQuantFollowedByTranspose(tensor<1x2xf32>, tensor, tensor) -> (tensor<2x1xf32>) { ^bb0(%arg0: tensor<1x2xf32>, %arg1: tensor, %arg2: tensor): %cst_0 = arith.constant dense<[1, 0]> : tensor<2xi32> %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %arg1, %arg2) {num_bits = 5, narrow_range = false} : (tensor<1x2xf32>, tensor, tensor) -> tensor<1x2xf32> %1 = "tf.Transpose"(%0, %cst_0): (tensor<1x2xf32>, tensor<2xi32>) -> tensor<2x1xf32> func.return %1 : tensor<2x1xf32> // CHECK: %cst = arith.constant // CHECK: %0 = "tf.Transpose"(%arg0, %cst) // CHECK: %1 = "tf.FakeQuantWithMinMaxVars"(%0, %arg1, %arg2) // CHECK: return %1 } // ----- // CHECK-LABEL: fakeQuantFollowedByTransposes func.func @fakeQuantFollowedByTransposes(tensor<1x2xf32>, tensor, tensor) -> (tensor<2x1xf32>, tensor<2x1xf32>) { ^bb0(%arg0: tensor<1x2xf32>, %arg1: tensor, %arg2: tensor): %cst_0 = arith.constant dense<[1, 0]> : tensor<2xi32> %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %arg1, %arg2) {num_bits = 5, narrow_range = false} : (tensor<1x2xf32>, tensor, tensor) -> tensor<1x2xf32> %1 = "tf.Transpose"(%0, %cst_0): (tensor<1x2xf32>, tensor<2xi32>) -> tensor<2x1xf32> %2 = "tf.Transpose"(%0, %cst_0): (tensor<1x2xf32>, tensor<2xi32>) -> tensor<2x1xf32> func.return %1, %2 : tensor<2x1xf32>, tensor<2x1xf32> // CHECK: %cst = arith.constant // CHECK: %[[FQ:.*]] = "tf.FakeQuantWithMinMaxVars"(%arg0, %arg1, %arg2) // CHECK: %[[T1:.*]] = "tf.Transpose"(%[[FQ]], %cst) // CHECK: %[[T2:.*]] = "tf.Transpose"(%[[FQ]], %cst) } // ----- // CHECK-LABEL: fakeQuantFollowedByReshape func.func @fakeQuantFollowedByReshape(tensor<1x2xf32>, tensor, tensor) -> (tensor<2x1xf32>) { ^bb0(%arg0: tensor<1x2xf32>, %arg1: tensor, %arg2: tensor): %cst_0 = arith.constant dense<[2, -1]> : tensor<2xi64> %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %arg1, %arg2) {num_bits = 5, narrow_range = false} : (tensor<1x2xf32>, tensor, tensor) -> tensor<1x2xf32> %1 = "tf.Reshape"(%0, %cst_0) : (tensor<1x2xf32>, tensor<2xi64>) -> tensor<2x1xf32> func.return %1 : tensor<2x1xf32> // CHECK: %cst = arith.constant // CHECK: %0 = "tf.Reshape"(%arg0, %cst) // CHECK-SAME: tensor<2x1xf32> // CHECK: %1 = "tf.FakeQuantWithMinMaxVars"(%0, %arg1, %arg2) // CHECK: return %1 } // ----- // CHECK-LABEL: fakeQuantFollowedByReshapes func.func @fakeQuantFollowedByReshapes(tensor<1x2xf32>, tensor, tensor) -> (tensor<2x1xf32>, tensor<2x1xf32>) { ^bb0(%arg0: tensor<1x2xf32>, %arg1: tensor, %arg2: tensor): %cst_0 = arith.constant dense<[2, -1]> : tensor<2xi64> %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %arg1, %arg2) {num_bits = 5, narrow_range = false} : (tensor<1x2xf32>, tensor, tensor) -> tensor<1x2xf32> %1 = "tf.Reshape"(%0, %cst_0) : (tensor<1x2xf32>, tensor<2xi64>) -> tensor<2x1xf32> %2 = "tf.Reshape"(%0, %cst_0) : (tensor<1x2xf32>, tensor<2xi64>) -> tensor<2x1xf32> func.return %1, %2 : tensor<2x1xf32>, tensor<2x1xf32> // CHECK: %cst = arith.constant // CHECK: %[[FQ:.*]] = "tf.FakeQuantWithMinMaxVars"(%arg0, %arg1, %arg2) // CHECK: %[[R1:.*]] = "tf.Reshape"(%[[FQ]], %cst) // CHECK-SAME: tensor<2x1xf32> // CHECK: %[[R2:.*]] = "tf.Reshape"(%[[FQ]], %cst) // CHECK-SAME: tensor<2x1xf32> } // ----- // CHECK-LABEL: fakeQuantWithConv2D func.func @fakeQuantWithConv2D(tensor<256x32x32x3xf32>) -> (tensor<256x8x7x16xf32>) { ^bb0(%arg: tensor<256x32x32x3xf32>) : %in = arith.constant dense<0.0> : tensor<3x3x3x16xf32> %min = arith.constant dense<0.0> : tensor %max = arith.constant dense<255.0> : tensor %mini = "tf.Identity"(%min) : (tensor) -> tensor %maxi = "tf.Identity"(%max) : (tensor) -> tensor %fq = "tf.FakeQuantWithMinMaxVars"(%in, %mini, %maxi) {num_bits = 5, narrow_range = false} : (tensor<3x3x3x16xf32>, tensor, tensor) -> tensor<3x3x3x16xf32> %rst = "tf.Conv2D"(%arg, %fq) {T = "tfdtype$DT_FLOAT", data_format = "NHWC", dilations = [1, 2, 3, 1], padding = "SAME", strides = [1, 4, 5, 1]} : (tensor<256x32x32x3xf32>, tensor<3x3x3x16xf32>) -> tensor<256x8x7x16xf32> func.return %rst : tensor<256x8x7x16xf32> // CHECK-DAG: %[[CONSTANT:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<16xf32>}> // CHECK-DAG: %[[CONSTANT0:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<16x3x3x3xf32>}> // CHECK: %[[QUANTIZE:.*]] = "tfl.quantize"(%[[CONSTANT0]]) <{qtype = tensor<16x3x3x3x!quant.uniform>}> // CHECK: %[[DEQUANTIZE:.*]] = "tfl.dequantize"(%[[QUANTIZE]]) // CHECK: %[[CONV:.*]] = "tfl.conv_2d"(%arg0, %[[DEQUANTIZE]], %[[CONSTANT]]) // CHECK: return %[[CONV]] } // ----- // CHECK-LABEL: perChannelFakeQuantWithConv2D func.func @perChannelFakeQuantWithConv2D(tensor<256x32x32x3xf32>) -> (tensor<256x8x7x16xf32>) { ^bb0(%arg: tensor<256x32x32x3xf32>) : %in = arith.constant dense<0.0> : tensor<3x3x3x16xf32> %min = arith.constant dense<0.0> : tensor<16xf32> %max = arith.constant dense<255.0> : tensor<16xf32> %mini = "tf.Identity"(%min) : (tensor<16xf32>) -> tensor<16xf32> %maxi = "tf.Identity"(%max) : (tensor<16xf32>) -> tensor<16xf32> %fq = "tf.FakeQuantWithMinMaxVarsPerChannel"(%in, %mini, %maxi) {num_bits = 5, narrow_range = false} : (tensor<3x3x3x16xf32>, tensor<16xf32>, tensor<16xf32>) -> tensor<3x3x3x16xf32> %rst = "tf.Conv2D"(%arg, %fq) {T = "tfdtype$DT_FLOAT", data_format = "NHWC", dilations = [1, 2, 3, 1], padding = "SAME", strides = [1, 4, 5, 1]} : (tensor<256x32x32x3xf32>, tensor<3x3x3x16xf32>) -> tensor<256x8x7x16xf32> func.return %rst : tensor<256x8x7x16xf32> // CHECK-DAG: %[[CONSTANT0:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<16x3x3x3xf32>}> // CHECK-DAG: %[[CONSTANT:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<16xf32>}> // CHECK: %[[QUANTIZE:.*]] = "tfl.quantize"(%[[CONSTANT0]]) <{qtype = tensor<16x3x3x3x!quant.uniform> // CHECK: %[[DEQUANTIZE:.*]] = "tfl.dequantize"(%[[QUANTIZE]]) // CHECK: %[[CONV:.*]] = "tfl.conv_2d"(%arg0, %[[DEQUANTIZE]], %[[CONSTANT]]) // CHECK: return %[[CONV]] : tensor<256x8x7x16xf32> } // ----- // CHECK-LABEL: fakeQuantWithDepthwiseConv2D func.func @fakeQuantWithDepthwiseConv2D(tensor<256x32x32x3xf32>) -> (tensor<256x30x30x16xf32>) { ^bb0(%arg: tensor<256x32x32x3xf32>) : %in = arith.constant dense<0.0> : tensor<3x3x3x16xf32> %min = arith.constant dense<0.0> : tensor %max = arith.constant dense<255.0> : tensor %mini = "tf.Identity"(%min) : (tensor) -> tensor %maxi = "tf.Identity"(%max) : (tensor) -> tensor %fq = "tf.FakeQuantWithMinMaxVars"(%in, %mini, %maxi) {num_bits = 5, narrow_range = false} : (tensor<3x3x3x16xf32>, tensor, tensor) -> tensor<3x3x3x16xf32> %rst = "tf.DepthwiseConv2dNative"(%arg, %fq) {T = "tfdtype$DT_FLOAT", data_format = "NHWC", dilations = [1, 2, 3, 1], padding = "SAME", strides = [1, 4, 5, 1]} : (tensor<256x32x32x3xf32>, tensor<3x3x3x16xf32>) -> tensor<256x30x30x16xf32> func.return %rst : tensor<256x30x30x16xf32> // CHECK-DAG: %[[CONSTANT:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<48xf32>}> // CHECK-DAG: %[[CONSTANT0:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<1x3x3x48xf32>}> // CHECK: %[[QUANTIZE:.*]] = "tfl.quantize"(%[[CONSTANT0]]) <{qtype = tensor<1x3x3x48x!quant.uniform>}> // CHECK: %[[DEQUANTIZE:.*]] = "tfl.dequantize"(%[[QUANTIZE]]) // CHECK: %[[CONV:.*]] = "tfl.depthwise_conv_2d"(%arg0, %[[DEQUANTIZE]], %[[CONSTANT]]) // CHECK: return %[[CONV]] } // ----- // CHECK-LABEL: perChannelFakeQuantWithDepthwiseConv2D func.func @perChannelFakeQuantWithDepthwiseConv2D(tensor<256x32x32x3xf32>) -> (tensor<256x30x30x16xf32>) { ^bb0(%arg: tensor<256x32x32x3xf32>) : %in = arith.constant dense<0.0> : tensor<3x3x3x16xf32> %min = arith.constant dense<0.0> : tensor<16xf32> %max = arith.constant dense<255.0> : tensor<16xf32> %mini = "tf.Identity"(%min) : (tensor<16xf32>) -> tensor<16xf32> %maxi = "tf.Identity"(%max) : (tensor<16xf32>) -> tensor<16xf32> %fq = "tf.FakeQuantWithMinMaxVarsPerChannel"(%in, %mini, %maxi) {num_bits = 5, narrow_range = false} : (tensor<3x3x3x16xf32>, tensor<16xf32>, tensor<16xf32>) -> tensor<3x3x3x16xf32> %rst = "tf.DepthwiseConv2dNative"(%arg, %fq) {T = "tfdtype$DT_FLOAT", data_format = "NHWC", dilations = [1, 2, 3, 1], padding = "SAME", strides = [1, 4, 5, 1]} : (tensor<256x32x32x3xf32>, tensor<3x3x3x16xf32>) -> tensor<256x30x30x16xf32> func.return %rst : tensor<256x30x30x16xf32> // CHECK-DAG: %[[CONSTANT0:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<1x3x3x48xf32>}> // CHECK-DAG: %[[CONSTANT:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<48xf32>}> // CHECK: %[[QUANTIZE:.*]] = "tfl.quantize"(%[[CONSTANT0]]) <{qtype = tensor<1x3x3x48x!quant.uniform>} // CHECK: %[[DEQUANTIZE:.*]] = "tfl.dequantize"(%[[QUANTIZE]]) // CHECK: %[[CONV:.*]] = "tfl.depthwise_conv_2d"(%arg0, %[[DEQUANTIZE]], %[[CONSTANT]]) // CHECK: return %[[CONV]] } // ----- // CHECK-LABEL: perChannelFakeQuantWithDepthwiseConv2DWithReshape func.func @perChannelFakeQuantWithDepthwiseConv2DWithReshape(%arg: tensor<1x160x160x48xf32>) -> (tensor<1x160x160x48xf32>) { %in = arith.constant dense<0.0> : tensor<3x3x48x1xf32> %min = arith.constant dense<0.0> : tensor<48xf32> %max = arith.constant dense<255.0> : tensor<48xf32> %mini = "tf.Identity"(%min) : (tensor<48xf32>) -> tensor<48xf32> %maxi = "tf.Identity"(%max) : (tensor<48xf32>) -> tensor<48xf32> %s1 = arith.constant dense<[3, 3, 48]> : tensor<3xi32> %s2 = arith.constant dense<[3, 3, 48, 1]> : tensor<4xi32> %r1 = "tf.Reshape"(%in, %s1) {T = f32, Tshape = i32, device = ""} : (tensor<3x3x48x1xf32>, tensor<3xi32>) -> tensor<3x3x48xf32> %fq = "tf.FakeQuantWithMinMaxVarsPerChannel"(%r1, %mini, %maxi) {num_bits = 5, narrow_range = false} : (tensor<3x3x48xf32>, tensor<48xf32>, tensor<48xf32>) -> tensor<3x3x48xf32> %r2 = "tf.Reshape"(%fq, %s2) {T = f32, Tshape = i32, device = ""} : (tensor<3x3x48xf32>, tensor<4xi32>) -> tensor<3x3x48x1xf32> %rst = "tf.DepthwiseConv2dNative"(%arg, %r2) {T = f32, data_format = "NHWC", dilations = [1, 1, 1, 1], padding = "SAME", strides = [1, 1, 1, 1]} : (tensor<1x160x160x48xf32>, tensor<3x3x48x1xf32>) -> tensor<1x160x160x48xf32> func.return %rst : tensor<1x160x160x48xf32> // CHECK-DAG: %[[CONSTANT0:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<1x3x3x48xf32>}> // CHECK-DAG: %[[CONSTANT:.*]] = "tfl.pseudo_const"() <{value = dense<0.000000e+00> : tensor<48xf32>}> // CHECK: %[[QUANTIZE:.*]] = "tfl.quantize"(%[[CONSTANT0]]) <{qtype = tensor<1x3x3x48x!quant.uniform>} // CHECK: %[[DEQUANTIZE:.*]] = "tfl.dequantize"(%[[QUANTIZE]]) // CHECK: %[[CONV:.*]] = "tfl.depthwise_conv_2d"(%arg0, %[[DEQUANTIZE]], %[[CONSTANT]]) // CHECK: return %[[CONV]] } // ----- // LOBIT-LABEL: fakeQuant3BitPerChannelForActivation func.func @fakeQuant3BitPerChannelForActivation(%arg0: tensor<8x4xf32>) -> (tensor<8x4xf32>) { %arg1 = arith.constant dense<[0.0, -1.0, -31.0, -30.0]> : tensor<4xf32> %arg2 = arith.constant dense<[31.0, 30.0, 31.0, 32.0]> : tensor<4xf32> %0 = "tf.FakeQuantWithMinMaxVarsPerChannel"(%arg0, %arg1, %arg2) {num_bits = 5, narrow_range = false} : (tensor<8x4xf32>, tensor<4xf32>, tensor<4xf32>) -> tensor<8x4xf32> func.return %0 : tensor<8x4xf32> // LOBIT: %[[fq:.*]] = "tf.FakeQuantWithMinMaxVarsPerChannel"(%arg0, %cst, %cst_0) // LOBIT: %[[q:.*]] = "tfl.quantize"(%[[fq]]) <{qtype = tensor<8x4x!quant.uniform:f32:1, {1.000000e+00,1.000000e+00:1,2.000000e+00:16,2.000000e+00:15}>>}> // LOBIT: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) // LOBIT: return %[[dq]] } // ----- // LOBIT-LABEL: fakeQuant3BitForActivation func.func @fakeQuant3BitForActivation(tensor<8xf32>) -> (tensor<8xf32>) { ^bb0(%arg0: tensor<8xf32>): %arg1 = arith.constant dense<-30.0> : tensor %arg2 = arith.constant dense<32.0> : tensor %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %arg1, %arg2) {num_bits = 5, narrow_range = false} : (tensor<8xf32>, tensor, tensor) -> tensor<8xf32> func.return %0 : tensor<8xf32> // LOBIT: %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst, %cst_0) // LOBIT: %1 = "tfl.quantize"(%0) <{qtype = tensor<8x!quant.uniform:f32, 2.000000e+00:15>>}> // LOBIT: %2 = "tfl.dequantize"(%1) // LOBIT: return %2 } // ----- // CHECK-LABEL: fakeQuantConcat func.func @fakeQuantConcat(%arg0: tensor<1x6400x2xf32>, %arg1: tensor<1x1600x2xf32>) -> (tensor<1x8000x2xf32>) { %cst = arith.constant dense<1> : tensor %cst_1 = arith.constant dense<-1.0> : tensor %cst_2 = arith.constant dense<1.0> : tensor %cst_3 = arith.constant dense<-2.0> : tensor %cst_4 = arith.constant dense<0.5> : tensor %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst_1, %cst_2) {num_bits = 8, narrow_range = false} : (tensor<1x6400x2xf32>, tensor, tensor) -> tensor<1x6400x2xf32> %1 = "tf.FakeQuantWithMinMaxVars"(%arg1, %cst_3, %cst_4) {num_bits = 8, narrow_range = false} : (tensor<1x1600x2xf32>, tensor, tensor) -> tensor<1x1600x2xf32> %2 = "tf.ConcatV2"(%0, %1, %cst) : (tensor<1x6400x2xf32>, tensor<1x1600x2xf32>, tensor) -> tensor<1x8000x2xf32> return %2 : tensor<1x8000x2xf32> // CHECK: %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst_0, %cst_1) // CHECK: %1 = "tfl.quantize"(%0) // CHECK: %2 = "tfl.dequantize"(%1) // CHECK: %3 = "tf.FakeQuantWithMinMaxVars"(%arg1, %cst_2, %cst_3) // CHECK: %4 = "tfl.quantize"(%3) // CHECK: %5 = "tfl.dequantize"(%4) // CHECK: %6 = "tf.ConcatV2"(%2, %5, %cst) // CHECK: %7 = "tf.FakeQuantWithMinMaxVars"(%6, %cst_2, %cst_1) <{narrow_range = false, num_bits = 8 : i64}> : (tensor<1x8000x2xf32>, tensor, tensor) -> tensor<1x8000x2xf32> // CHECK: %8 = "tfl.quantize"(%7) <{qtype = tensor<1x8000x2x!quant.uniform>}> : (tensor<1x8000x2xf32>) -> tensor<1x8000x2x!quant.uniform> // CHECK: %9 = "tfl.dequantize"(%8) : (tensor<1x8000x2x!quant.uniform>) -> tensor<1x8000x2xf32> // CHECK: return %9 } // ----- // CHECK-LABEL: fakeQuantConcatQDQ func.func @fakeQuantConcatQDQ(%arg0: tensor<1x6400x2xf32>, %arg1: tensor<1x1600x2xf32>) -> (tensor<1x8000x2xf32>) { %cst = arith.constant dense<1> : tensor %cst_1 = arith.constant dense<-1.0> : tensor %cst_2 = arith.constant dense<1.0> : tensor %cst_3 = arith.constant dense<-2.0> : tensor %cst_4 = arith.constant dense<0.5> : tensor %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst_1, %cst_2) {num_bits = 8, narrow_range = false} : (tensor<1x6400x2xf32>, tensor, tensor) -> tensor<1x6400x2xf32> %1 = "tfl.quantize"(%0) {qtype = tensor<1x6400x2x!quant.uniform>} : (tensor<1x6400x2xf32>) -> tensor<1x6400x2x!quant.uniform> %2 = "tfl.dequantize"(%1) : (tensor<1x6400x2x!quant.uniform>) -> tensor<1x6400x2xf32> %3 = "tf.FakeQuantWithMinMaxVars"(%arg1, %cst_3, %cst_4) {num_bits = 8, narrow_range = false} : (tensor<1x1600x2xf32>, tensor, tensor) -> tensor<1x1600x2xf32> %4 = "tfl.quantize"(%3) {qtype = tensor<1x1600x2x!quant.uniform>} : (tensor<1x1600x2xf32>) -> tensor<1x1600x2x!quant.uniform> %5 = "tfl.dequantize"(%4) : (tensor<1x1600x2x!quant.uniform>) -> tensor<1x1600x2xf32> %6 = "tf.ConcatV2"(%2, %5, %cst) : (tensor<1x6400x2xf32>, tensor<1x1600x2xf32>, tensor) -> tensor<1x8000x2xf32> return %6 : tensor<1x8000x2xf32> // CHECK: %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst_0, %cst_1) // CHECK: %1 = "tfl.quantize"(%0) // CHECK: %2 = "tfl.dequantize"(%1) // CHECK: %3 = "tf.FakeQuantWithMinMaxVars"(%arg1, %cst_2, %cst_3) // CHECK: %4 = "tfl.quantize"(%3) // CHECK: %5 = "tfl.dequantize"(%4) // CHECK: %6 = "tf.ConcatV2"(%2, %5, %cst) // CHECK: %7 = "tf.FakeQuantWithMinMaxVars"(%6, %cst_2, %cst_1) <{narrow_range = false, num_bits = 8 : i64}> : (tensor<1x8000x2xf32>, tensor, tensor) -> tensor<1x8000x2xf32> // CHECK: %8 = "tfl.quantize"(%7) <{qtype = tensor<1x8000x2x!quant.uniform>}> : (tensor<1x8000x2xf32>) -> tensor<1x8000x2x!quant.uniform> // CHECK: %9 = "tfl.dequantize"(%8) : (tensor<1x8000x2x!quant.uniform>) -> tensor<1x8000x2xf32> // CHECK: return %9 } // ----- // CHECK-LABEL: populateFakeQuantOnMeanOutput func.func @populateFakeQuantOnMeanOutput(%arg0: tensor) -> (tensor) { %cst = arith.constant dense<-1.0> : tensor %cst_1 = arith.constant dense<1.0> : tensor %cst_2 = arith.constant dense<0> : tensor<1xi32> %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst, %cst_1) {num_bits = 8, narrow_range = false} : (tensor, tensor, tensor) -> tensor %1 = "tf.Mean"(%0, %cst_2) <{keep_dims = false}> : (tensor, tensor<1xi32>) -> tensor return %1 : tensor // CHECK: %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst, %cst_0) // CHECK: %1 = "tfl.quantize"(%0) <{qtype = tensor>}> : (tensor) -> tensor> // CHECK: %2 = "tfl.dequantize"(%1) : (tensor>) -> tensor // CHECK: %3 = "tf.Mean"(%2, %cst_1) // CHECK: %4 = "tf.FakeQuantWithMinMaxVars"(%3, %cst, %cst_0) // CHECK: %5 = "tfl.quantize"(%4) <{qtype = tensor>}> : (tensor) -> tensor> // CHECK: %6 = "tfl.dequantize"(%5) : (tensor>) -> tensor // CHECK: return %6 } // ----- // CHECK-LABEL: populateFakeQuantOnMeanOutputQDQs func.func @populateFakeQuantOnMeanOutputQDQs(%arg0: tensor) -> (tensor) { %cst = arith.constant dense<-1.0> : tensor %cst_1 = arith.constant dense<1.0> : tensor %cst_2 = arith.constant dense<0> : tensor<1xi32> %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst, %cst_1) {num_bits = 8, narrow_range = false} : (tensor, tensor, tensor) -> tensor %1 = "tfl.quantize"(%0) <{qtype = tensor>}> : (tensor) -> tensor> %2 = "tfl.dequantize"(%1) : (tensor>) -> tensor %3 = "tf.Mean"(%2, %cst_2) <{keep_dims = false}> : (tensor, tensor<1xi32>) -> tensor return %3 : tensor // CHECK: %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst, %cst_0) // CHECK-NEXT: %1 = "tfl.quantize"(%0) <{qtype = tensor>}> : (tensor) -> tensor> // CHECK-NEXT: %2 = "tfl.dequantize"(%1) : (tensor>) -> tensor // CHECK-NEXT: %3 = "tf.Mean"(%2, %cst_1) // CHECK-NEXT: %4 = "tf.FakeQuantWithMinMaxVars"(%3, %cst, %cst_0) // CHECK-NEXT: %5 = "tfl.quantize"(%4) <{qtype = tensor>}> : (tensor) -> tensor> // CHECK-NEXT: %6 = "tfl.dequantize"(%5) : (tensor>) -> tensor // CHECK-NEXT: return %6 } // ----- // CHECK-LABEL: populateFakeQuantOnMeanOutputFollowedByConcat func.func @populateFakeQuantOnMeanOutputFollowedByConcat(%arg0: tensor, %arg1: tensor) -> (tensor<1xf32>) { %cst = arith.constant dense<1> : tensor %cst_1 = arith.constant dense<-1.0> : tensor %cst_2 = arith.constant dense<1.0> : tensor %cst_3 = arith.constant dense<0> : tensor<1xi32> %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst_1, %cst_2) {num_bits = 8, narrow_range = false} : (tensor, tensor, tensor) -> tensor %1 = "tf.Mean"(%0, %cst_3) <{keep_dims = false}> : (tensor, tensor<1xi32>) -> tensor %2 = "tf.FakeQuantWithMinMaxVars"(%arg1, %cst_1, %cst_2) {num_bits = 8, narrow_range = false} : (tensor, tensor, tensor) -> tensor %3 = "tf.Mean"(%2, %cst_3) <{keep_dims = false}> : (tensor, tensor<1xi32>) -> tensor %4 = "tf.ConcatV2"(%1, %3, %cst) : (tensor, tensor, tensor) -> tensor<1xf32> return %4 : tensor<1xf32> // CHECK: %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst_0, %cst_1) // CHECK-NEXT: %1 = "tfl.quantize"(%0) <{qtype = tensor>}> : (tensor) -> tensor> // CHECK-NEXT: %2 = "tfl.dequantize"(%1) : (tensor>) -> tensor // CHECK-NEXT: %3 = "tf.Mean"(%2, %cst_2) // CHECK-NEXT: %4 = "tf.FakeQuantWithMinMaxVars"(%3, %cst_0, %cst_1) // CHECK-NEXT: %5 = "tfl.quantize"(%4) <{qtype = tensor>}> : (tensor) -> tensor> // CHECK-NEXT: %6 = "tfl.dequantize"(%5) : (tensor>) -> tensor // CHECK-NEXT: %7 = "tf.FakeQuantWithMinMaxVars"(%arg1, %cst_0, %cst_1) // CHECK-NEXT: %8 = "tfl.quantize"(%7) <{qtype = tensor>}> : (tensor) -> tensor> // CHECK-NEXT: %9 = "tfl.dequantize"(%8) : (tensor>) -> tensor // CHECK-NEXT: %10 = "tf.Mean"(%9, %cst_2) // CHECK-NEXT: %11 = "tf.FakeQuantWithMinMaxVars"(%10, %cst_0, %cst_1) // CHECK-NEXT: %12 = "tfl.quantize"(%11) <{qtype = tensor>}> : (tensor) -> tensor> // CHECK-NEXT: %13 = "tfl.dequantize"(%12) : (tensor>) -> tensor // CHECK-NEXT: %14 = "tf.ConcatV2"(%6, %13, %cst) // CHECK-NEXT: %15 = "tf.FakeQuantWithMinMaxVars"(%14, %cst_0, %cst_1) <{narrow_range = false, num_bits = 8 : i64}> : (tensor<1xf32>, tensor, tensor) -> tensor<1xf32> // CHECK-NEXT: %16 = "tfl.quantize"(%15) <{qtype = tensor<1x!quant.uniform>}> : (tensor<1xf32>) -> tensor<1x!quant.uniform> // CHECK-NEXT: %17 = "tfl.dequantize"(%16) : (tensor<1x!quant.uniform>) -> tensor<1xf32> // CHECK-NEXT: return %17 } // ----- // CHECK-LABEL: populateFakeQuantOnMeanOutputNegativeCase func.func @populateFakeQuantOnMeanOutputNegativeCase(%arg0: tensor) -> (tensor) { %cst = arith.constant dense<-1.0> : tensor %cst_1 = arith.constant dense<1.0> : tensor %cst_2 = arith.constant dense<0> : tensor<1xi32> %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst, %cst_1) {num_bits = 8, narrow_range = false} : (tensor, tensor, tensor) -> tensor %1 = "tf.Mean"(%0, %cst_2) <{keep_dims = false}> : (tensor, tensor<1xi32>) -> tensor %2 = "tf.FakeQuantWithMinMaxVars"(%1, %cst, %cst_1) {num_bits = 8, narrow_range = false} : (tensor, tensor, tensor) -> tensor return %2 : tensor // CHECK: %0 = "tf.FakeQuantWithMinMaxVars"(%arg0, %cst, %cst_0) // CHECK: %1 = "tfl.quantize"(%0) // CHECK: %2 = "tfl.dequantize"(%1) // CHECK: %3 = "tf.Mean"(%2, %cst_1) // CHECK: %4 = "tf.FakeQuantWithMinMaxVars"(%3, %cst, %cst_0) // CHECK-NOT: "tf.FakeQuantWithMinMaxVars" } // -----