From 4d19a5b4626f08debcbc14a324378b9e800431d7 Mon Sep 17 00:00:00 2001 From: Elena Zhelezina Date: Tue, 26 Nov 2019 18:38:19 +0000 Subject: [PATCH 1/4] [tflite] Fix and tests for the operator PACK There is a bug in the current implementation of the operator PACK. The multiple inputs should be requantized. The current PR fixes this bug and adds a test for the quantization of the PACK operator. Change-Id: Id829a6c62ea35b6b1b64c41797c02a924c14064a --- tensorflow/lite/tools/optimize/BUILD | 1 + .../lite/tools/optimize/operator_property.cc | 1 + .../lite/tools/optimize/operator_property.h | 4 ++ .../lite/tools/optimize/quantize_model.cc | 6 +- .../tools/optimize/quantize_model_test.cc | 63 ++++++++++++++++++ tensorflow/lite/tools/optimize/test_util.cc | 2 + tensorflow/lite/tools/optimize/test_util.h | 3 + .../lite/tools/optimize/testdata/pack.bin | Bin 0 -> 732 bytes 8 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 tensorflow/lite/tools/optimize/testdata/pack.bin diff --git a/tensorflow/lite/tools/optimize/BUILD b/tensorflow/lite/tools/optimize/BUILD index 096580a826d..c650cc19a69 100644 --- a/tensorflow/lite/tools/optimize/BUILD +++ b/tensorflow/lite/tools/optimize/BUILD @@ -242,6 +242,7 @@ tf_cc_test( "//tensorflow/lite/tools/optimize:testdata/single_conv_weights_min_minus_127_max_plus_127.bin", "//tensorflow/lite/tools/optimize:testdata/single_softmax_min_minus_5_max_plus_5.bin", "//tensorflow/lite/tools/optimize:testdata/split.bin", + "//tensorflow/lite/tools/optimize:testdata/pack.bin", ], tags = [ "tflite_not_portable_android", diff --git a/tensorflow/lite/tools/optimize/operator_property.cc b/tensorflow/lite/tools/optimize/operator_property.cc index cba729ec4ca..5ea31de02a7 100644 --- a/tensorflow/lite/tools/optimize/operator_property.cc +++ b/tensorflow/lite/tools/optimize/operator_property.cc @@ -290,6 +290,7 @@ OperatorProperty GetOperatorProperty(const ModelT* model, int subgraph_index, property.arbitrary_inputs = true; property.outputs = {{0, {}}}; property.restrict_same_input_output_scale = true; + property.restrict_multiple_inputs_scale = true; property.version = 2; break; case BuiltinOperator_PAD: diff --git a/tensorflow/lite/tools/optimize/operator_property.h b/tensorflow/lite/tools/optimize/operator_property.h index 5d37aa304e5..a2b93da6ac2 100644 --- a/tensorflow/lite/tools/optimize/operator_property.h +++ b/tensorflow/lite/tools/optimize/operator_property.h @@ -85,6 +85,10 @@ struct OperatorProperty { // Force output to reuse the same scale and zero point of input. bool restrict_same_input_output_scale = false; + // In the case of multiple inputs, requantize all inputs to have + // the same scale and zero point. + bool restrict_multiple_inputs_scale = false; + // Use same min of min and max of max for each group. // Incompatable with restrict_same_input_output_scale and restricted_value. // TODO(jianlijianli): make it compatible with other restrictions when there diff --git a/tensorflow/lite/tools/optimize/quantize_model.cc b/tensorflow/lite/tools/optimize/quantize_model.cc index 304aad618d8..43b8fee4e02 100644 --- a/tensorflow/lite/tools/optimize/quantize_model.cc +++ b/tensorflow/lite/tools/optimize/quantize_model.cc @@ -300,7 +300,8 @@ TfLiteStatus ApplyConstraints(ModelT* model, if (!property.quantizable) { continue; } - if (!property.arbitrary_inputs || + if ((!property.arbitrary_inputs && + !property.restrict_multiple_inputs_scale) || !property.restrict_same_input_output_scale) { continue; } @@ -384,7 +385,8 @@ bool ShouldRestrictSameInputOutputScale( operator_property::OperatorProperty property) { // Ops with multiple inputs (i.e. concat) gets restricted in ApplyConstraints. return (!property.arbitrary_inputs && - property.restrict_same_input_output_scale); + property.restrict_same_input_output_scale && + !property.restrict_multiple_inputs_scale); } bool IsSubgraphInput(SubGraphT* subgraph, int32_t index) { diff --git a/tensorflow/lite/tools/optimize/quantize_model_test.cc b/tensorflow/lite/tools/optimize/quantize_model_test.cc index 5e736d96e5b..80cf28632b6 100644 --- a/tensorflow/lite/tools/optimize/quantize_model_test.cc +++ b/tensorflow/lite/tools/optimize/quantize_model_test.cc @@ -1124,6 +1124,69 @@ TEST_F(QuantizeCustomOpTest, VerifyMixedQuantization) { } } +class QuantizePackTest : public QuantizeModelTest { +protected: + QuantizePackTest() { + input_model_ = ReadModel(internal::kModelPack); + readonly_model_ = input_model_->GetModel(); + readonly_model_->UnPackTo(&model_); + } +}; + +TEST_F(QuantizePackTest, VerifyPack) { + auto status = QuantizeModel(&builder_, &model_, &error_reporter_); + + ASSERT_EQ(kTfLiteOk, status); + + const auto subgraph = model_.subgraphs[0].get(); + + // The model should only have 3 inputs and 1 output. + EXPECT_EQ(subgraph->inputs.size(), 3); + EXPECT_EQ(subgraph->outputs.size(), 1); + + const auto & op1 = subgraph->operators[1].get(); + const auto & op2 = subgraph->operators[2].get(); + const auto & op3 = subgraph->operators[3].get(); + const auto & op4 = subgraph->operators[4].get(); + + ASSERT_EQ(model_.operator_codes[op1->opcode_index].get()->builtin_code, + BuiltinOperator_QUANTIZE); + ASSERT_EQ(model_.operator_codes[op2->opcode_index].get()->builtin_code, + BuiltinOperator_QUANTIZE); + ASSERT_EQ(model_.operator_codes[op3->opcode_index].get()->builtin_code, + BuiltinOperator_PACK); + ASSERT_EQ(model_.operator_codes[op4->opcode_index].get()->builtin_code, + BuiltinOperator_DEQUANTIZE); + + const auto & pack_input0 = subgraph->tensors[op3->inputs[0]].get(); + const auto & pack_input1 = subgraph->tensors[op3->inputs[1]].get(); + const auto & pack_input2 = subgraph->tensors[op3->inputs[2]].get(); + + const auto & pack_output = subgraph->tensors[op3->outputs[0]].get(); + + // Check quantization parameters for input and output. + EXPECT_FLOAT_EQ(pack_input0->quantization->scale[0], + pack_input1->quantization->scale[0]); + EXPECT_FLOAT_EQ(pack_input1->quantization->scale[0], + pack_input2->quantization->scale[0]); + EXPECT_FLOAT_EQ(pack_input0->quantization->zero_point[0], + pack_input1->quantization->zero_point[0]); + EXPECT_FLOAT_EQ(pack_input1->quantization->zero_point[0], + pack_input2->quantization->zero_point[0]); + + EXPECT_FLOAT_EQ(pack_input1->quantization->scale[0], + pack_output->quantization->scale[0]); + EXPECT_FLOAT_EQ(pack_input1->quantization->zero_point[0], + pack_output->quantization->zero_point[0]); + + // Check type of input and output. + EXPECT_EQ(pack_output->type, TensorType_INT8); + EXPECT_EQ(pack_input0->type, TensorType_INT8); + EXPECT_EQ(pack_input1->type, TensorType_INT8); + EXPECT_EQ(pack_input2->type, TensorType_INT8); + +}; + } // namespace } // namespace optimize } // namespace tflite diff --git a/tensorflow/lite/tools/optimize/test_util.cc b/tensorflow/lite/tools/optimize/test_util.cc index 74524a18081..ddec8108fc3 100644 --- a/tensorflow/lite/tools/optimize/test_util.cc +++ b/tensorflow/lite/tools/optimize/test_util.cc @@ -49,6 +49,8 @@ const char* kModelMixed = "mixed.bin"; const char* kModelSplit = "split.bin"; +const char* kModelPack = "pack.bin"; + const char* kLstmCalibrated = "lstm_calibrated.bin"; const char* kLstmQuantized = "lstm_quantized.bin"; diff --git a/tensorflow/lite/tools/optimize/test_util.h b/tensorflow/lite/tools/optimize/test_util.h index 12c46aa882b..e12a40bb82b 100644 --- a/tensorflow/lite/tools/optimize/test_util.h +++ b/tensorflow/lite/tools/optimize/test_util.h @@ -76,6 +76,9 @@ extern const char* kModelMixed; // Test model with split op. extern const char* kModelSplit; +// Test model with pack op. +extern const char* kModelPack; + // Test model with LSTM op. extern const char* kLstmCalibrated; extern const char* kLstmQuantized; diff --git a/tensorflow/lite/tools/optimize/testdata/pack.bin b/tensorflow/lite/tools/optimize/testdata/pack.bin new file mode 100644 index 0000000000000000000000000000000000000000..c367eea06a5edea1a70670ad7b6a1bf7f309cd7c GIT binary patch literal 732 zcma)4y-LGS7(HriIs^@xp-6@f9VHm+Ah-w-K@d8a!O1R-n4ziERB+PKM{soL6Z9E; zAO{BrC7yGW6rl>eaQMD^?!D*xyFP&U^t=mf!H0z=9Juhvw#Wc$#Oo^XLib0X$M(sQq1SSucyu+O9>>ci(iJZ70>U>-DJ=O(NrOi6EJX0;5 zBjwgMO!_l0w88}~V8cwL?6u1sa6+hW>a%8~ lzowb#|NK|G&dvr2KUDre*YxLi@0F|iB)xK0wwV<-7eBf5RA2xA literal 0 HcmV?d00001 From a0338d6505bfa40a8cca32d3610febd098082755 Mon Sep 17 00:00:00 2001 From: Elena Zhelezina Date: Tue, 10 Dec 2019 10:44:39 +0000 Subject: [PATCH 2/4] Addressed review comments. Change-Id: Ifefd7825025eedda29c1fc5baf7a14b5f0acae09 --- tensorflow/lite/tools/optimize/operator_property.cc | 1 - tensorflow/lite/tools/optimize/operator_property.h | 4 ---- tensorflow/lite/tools/optimize/quantize_model.cc | 6 ++---- tensorflow/lite/tools/optimize/quantize_model_test.cc | 2 -- 4 files changed, 2 insertions(+), 11 deletions(-) diff --git a/tensorflow/lite/tools/optimize/operator_property.cc b/tensorflow/lite/tools/optimize/operator_property.cc index 30ae84ed53c..2eacd62725b 100644 --- a/tensorflow/lite/tools/optimize/operator_property.cc +++ b/tensorflow/lite/tools/optimize/operator_property.cc @@ -779,7 +779,6 @@ OperatorProperty GetOperatorProperty(const ModelT* model, int subgraph_index, property.arbitrary_inputs = true; property.outputs = {{0, {}}}; property.restrict_same_input_output_scale = true; - property.restrict_multiple_inputs_scale = true; property.version = 2; break; case BuiltinOperator_PAD: diff --git a/tensorflow/lite/tools/optimize/operator_property.h b/tensorflow/lite/tools/optimize/operator_property.h index a2b93da6ac2..5d37aa304e5 100644 --- a/tensorflow/lite/tools/optimize/operator_property.h +++ b/tensorflow/lite/tools/optimize/operator_property.h @@ -85,10 +85,6 @@ struct OperatorProperty { // Force output to reuse the same scale and zero point of input. bool restrict_same_input_output_scale = false; - // In the case of multiple inputs, requantize all inputs to have - // the same scale and zero point. - bool restrict_multiple_inputs_scale = false; - // Use same min of min and max of max for each group. // Incompatable with restrict_same_input_output_scale and restricted_value. // TODO(jianlijianli): make it compatible with other restrictions when there diff --git a/tensorflow/lite/tools/optimize/quantize_model.cc b/tensorflow/lite/tools/optimize/quantize_model.cc index 375c4b89462..30d9f961098 100644 --- a/tensorflow/lite/tools/optimize/quantize_model.cc +++ b/tensorflow/lite/tools/optimize/quantize_model.cc @@ -300,8 +300,7 @@ TfLiteStatus ApplyConstraints(ModelT* model, if (!property.quantizable) { continue; } - if ((!property.arbitrary_inputs && - !property.restrict_multiple_inputs_scale) || + if ((!property.arbitrary_inputs) || !property.restrict_same_input_output_scale) { continue; } @@ -385,8 +384,7 @@ bool ShouldRestrictSameInputOutputScale( operator_property::OperatorProperty property) { // Ops with multiple inputs (i.e. concat) gets restricted in ApplyConstraints. return (!property.arbitrary_inputs && - property.restrict_same_input_output_scale && - !property.restrict_multiple_inputs_scale); + property.restrict_same_input_output_scale); } bool IsSubgraphInput(SubGraphT* subgraph, int32_t index) { diff --git a/tensorflow/lite/tools/optimize/quantize_model_test.cc b/tensorflow/lite/tools/optimize/quantize_model_test.cc index b3eca76840d..85afbee8c42 100644 --- a/tensorflow/lite/tools/optimize/quantize_model_test.cc +++ b/tensorflow/lite/tools/optimize/quantize_model_test.cc @@ -1256,13 +1256,11 @@ class QuantizeUnpackTest : public QuantizeModelTest { }; TEST_F(QuantizeUnpackTest, VerifyUnpack) { - auto status = QuantizeModel(&builder_, &model_, &error_reporter_); ASSERT_EQ(kTfLiteOk, status); const auto subgraph = model_.subgraphs[0].get(); - auto op = subgraph->operators[1].get(); auto float_graph = readonly_model_->subgraphs()->Get(0); From c93191244a33100728bd39a24e104cc1a4636ffd Mon Sep 17 00:00:00 2001 From: Elena Zhelezina Date: Tue, 10 Dec 2019 11:26:34 +0000 Subject: [PATCH 3/4] Addressed review comments. Change-Id: Ibaca013d126b9a50e775247f2a6df90244160eb9 --- tensorflow/lite/tools/optimize/quantize_model.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/lite/tools/optimize/quantize_model.cc b/tensorflow/lite/tools/optimize/quantize_model.cc index 30d9f961098..42db16eb965 100644 --- a/tensorflow/lite/tools/optimize/quantize_model.cc +++ b/tensorflow/lite/tools/optimize/quantize_model.cc @@ -300,7 +300,7 @@ TfLiteStatus ApplyConstraints(ModelT* model, if (!property.quantizable) { continue; } - if ((!property.arbitrary_inputs) || + if (!property.arbitrary_inputs || !property.restrict_same_input_output_scale) { continue; } From df972879598975ebe396080b41505a2656a8a284 Mon Sep 17 00:00:00 2001 From: Elena Zhelezina Date: Wed, 11 Dec 2019 11:16:53 +0000 Subject: [PATCH 4/4] Fix Ubuntu sanity check. Change-Id: I1e15495f001d2fe56326c8b056a73756a5e5e04b --- tensorflow/lite/tools/optimize/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/lite/tools/optimize/BUILD b/tensorflow/lite/tools/optimize/BUILD index 9e322fedc90..5ff5b7884c1 100644 --- a/tensorflow/lite/tools/optimize/BUILD +++ b/tensorflow/lite/tools/optimize/BUILD @@ -239,12 +239,12 @@ tf_cc_test( "//tensorflow/lite/tools/optimize:testdata/lstm_quantized2.bin", "//tensorflow/lite/tools/optimize:testdata/mixed.bin", "//tensorflow/lite/tools/optimize:testdata/multi_input_add_reshape.bin", + "//tensorflow/lite/tools/optimize:testdata/pack.bin", "//tensorflow/lite/tools/optimize:testdata/single_avg_pool_min_minus_5_max_plus_5.bin", "//tensorflow/lite/tools/optimize:testdata/single_conv_weights_min_0_max_plus_10.bin", "//tensorflow/lite/tools/optimize:testdata/single_conv_weights_min_minus_127_max_plus_127.bin", "//tensorflow/lite/tools/optimize:testdata/single_softmax_min_minus_5_max_plus_5.bin", "//tensorflow/lite/tools/optimize:testdata/split.bin", - "//tensorflow/lite/tools/optimize:testdata/pack.bin", "//tensorflow/lite/tools/optimize:testdata/unpack.bin", ], tags = [