// 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 -tfl-prepare-quantize="quantize-signed=true" | FileCheck %s // RUN: litert-opt %s -tfl-prepare-quantize="quantize-signed=true disable-per-channel=true" | FileCheck --check-prefix=PerTensor %s // CHECK-LABEL: uint8_to_int8 func.func @uint8_to_int8(%arg0: tensor<2x2xf32>) -> tensor<2x2xf32> { %1 = "tfl.quantize"(%arg0) {qtype = tensor<2x2x!quant.uniform>} : (tensor<2x2xf32>) -> tensor<2x2x!quant.uniform> %2 = "tfl.dequantize"(%1) : (tensor<2x2x!quant.uniform>) -> tensor<2x2xf32> func.return %2 : tensor<2x2xf32> // CHECK-NEXT: %[[q:.*]] = "tfl.quantize"(%arg0) <{qtype = tensor<2x2x!quant.uniform>}> : (tensor<2x2xf32>) // CHECK-NEXT: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) // CHECK-NEXT: return %[[dq]] : tensor<2x2xf32> } // CHECK-LABEL: uint8_to_int8_per_axis func.func @uint8_to_int8_per_axis(%arg0: tensor<2x2xf32>) -> tensor<2x2xf32> { %1 = "tfl.quantize"(%arg0) {qtype = tensor<2x2x!quant.uniform>} : (tensor<2x2xf32>) -> tensor<2x2x!quant.uniform> %2 = "tfl.dequantize"(%1) : (tensor<2x2x!quant.uniform>) -> tensor<2x2xf32> func.return %2 : tensor<2x2xf32> // CHECK-NEXT: %[[q:.*]] = "tfl.quantize"(%arg0) <{qtype = tensor<2x2x!quant.uniform>}> // CHECK-NEXT: %[[dq:.*]] = "tfl.dequantize"(%0) // CHECK-NEXT: return %[[dq]] : tensor<2x2xf32> } // CHECK-LABEL: uint8_to_int8_narrow_range func.func @uint8_to_int8_narrow_range(%arg0: tensor<2x2xf32>) -> tensor<2x2xf32> { %1 = "tfl.quantize"(%arg0) {qtype = tensor<2x2x!quant.uniform:f32, 1.0:255>>} : (tensor<2x2xf32>) -> tensor<2x2x!quant.uniform:f32, 1.0:255>> %2 = "tfl.dequantize"(%1) : (tensor<2x2x!quant.uniform:f32, 1.0:255>>) -> tensor<2x2xf32> func.return %2 : tensor<2x2xf32> // CHECK-NEXT: %[[q:.*]] = "tfl.quantize"(%arg0) <{qtype = tensor<2x2x!quant.uniform:f32, 1.000000e+00:127>>}> // CHECK-NEXT: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) // CHECK-NEXT: return %[[dq]] : tensor<2x2xf32> } // CHECK-LABEL: prepareStatistics func.func @prepareStatistics(%arg0: tensor<8x4x3xf32>) -> tensor<8x4x3xf32> { %0 = "quantfork.stats"(%arg0) { layerStats = dense<[-1.0, 1.0]> : tensor<2xf32> } : (tensor<8x4x3xf32>) -> tensor<8x4x3xf32> %1 = "quantfork.stats"(%0) { layerStats = dense<[-1.0, 1.0]> : tensor<2xf32>, axisStats = dense<[ [-1.0, 1.0], [-8.0, 8.0], [-0.5, 0.5] ]> : tensor<3x2xf32>, axis = 2 : i64 } : (tensor<8x4x3xf32>) -> tensor<8x4x3xf32> func.return %1 : tensor<8x4x3xf32> // CHECK: %[[q1:.*]] = "tfl.quantize"(%arg0) <{qtype = tensor<8x4x3x!quant.uniform>}> {volatile} // CHECK: %[[dq1:.*]] = "tfl.dequantize"(%[[q1]]) // CHECK: %[[q2:.*]] = "tfl.quantize"(%[[dq1]]) <{qtype = tensor<8x4x3x!quant.uniform>}> {volatile} // CHECK: %[[dq2:.*]] = "tfl.dequantize"(%[[q2]]) // CHECK: return %[[dq2]] } // CHECK-LABEL: prepareStatisticsNudge func.func @prepareStatisticsNudge(%arg0: tensor<8x4x3xf32>) -> tensor<8x4x3xf32> { %0 = "quantfork.stats"(%arg0) { layerStats = dense<[0.1, 1.0]> : tensor<2xf32> } : (tensor<8x4x3xf32>) -> tensor<8x4x3xf32> %1 = "quantfork.stats"(%0) { layerStats = dense<[0.1, 1.0]> : tensor<2xf32>, axisStats = dense<[ [-1.0, 1.0], [-8.0, -1.0], [-0.5, 0.5] ]> : tensor<3x2xf32>, axis = 2 : i64 } : (tensor<8x4x3xf32>) -> tensor<8x4x3xf32> func.return %1 : tensor<8x4x3xf32> // CHECK: %[[q1:.*]] = "tfl.quantize"(%arg0) <{qtype = tensor<8x4x3x!quant.uniform>}> {volatile} // CHECK: %[[dq1:.*]] = "tfl.dequantize"(%[[q1]]) // CHECK: %[[q2:.*]] = "tfl.quantize"(%[[dq1]]) <{qtype = tensor<8x4x3x!quant.uniform>}> {volatile} // CHECK: %[[dq2:.*]] = "tfl.dequantize"(%[[q2]]) // CHECK: return %[[dq2]] } // CHECK-LABEL: preparePrelu func.func @preparePrelu(%arg0: tensor<1x10x10x3xf32>) -> tensor<1x10x10x3xf32> { %cst = "arith.constant"() {value = dense<[[[1.66394591, 3.61694336, 2.0382936]]]> : tensor<1x1x3xf32>} : () -> tensor<1x1x3xf32> %prelu = "tfl.prelu"(%arg0, %cst) : (tensor<1x10x10x3xf32>, tensor<1x1x3xf32>) -> tensor<1x10x10x3xf32> func.return %prelu : tensor<1x10x10x3xf32> // CHECK: %[[cst:.*]] = arith.constant dense<[{{\[}}[1.66394591, 3.61694336, 2.0382936]]]> : tensor<1x1x3xf32> // CHECK: %[[q:.*]] = "tfl.quantize"(%[[cst]]) <{qtype = tensor<1x1x3x!quant.uniform:f32, 0.028479868971456691>>}> {volatile} : (tensor<1x1x3xf32>) -> tensor<1x1x3x!quant.uniform:f32, 0.028479868971456691>> // CHECK: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) : (tensor<1x1x3x!quant.uniform:f32, 0.028479868971456691>>) -> tensor<1x1x3xf32> // CHECK: %[[p:.*]] = "tfl.prelu"(%arg0, %[[dq]]) : (tensor<1x10x10x3xf32>, tensor<1x1x3xf32>) -> tensor<1x10x10x3xf32> // CHECK: return %[[p]] : tensor<1x10x10x3xf32> } // CHECK-LABEL: prepareAdd func.func @prepareAdd(%arg0: tensor<2x2xf32>) -> tensor<2x2xf32> { %cst = arith.constant dense<[[0.0, 1.0], [2.0, 255.0]]> : tensor<2x2xf32> %add = "tfl.add"(%arg0, %cst) {fused_activation_function="NONE"} : (tensor<2x2xf32>, tensor<2x2xf32>) -> tensor<2x2xf32> func.return %add : tensor<2x2xf32> // CHECK: %[[cst:.*]] = arith.constant dense<[{{\[}}0.000000e+00, 1.000000e+00], [2.000000e+00, 2.550000e+02]]> // CHECK: %[[q:.*]] = "tfl.quantize"(%[[cst]]) <{qtype = tensor<2x2x!quant.uniform>}> {volatile} // CHECK: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) // CHECK: %[[add:.*]] = tfl.add %arg0, %[[dq]] // CHECK: return %[[add]] } // CHECK-LABEL: prepareConv2DSplat // PerTensor-LABEL: prepareConv2DSplat func.func @prepareConv2DSplat(%arg0: tensor<1x5x5x3xf32>) -> tensor<1x5x5x3xf32> { %w = arith.constant dense<127.0> : tensor<3x3x3x3xf32> %b = arith.constant dense<0.0> : tensor<3xf32> %conv = "tfl.conv_2d"(%arg0, %w, %b) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "RELU", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32} : (tensor<1x5x5x3xf32>, tensor<3x3x3x3xf32>, tensor<3xf32>) -> tensor<1x5x5x3xf32> func.return %conv : tensor<1x5x5x3xf32> // CHECK: %[[cst:.*]] = arith.constant dense<1.270000e+02> : tensor<3x3x3x3xf32> // CHECK: %[[q:.*]] = "tfl.quantize"(%[[cst]]) <{qtype = tensor<3x3x3x3x!quant.uniform:f32:0 // CHECK-SAME: {1.000000e+00,1.000000e+00,1.000000e+00} // CHECK: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) // CHECK: %[[conv:.*]] = "tfl.conv_2d"(%arg0, %[[dq]] // PerTensor: %[[cst:.*]] = arith.constant dense<1.270000e+02> : tensor<3x3x3x3xf32> // PerTensor: %[[q:.*]] = "tfl.quantize"(%[[cst]]) <{qtype = tensor<3x3x3x3x!quant.uniform:f32, 1.000000e+00>>}> {volatile} // PerTensor: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) // PerTensor: %[[conv:.*]] = "tfl.conv_2d"(%arg0, %[[dq]] } // CHECK-LABEL: prepareConv2D // PerTensor-LABEL: prepareConv2D func.func @prepareConv2D(%arg0: tensor<1x5x5x1xf32>) -> tensor<1x5x5x3xf32> { %w = arith.constant dense<[[[[0.0]]], [[[127.0]]], [[[-127.0]]]]> : tensor<3x1x1x1xf32> %b = arith.constant dense<0.0> : tensor<3xf32> %conv = "tfl.conv_2d"(%arg0, %w, %b) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "RELU", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32} : (tensor<1x5x5x1xf32>, tensor<3x1x1x1xf32>, tensor<3xf32>) -> tensor<1x5x5x3xf32> func.return %conv : tensor<1x5x5x3xf32> // CHECK: %[[cst:.*]] = arith.constant dense<[{{\[\[\[}}0.000000e+00]]], [{{\[\[}}1.270000e+02]]], [{{\[\[}}-1.270000e+02]]]]> // CHECK: %[[q:.*]] = "tfl.quantize"(%[[cst]]) <{qtype = tensor<3x1x1x1x!quant.uniform:f32:0, // CHECK-SAME: {3.9370078740157481E-9,1.000000e+00,1.000000e+00}>>}> {volatile} // CHECK: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) // CHECK: %[[conv:.*]] = "tfl.conv_2d"(%arg0, %[[dq]] // PerTensor: %[[cst:.*]] = arith.constant dense<[{{\[\[\[}}0.000000e+00]]], [{{\[\[}}1.270000e+02]]], [{{\[\[}}-1.270000e+02]]]]> // PerTensor: %[[q:.*]] = "tfl.quantize"(%[[cst]]) <{qtype = tensor<3x1x1x1x!quant.uniform:f32, // PerTensor: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) // PerTensor: %[[conv:.*]] = "tfl.conv_2d"(%arg0, %[[dq]] } // CHECK-LABEL: prepareDepthwiseConv2D // PerTensor-LABEL: prepareDepthwiseConv2D func.func @prepareDepthwiseConv2D(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x112x112x32xf32> { %w = arith.constant dense<127.0> : tensor<32x3x3x3xf32> %b = arith.constant dense<0.0> : tensor<32xf32> %dc = "tfl.depthwise_conv_2d"(%arg0, %w, %b) {depth_multiplier = 4 : i32, dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "VALID", stride_h = 4 : i32, stride_w = 5 : i32} : (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32> func.return %dc : tensor<1x112x112x32xf32> // CHECK: %[[cst:.*]] = arith.constant dense<1.270000e+02> : tensor<32x3x3x3xf32> // CHECK: %[[q:.*]] = "tfl.quantize"(%[[cst]]) <{qtype = tensor<32x3x3x3x!quant.uniform:f32:3 // CHECK-SAME: {1.000000e+00,1.000000e+00,1.000000e+00} // CHECK: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) // CHECK: %[[conv:.*]] = "tfl.depthwise_conv_2d"(%arg0, %[[dq]] // PerTensor: %[[cst:.*]] = arith.constant dense<1.270000e+02> : tensor<32x3x3x3xf32> // PerTensor: %[[q:.*]] = "tfl.quantize"(%[[cst]]) <{qtype = tensor<32x3x3x3x!quant.uniform:f32, // PerTensor: %[[dq:.*]] = "tfl.dequantize"(%[[q]]) // PerTensor: %[[conv:.*]] = "tfl.depthwise_conv_2d"(%arg0, %[[dq]] } // CHECK-LABEL: QuantizeFullyConnected // PerTensor-LABEL: QuantizeFullyConnected func.func @QuantizeFullyConnected(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x112x112x4xf32> { %w = arith.constant dense<127.0> : tensor<4x12xf32> %b = arith.constant dense<0.0> : tensor<4xf32> %fc = "tfl.fully_connected"(%arg0, %w, %b) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<1x224x224x3xf32>, tensor<4x12xf32>, tensor<4xf32>) -> tensor<1x112x112x4xf32> func.return %fc : tensor<1x112x112x4xf32> // CHECK: %[[cst:.*]] = arith.constant dense<1.270000e+02> : tensor<4x12xf32> // CHECK: %[[q:.*]] = "tfl.quantize"(%cst) <{qtype = tensor<4x12x!quant.uniform:f32:0, {1.000000e+00,1.000000e+00,1.000000e+00,1.000000e+00}>>}> {volatile} // CHECK: %[[dq:.*]] = "tfl.dequantize"(%0) : (tensor<4x12x!quant.uniform:f32:0, {1.000000e+00,1.000000e+00,1.000000e+00,1.000000e+00}>>) -> tensor<4x12xf32> // CHECK: "tfl.fully_connected"(%arg0, %[[dq]] // PerTensor: %[[cst:.*]] = arith.constant dense<1.270000e+02> : tensor<4x12xf32> // PerTensor: %[[q:.*]] = "tfl.quantize"(%cst) <{qtype = tensor<4x12x!quant.uniform:f32, 1.000000e+00>>}> {volatile} // PerTensor: %[[dq:.*]] = "tfl.dequantize"(%0) : (tensor<4x12x!quant.uniform:f32, 1.000000e+00>>) -> tensor<4x12xf32> // PerTensor: "tfl.fully_connected"(%arg0, %[[dq]] } // CHECK-LABEL: QuantizeTransposeConv // PerTensor-LABEL: QuantizeTransposeConv func.func @QuantizeTransposeConv(%arg0: tensor<32x4x4x128xf32>, %arg1: tensor<4xi32>) -> tensor<1x32x42x128xf32> { %w = arith.constant dense<127.0> : tensor<1x32x42x128xf32> %b = arith.constant dense<0.0> : tensor<1x32x42x128xf32> %tc = "tfl.transpose_conv"(%arg1, %w, %arg0, %b) {padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32, fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<1x32x42x128xf32>, tensor<32x4x4x128xf32>, tensor<1x32x42x128xf32>) -> tensor<1x32x42x128xf32> func.return %tc : tensor<1x32x42x128xf32> // CHECK: %[[CST:.*]] = arith.constant dense<1.270000e+02> : tensor<1x32x42x128xf32> // CHECK: %[[QUANTIZE:.*]] = "tfl.quantize"(%[[CST]]) <{qtype = tensor<1x32x42x128x!quant.uniform:f32:0, {1.000000e+00}>>}> {volatile} // CHECK: %[[DEQUANTIZE:.*]] = "tfl.dequantize"(%[[QUANTIZE]]) : (tensor<1x32x42x128x!quant.uniform:f32:0, {1.000000e+00}>>) -> tensor<1x32x42x128xf32> // CHECK: "tfl.transpose_conv"(%arg1, %[[DEQUANTIZE]], %arg0, // PerTensor: %[[CST:.*]] = arith.constant dense<1.270000e+02> : tensor<1x32x42x128xf32> // PerTensor: %[[QUANTIZE:.*]] = "tfl.quantize"(%[[CST]]) <{qtype = tensor<1x32x42x128x!quant.uniform:f32, 1.000000e+00>>}> {volatile} // PerTensor: %[[DEQUANTIZE:.*]] = "tfl.dequantize"(%[[QUANTIZE]]) : (tensor<1x32x42x128x!quant.uniform:f32, 1.000000e+00>>) -> tensor<1x32x42x128xf32> // PerTensor: "tfl.transpose_conv"(%arg1, %[[DEQUANTIZE]], %arg0, } // CHECK-LABEL: bias_adjust_pertensor func.func @bias_adjust_pertensor(%arg0: tensor<1x2xf32>) -> (tensor<1x2xf32>) { %0 = "quantfork.stats"(%arg0) { layerStats = dense<[-1.28e-5, 1.27e-5]> : tensor<2xf32> } : (tensor<1x2xf32>) -> tensor<1x2xf32> %w = arith.constant dense<[[0.0, 1.0], [1.0, 2.0]]> : tensor<2x2xf32> %b = arith.constant dense<[0.0, 2.1473647e6]> : tensor<2xf32> %fc = "tfl.fully_connected"(%0, %w, %b) { fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT" } : (tensor<1x2xf32>, tensor<2x2xf32>, tensor<2xf32>) -> tensor<1x2xf32> func.return %fc : tensor<1x2xf32> // CHECK-DAG: %[[weight:.*]] = arith.constant dense<{{\[\[}}0.000000e+00, 1.000000e+00] // CHECK-DAG: %[[bias:.*]] = arith.constant dense<[0.000000e+00, 2147364.75]> // CHECK-DAG: %[[b_q:.*]] = "tfl.quantize"(%[[bias]]){{.*}}quant.uniform> // CHECK-DAG: %[[w_q:.*]] = "tfl.quantize"(%[[weight]]){{.*}}quant.uniform:f32:0, {0.0078740157480314959,19998.892343977564}>> // CHECK-DAG: %[[b_dq:.*]] = "tfl.dequantize"(%[[b_q]]) // CHECK-DAG: %[[w_dq:.*]] = "tfl.dequantize"(%[[w_q]]) // CHECK: %[[fc:.*]] = "tfl.fully_connected"(%[[input:.*]], %[[w_dq]], %[[b_dq]]) // CHECK: return %[[fc]] } // CHECK-LABEL: bias_adjust_perchannel func.func @bias_adjust_perchannel(%arg0: tensor<1x5x5x2xf32>, %arg1: tensor<4xi32>) -> (tensor<1x5x5x3xf32>) { %0 = "quantfork.stats"(%arg0) { layerStats = dense<[-1.28e-5, 1.27e-5]> : tensor<2xf32> } : (tensor<1x5x5x2xf32>) -> tensor<1x5x5x2xf32> %w = arith.constant dense<[[[[-1.0, 1.0]]], [[[1.0, 2.0]]], [[[-2.0, 1.0]]]]> : tensor<3x1x1x2xf32> %b = arith.constant dense<[1.0e-2, 2.1473647e1, -2.1473647e2]> : tensor<3xf32> %transpose_conv = "tfl.transpose_conv"(%arg1, %w, %0, %b) { padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32, fused_activation_function = "NONE" } : (tensor<4xi32>, tensor<3x1x1x2xf32>, tensor<1x5x5x2xf32>, tensor<3xf32>) -> tensor<1x5x5x3xf32> func.return %transpose_conv : tensor<1x5x5x3xf32> // CHECK: %[[bias:.*]] = arith.constant dense<[0.00999999977, 21.4736462, -214.736465]> // CHECK: %[[b_q:.*]] = "tfl.quantize"(%[[bias]]) // CHECK-SAME: {7.8740158861230386E-10,1.9998891450408216E-8,1.9998891805679583E-7} // CHECK: %[[b_dq:.*]] = "tfl.dequantize"(%[[b_q]]) // CHECK: %[[weight:.*]] = arith.constant dense<{{\[\[\[\[}}-1.000000e+00, 1.000000e+00]]] // CHECK: %[[w_q:.*]] = "tfl.quantize"(%[[weight]]) // CHECK-SAME: {0.0078740157480314959,0.19998891099675145,1.9998891454946508} // CHECK: %[[w_dq:.*]] = "tfl.dequantize"(%[[w_q]]) // CHECK: %[[conv:.*]] = "tfl.transpose_conv"(%arg1, %[[w_dq]], %[[input:.*]], %[[b_dq]]) // CHECK: return %6 : tensor<1x5x5x3xf32> } // CHECK-LABEL: bias_adjust_duplicate_filter func.func @bias_adjust_duplicate_filter(%arg0: tensor<1x5x5x2xf32>) -> (tensor<1x5x5x3xf32>, tensor<1x5x5x3xf32>) { %0 = "quantfork.stats"(%arg0) { layerStats = dense<[-1.28e-5, 1.27e-5]> : tensor<2xf32> } : (tensor<1x5x5x2xf32>) -> tensor<1x5x5x2xf32> %w = arith.constant dense<[[[[-1.0, 1.0]]], [[[1.0, 2.0]]], [[[-2.0, 1.0]]]]> : tensor<3x1x1x2xf32> %b = arith.constant dense<0.0> : tensor<3xf32> %b2 = arith.constant dense<[1.0e-2, 2.1473647e1, -2.1473647e2]> : tensor<3xf32> %conv = "tfl.conv_2d"(%0, %w, %b) { dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "RELU", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32 } : (tensor<1x5x5x2xf32>, tensor<3x1x1x2xf32>, tensor<3xf32>) -> tensor<1x5x5x3xf32> %conv2 = "tfl.conv_2d"(%0, %w, %b2) { dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "RELU", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32 } : (tensor<1x5x5x2xf32>, tensor<3x1x1x2xf32>, tensor<3xf32>) -> tensor<1x5x5x3xf32> func.return %conv, %conv2 : tensor<1x5x5x3xf32>, tensor<1x5x5x3xf32> // CHECK-DAG: %[[bias:.*]] = arith.constant dense<[0.00999999977, 21.4736462, -214.736465]> // CHECK-DAG: %[[w1:.*]] = arith.constant dense<{{\[\[\[\[}}-1.000000e+00, 1.000000e+00]]] // CHECK-DAG: %[[b_q:.*]] = "tfl.quantize"(%[[bias]]){{.*}}{7.8740158861230386E-10,1.9998891450408216E-8,1.9998891805679583E-7} // CHECK-DAG: %[[b_dq:.*]] = "tfl.dequantize"(%[[b_q]]) // CHECK-DAG: %[[w1_q:.*]] = "tfl.quantize"(%[[w1]]){{.*}}{0.0078740157480314959,0.015748031496062992,0.015748031496062992} // CHECK-DAG: %[[w1_dq:.*]] = "tfl.dequantize"(%[[w1_q]]) // Weight with adjusted scales // CHECK-DAG: %[[w2:.*]] = arith.constant dense<{{\[\[\[\[}}-1.000000e+00, 1.000000e+00]]] // CHECK-DAG: %[[w2_q:.*]] = "tfl.quantize"(%[[w2]]){{.*}}{0.0078740157480314959,0.19998891099675145,1.9998891454946508} // CHECK-DAG: %[[w2_dq:.*]] = "tfl.dequantize"(%[[w2_q]]) // Bias with adjusted scales // CHECK: %[[conv_normal:.*]] = "tfl.conv_2d"(%[[input:.*]], %[[w1_dq]], %[[bias_normal:.*]]) // CHECK: %[[conv_adjusted:.*]] = "tfl.conv_2d"(%[[input:.*]], %[[w2_dq]], %[[b_dq]]) // CHECK: return %[[conv_normal]], %[[conv_adjusted]] } // CHECK-LABEL: bias_adjust_pass_immutable func.func @bias_adjust_pass_immutable(%arg0: tensor<1x2xf32>) -> (tensor<1x2xf32>) { %0 = "quantfork.stats"(%arg0) { layerStats = dense<[-1.28e-5, 1.27e-5]> : tensor<2xf32> } : (tensor<1x2xf32>) -> tensor<1x2xf32> %w = arith.constant dense<[[0.0, 1.0], [1.0, 2.0]]> : tensor<2x2xf32> %w_q = "quantfork.stats"(%w) { layerStats = dense<[0.0, 2.0]> : tensor<2xf32> } : (tensor<2x2xf32>) -> tensor<2x2xf32> %b = arith.constant dense<[0.0, 2.1473647e3]> : tensor<2xf32> %fc = "tfl.fully_connected"(%0, %w_q, %b) { fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT" } : (tensor<1x2xf32>, tensor<2x2xf32>, tensor<2xf32>) -> tensor<1x2xf32> func.return %fc : tensor<1x2xf32> // CHECK: %[[weight:.*]] = arith.constant dense<{{\[\[}}0.000000e+00, 1.000000e+00] // CHECK: %[[w_q:.*]] = "tfl.quantize"(%[[weight]]) // CHECK-SAME: quant.uniform } // ----- // Series of values needing requantization -- first the args then the results // of concatenation operations. concat(concat(arg2, arg0), concat(arg1, arg0)), // concat(concat(arg2, arg0), arg3)). arg0 should be requantized twice -- // concat(arg2, arg0) should be requantized twice as well. // Int8-LABEL: QuantizedCatsAddRequantsTest func.func @QuantizedCatsAddRequantsTest(%arg0: tensor<1x1xf32>, %arg1: tensor<1x1xf32>, %arg2: tensor<1x1xf32>, %arg3: tensor<1x1xf32>) -> (tensor<1x4xf32>, tensor<1x3xf32>) { %0 = "quantfork.stats"(%arg0) {layerStats = dense<[-0.440728068, 0.189515018]> : tensor<2xf32>} : (tensor<1x1xf32>) -> tensor<1x1xf32> %1 = "quantfork.stats"(%arg1) {layerStats = dense<[-0.154693216, 0.26483655]> : tensor<2xf32>} : (tensor<1x1xf32>) -> tensor<1x1xf32> %2 = "quantfork.stats"(%arg2) {layerStats = dense<[-0.488159984, 0.16362021]> : tensor<2xf32>} : (tensor<1x1xf32>) -> tensor<1x1xf32> %3 = "quantfork.stats"(%arg3) {layerStats = dense<[-0.25180456, 0.398609281]> : tensor<2xf32>} : (tensor<1x1xf32>) -> tensor<1x1xf32> %6 = "tfl.concatenation"(%1, %0) {axis = -1 : i32, fused_activation_function = "NONE"} : (tensor<1x1xf32>, tensor<1x1xf32>) -> tensor<1x2xf32> %7 = "quantfork.stats"(%6) {layerStats = dense<[-0.440728068, 0.26483655]> : tensor<2xf32>} : (tensor<1x2xf32>) -> tensor<1x2xf32> %8 = "tfl.concatenation"(%2, %0) {axis = -1 : i32, fused_activation_function = "NONE"} : (tensor<1x1xf32>, tensor<1x1xf32>) -> tensor<1x2xf32> %9 = "quantfork.stats"(%8) {layerStats = dense<[-0.488159984, 0.189515018]> : tensor<2xf32>} : (tensor<1x2xf32>) -> tensor<1x2xf32> %10 = "tfl.concatenation"(%9, %7) {axis = -1 : i32, fused_activation_function = "NONE"} : (tensor<1x2xf32>, tensor<1x2xf32>) -> tensor<1x4xf32> %11 = "quantfork.stats"(%10) {layerStats = dense<[-0.488159984, 0.26483655]> : tensor<2xf32>} : (tensor<1x4xf32>) -> tensor<1x4xf32> %13 = "tfl.concatenation"(%9, %3) {axis = -1 : i32, fused_activation_function = "NONE"} : (tensor<1x2xf32>, tensor<1x1xf32>) -> tensor<1x3xf32> %14 = "quantfork.stats"(%13) {layerStats = dense<[-0.488159984, 0.398609281]> : tensor<2xf32>} : (tensor<1x3xf32>) -> tensor<1x3xf32> func.return %10, %14 : tensor<1x4xf32>, tensor<1x3xf32> // Int8: %[[q0:.*]] = "tfl.quantize"(%arg0) <{qtype = tensor<1x1x!quant.uniform>}> {volatile} : (tensor<1x1xf32>) -> tensor<1x1x!quant.uniform> // Int8-NEXT: %[[r0q0:.*]] = "tfl.quantize"(%[[q0]]) <{qtype = tensor<1x1x!quant.uniform>}> : (tensor<1x1x!quant.uniform>) -> tensor<1x1x!quant.uniform> // Int8-NEXT: %[[r1q0:.*]] = "tfl.quantize"(%[[q0]]) <{qtype = tensor<1x1x!quant.uniform>}> : (tensor<1x1x!quant.uniform>) -> tensor<1x1x!quant.uniform> // Int8-NEXT: %[[d1q0:.*]] = "tfl.dequantize"(%[[r1q0]]) : (tensor<1x1x!quant.uniform>) -> tensor<1x1xf32> // Int8-NEXT: %[[d0q0:.*]] = "tfl.dequantize"(%[[r0q0]]) : (tensor<1x1x!quant.uniform>) -> tensor<1x1xf32> // Int8-NEXT: %[[q1:.*]] = "tfl.quantize"(%arg1) <{qtype = tensor<1x1x!quant.uniform>}> {volatile} : (tensor<1x1xf32>) -> tensor<1x1x!quant.uniform> // Int8-NEXT: %[[r0q1:.*]] = "tfl.quantize"(%[[q1]]) <{qtype = tensor<1x1x!quant.uniform>}> : (tensor<1x1x!quant.uniform>) -> tensor<1x1x!quant.uniform> // Int8-NEXT: %[[d0q1:.*]] = "tfl.dequantize"(%[[r0q1]]) : (tensor<1x1x!quant.uniform>) -> tensor<1x1xf32> // Int8-NEXT: %[[q2:.*]] = "tfl.quantize"(%arg2) <{qtype = tensor<1x1x!quant.uniform>}> {volatile} : (tensor<1x1xf32>) -> tensor<1x1x!quant.uniform> // Int8-NEXT: %[[r0q2:.*]] = "tfl.quantize"(%[[q2]]) <{qtype = tensor<1x1x!quant.uniform>}> : (tensor<1x1x!quant.uniform>) -> tensor<1x1x!quant.uniform> // Int8-NEXT: %[[d0q2:.*]] = "tfl.dequantize"(%[[r0q2]]) : (tensor<1x1x!quant.uniform>) -> tensor<1x1xf32> // Int8-NEXT: %[[q3:.*]] = "tfl.quantize"(%arg3) <{qtype = tensor<1x1x!quant.uniform>}> {volatile} : (tensor<1x1xf32>) -> tensor<1x1x!quant.uniform> // Int8-NEXT: %[[r0q3:.*]] = "tfl.quantize"(%[[q3]]) <{qtype = tensor<1x1x!quant.uniform>}> : (tensor<1x1x!quant.uniform>) -> tensor<1x1x!quant.uniform> // Int8-NEXT: %[[d0q3:.*]] = "tfl.dequantize"(%[[r0q3]]) : (tensor<1x1x!quant.uniform>) -> tensor<1x1xf32> // Int8-NEXT: %[[cat1_0:.*]] = "tfl.concatenation"(%[[d0q1]], %[[d1q0]]) <{axis = -1 : i32, fused_activation_function = "NONE"}> : (tensor<1x1xf32>, tensor<1x1xf32>) -> tensor<1x2xf32> // Int8-NEXT: %[[qcat1_0:.*]] = "tfl.quantize"(%[[cat1_0]]) <{qtype = tensor<1x2x!quant.uniform>}> {volatile} : (tensor<1x2xf32>) -> tensor<1x2x!quant.uniform> // Int8-NEXT: %[[r0qcat1_0:.*]] = "tfl.quantize"(%[[qcat1_0]]) <{qtype = tensor<1x2x!quant.uniform>}> : (tensor<1x2x!quant.uniform>) -> tensor<1x2x!quant.uniform> // Int8-NEXT: %[[d0qcat1_0:.*]] = "tfl.dequantize"(%[[r0qcat1_0]]) : (tensor<1x2x!quant.uniform>) -> tensor<1x2xf32> // Int8-NEXT: %[[cat_2_0:.*]] = "tfl.concatenation"(%[[d0q2]], %[[d0q0]]) <{axis = -1 : i32, fused_activation_function = "NONE"}> : (tensor<1x1xf32>, tensor<1x1xf32>) -> tensor<1x2xf32> // Int8-NEXT: %[[qcat_2_0:.*]] = "tfl.quantize"(%[[cat_2_0]]) <{qtype = tensor<1x2x!quant.uniform>}> {volatile} : (tensor<1x2xf32>) -> tensor<1x2x!quant.uniform> // Int8-NEXT: %[[r0qcat_2_0:.*]] = "tfl.quantize"(%[[qcat_2_0]]) <{qtype = tensor<1x2x!quant.uniform>}> : (tensor<1x2x!quant.uniform>) -> tensor<1x2x!quant.uniform> // Int8-NEXT: %[[d0qcat_2_0:.*]] = "tfl.dequantize"(%[[r0qcat_2_0]]) : (tensor<1x2x!quant.uniform>) -> tensor<1x2xf32> // Int8-NEXT: %[[dqcat_2_0:.*]] = "tfl.dequantize"(%[[qcat_2_0]]) : (tensor<1x2x!quant.uniform>) -> tensor<1x2xf32> // Int8-NEXT: %[[cat_2_0_1_0:.*]] = "tfl.concatenation"(%[[dqcat_2_0]], %[[d0qcat1_0]]) <{axis = -1 : i32, fused_activation_function = "NONE"}> : (tensor<1x2xf32>, tensor<1x2xf32>) -> tensor<1x4xf32> // Int8-NEXT: %[[qcat_2_0_1_0:.*]] = "tfl.quantize"(%[[cat_2_0_1_0]]) <{qtype = tensor<1x4x!quant.uniform>}> {volatile} : (tensor<1x4xf32>) -> tensor<1x4x!quant.uniform> // Int8-NEXT: %[[dqcat_2_0_1_0:.*]] = "tfl.dequantize"(%[[qcat_2_0_1_0]]) : (tensor<1x4x!quant.uniform>) -> tensor<1x4xf32> // Int8-NEXT: %[[cat_2_0_3:.*]] = "tfl.concatenation"(%[[d0qcat_2_0]], %[[d0q3]]) <{axis = -1 : i32, fused_activation_function = "NONE"}> : (tensor<1x2xf32>, tensor<1x1xf32>) -> tensor<1x3xf32> // Int8-NEXT: %[[qcat_2_0_3:.*]] = "tfl.quantize"(%[[cat_2_0_3]]) <{qtype = tensor<1x3x!quant.uniform>}> {volatile} : (tensor<1x3xf32>) -> tensor<1x3x!quant.uniform> // Int8-NEXT: %[[dqcat_2_0_3:.*]] = "tfl.dequantize"(%[[qcat_2_0_3]]) : (tensor<1x3x!quant.uniform>) -> tensor<1x3xf32> // Int8-NEXT: return %[[dqcat_2_0_1_0]], %[[dqcat_2_0_3]] : tensor<1x4xf32>, tensor<1x3xf32> }