1 /* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #include "tensorflow/lite/tools/optimize/modify_model_interface.h"
16
17 #include <memory>
18 #include <utility>
19
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 #include "absl/memory/memory.h"
23 #include "tensorflow/lite/model.h"
24 #include "tensorflow/lite/schema/schema_generated.h"
25 #include "tensorflow/lite/schema/schema_utils.h"
26
27 namespace tflite {
28 namespace optimize {
29 namespace {
30
31 // Create a model with 1 quant, 1 FC, 1 dequant
CreateQuantizedModelSingleInputOutput(const TensorType & quantization_type)32 std::unique_ptr<ModelT> CreateQuantizedModelSingleInputOutput(
33 const TensorType& quantization_type) {
34 auto model = std::make_unique<ModelT>();
35 auto subgraph = std::make_unique<tflite::SubGraphT>();
36 auto buffer = std::make_unique<tflite::BufferT>();
37 auto quant_op_code = std::make_unique<OperatorCodeT>();
38 auto quant_op = std::make_unique<OperatorT>();
39 auto fc_op_code = std::make_unique<OperatorCodeT>();
40 auto fc_op = std::make_unique<OperatorT>();
41 auto dequant_op_code = std::make_unique<OperatorCodeT>();
42 auto dequant_op = std::make_unique<OperatorT>();
43
44 model->subgraphs.push_back(std::move(subgraph));
45
46 // Op code
47 quant_op_code->builtin_code = BuiltinOperator_QUANTIZE;
48 quant_op_code->deprecated_builtin_code =
49 static_cast<int8_t>(BuiltinOperator_QUANTIZE);
50 quant_op_code->version = 2;
51
52 fc_op_code->builtin_code = BuiltinOperator_FULLY_CONNECTED;
53 fc_op_code->deprecated_builtin_code =
54 static_cast<int8_t>(BuiltinOperator_FULLY_CONNECTED);
55 fc_op_code->version = 2;
56
57 dequant_op_code->builtin_code = BuiltinOperator_DEQUANTIZE;
58 dequant_op_code->deprecated_builtin_code =
59 static_cast<int8_t>(BuiltinOperator_DEQUANTIZE);
60 dequant_op_code->version = 2;
61
62 // Op.
63 quant_op->opcode_index = 0;
64 quant_op->inputs = {0};
65 quant_op->outputs = {1};
66
67 fc_op->opcode_index = 1;
68 fc_op->inputs = {1};
69 fc_op->outputs = {2};
70
71 dequant_op->opcode_index = 2;
72 dequant_op->inputs = {2};
73 dequant_op->outputs = {3};
74
75 model->subgraphs[0]->operators.push_back(std::move(quant_op));
76 model->subgraphs[0]->operators.push_back(std::move(fc_op));
77 model->subgraphs[0]->operators.push_back(std::move(dequant_op));
78
79 model->operator_codes.push_back(std::move(quant_op_code));
80 model->operator_codes.push_back(std::move(fc_op_code));
81 model->operator_codes.push_back(std::move(dequant_op_code));
82
83 // Model input/output.
84 model->subgraphs[0]->inputs = {0};
85 model->subgraphs[0]->outputs = {3};
86
87 // Tensors
88 auto tensor_0 = std::make_unique<TensorT>();
89 tensor_0->name = "tensor_0";
90 tensor_0->shape = {};
91 tensor_0->type = TensorType_FLOAT32;
92
93 auto tensor_1 = std::make_unique<TensorT>();
94 tensor_1->quantization = std::make_unique<QuantizationParametersT>();
95 tensor_1->quantization->scale.push_back(0.35);
96 tensor_1->quantization->zero_point.push_back(28);
97 tensor_1->name = "tensor_1";
98 tensor_1->shape = {};
99 tensor_1->type = quantization_type;
100
101 auto tensor_2 = std::make_unique<TensorT>();
102 tensor_2->quantization = std::make_unique<QuantizationParametersT>();
103 tensor_2->quantization->scale.push_back(0.12);
104 tensor_2->quantization->zero_point.push_back(50);
105 tensor_2->name = "tensor_2";
106 tensor_2->shape = {};
107 tensor_2->type = quantization_type;
108
109 auto tensor_3 = std::make_unique<TensorT>();
110 tensor_3->name = "tensor_3";
111 tensor_3->shape = {};
112 tensor_3->type = TensorType_FLOAT32;
113
114 model->subgraphs[0]->tensors.push_back(std::move(tensor_0));
115 model->subgraphs[0]->tensors.push_back(std::move(tensor_1));
116 model->subgraphs[0]->tensors.push_back(std::move(tensor_2));
117 model->subgraphs[0]->tensors.push_back(std::move(tensor_3));
118
119 // Buffer
120 model->buffers.push_back(std::move(buffer));
121
122 return model;
123 }
124
125 // Create a model with 2 quant, 1 FC, 2 dequant
126 // The model mimics the behavior of the quantize_model.cc.
CreateQuantizedModelMultipleInputOutput(const TensorType & quantization_type)127 std::unique_ptr<ModelT> CreateQuantizedModelMultipleInputOutput(
128 const TensorType& quantization_type) {
129 auto model = std::make_unique<ModelT>();
130 auto subgraph = std::make_unique<tflite::SubGraphT>();
131 auto buffer = std::make_unique<tflite::BufferT>();
132 auto quant_op_code = std::make_unique<OperatorCodeT>();
133 auto quant_op_1 = std::make_unique<OperatorT>();
134 auto quant_op_2 = std::make_unique<OperatorT>();
135 auto fc_op_code = std::make_unique<OperatorCodeT>();
136 auto fc_op = std::make_unique<OperatorT>();
137 auto dequant_op_code = std::make_unique<OperatorCodeT>();
138 auto dequant_op_1 = std::make_unique<OperatorT>();
139 auto dequant_op_2 = std::make_unique<OperatorT>();
140
141 model->subgraphs.push_back(std::move(subgraph));
142
143 // Op code
144 quant_op_code->builtin_code = BuiltinOperator_QUANTIZE;
145 quant_op_code->deprecated_builtin_code =
146 static_cast<int8_t>(BuiltinOperator_QUANTIZE);
147 quant_op_code->version = 2;
148
149 fc_op_code->builtin_code = BuiltinOperator_FULLY_CONNECTED;
150 fc_op_code->deprecated_builtin_code =
151 static_cast<int8_t>(BuiltinOperator_FULLY_CONNECTED);
152 fc_op_code->version = 2;
153
154 dequant_op_code->builtin_code = BuiltinOperator_DEQUANTIZE;
155 dequant_op_code->deprecated_builtin_code =
156 static_cast<int8_t>(BuiltinOperator_DEQUANTIZE);
157 dequant_op_code->version = 2;
158
159 // Op.
160 quant_op_1->opcode_index = 0;
161 quant_op_1->inputs = {0};
162 quant_op_1->outputs = {2};
163 quant_op_2->opcode_index = 0;
164 quant_op_2->inputs = {1};
165 quant_op_2->outputs = {3};
166
167 fc_op->opcode_index = 1;
168 fc_op->inputs = {2, 3};
169 fc_op->outputs = {4, 5};
170
171 dequant_op_1->opcode_index = 2;
172 dequant_op_1->inputs = {4};
173 dequant_op_1->outputs = {6};
174 dequant_op_2->opcode_index = 2;
175 dequant_op_2->inputs = {5};
176 dequant_op_2->outputs = {7};
177
178 model->subgraphs[0]->operators.push_back(std::move(quant_op_1));
179 model->subgraphs[0]->operators.push_back(std::move(quant_op_2));
180 model->subgraphs[0]->operators.push_back(std::move(fc_op));
181 model->subgraphs[0]->operators.push_back(std::move(dequant_op_1));
182 model->subgraphs[0]->operators.push_back(std::move(dequant_op_2));
183
184 model->operator_codes.push_back(std::move(quant_op_code));
185 model->operator_codes.push_back(std::move(fc_op_code));
186 model->operator_codes.push_back(std::move(dequant_op_code));
187
188 // Model input/output.
189 model->subgraphs[0]->inputs = {0, 1};
190 model->subgraphs[0]->outputs = {6, 7};
191
192 // Tensors
193 auto tensor_0 = std::make_unique<TensorT>();
194 tensor_0->name = "tensor_0";
195 tensor_0->shape = {};
196 tensor_0->type = TensorType_FLOAT32;
197
198 auto tensor_1 = std::make_unique<TensorT>();
199 tensor_1->name = "tensor_1";
200 tensor_1->shape = {};
201 tensor_1->type = TensorType_FLOAT32;
202
203 auto tensor_2 = std::make_unique<TensorT>();
204 tensor_2->quantization = std::make_unique<QuantizationParametersT>();
205 tensor_2->quantization->scale.push_back(0.35);
206 tensor_2->quantization->zero_point.push_back(28);
207 tensor_2->name = "tensor_2";
208 tensor_2->shape = {};
209 tensor_2->type = quantization_type;
210
211 auto tensor_3 = std::make_unique<TensorT>();
212 tensor_3->quantization = std::make_unique<QuantizationParametersT>();
213 tensor_3->quantization->scale.push_back(0.12);
214 tensor_3->quantization->zero_point.push_back(50);
215 tensor_3->name = "tensor_3";
216 tensor_3->shape = {};
217 tensor_3->type = quantization_type;
218
219 auto tensor_4 = std::make_unique<TensorT>();
220 tensor_4->quantization = std::make_unique<QuantizationParametersT>();
221 tensor_4->quantization->scale.push_back(0.45);
222 tensor_4->quantization->zero_point.push_back(28);
223 tensor_4->name = "tensor_4";
224 tensor_4->shape = {};
225 tensor_4->type = quantization_type;
226
227 auto tensor_5 = std::make_unique<TensorT>();
228 tensor_5->quantization = std::make_unique<QuantizationParametersT>();
229 tensor_5->quantization->scale.push_back(0.22);
230 tensor_5->quantization->zero_point.push_back(50);
231 tensor_5->name = "tensor_5";
232 tensor_5->shape = {};
233 tensor_5->type = quantization_type;
234
235 auto tensor_6 = std::make_unique<TensorT>();
236 tensor_6->name = "tensor_6";
237 tensor_6->shape = {};
238 tensor_6->type = TensorType_FLOAT32;
239
240 auto tensor_7 = std::make_unique<TensorT>();
241 tensor_7->name = "tensor_7";
242 tensor_7->shape = {};
243 tensor_7->type = TensorType_FLOAT32;
244
245 model->subgraphs[0]->tensors.push_back(std::move(tensor_0));
246 model->subgraphs[0]->tensors.push_back(std::move(tensor_1));
247 model->subgraphs[0]->tensors.push_back(std::move(tensor_2));
248 model->subgraphs[0]->tensors.push_back(std::move(tensor_3));
249 model->subgraphs[0]->tensors.push_back(std::move(tensor_4));
250 model->subgraphs[0]->tensors.push_back(std::move(tensor_5));
251 model->subgraphs[0]->tensors.push_back(std::move(tensor_6));
252 model->subgraphs[0]->tensors.push_back(std::move(tensor_7));
253
254 // Buffer
255 model->buffers.push_back(std::move(buffer));
256
257 return model;
258 }
259
260 // Create a model with 1 FC.
CreateFloatModel()261 std::unique_ptr<ModelT> CreateFloatModel() {
262 auto model = std::make_unique<ModelT>();
263 auto subgraph = std::make_unique<tflite::SubGraphT>();
264 auto buffer = std::make_unique<tflite::BufferT>();
265 auto fc_op_code = std::make_unique<OperatorCodeT>();
266 auto fc_op = std::make_unique<OperatorT>();
267
268 model->subgraphs.push_back(std::move(subgraph));
269
270 // Op code
271 fc_op_code->builtin_code = BuiltinOperator_FULLY_CONNECTED;
272 fc_op_code->deprecated_builtin_code =
273 static_cast<int8_t>(BuiltinOperator_FULLY_CONNECTED);
274 fc_op_code->version = 2;
275
276 // Op.
277 fc_op->opcode_index = 0;
278 fc_op->inputs = {0};
279 fc_op->outputs = {1};
280
281 model->subgraphs[0]->operators.push_back(std::move(fc_op));
282 model->operator_codes.push_back(std::move(fc_op_code));
283
284 // Model input/output.
285 model->subgraphs[0]->inputs = {0};
286 model->subgraphs[0]->outputs = {1};
287
288 // Tensors
289 auto tensor_0 = std::make_unique<TensorT>();
290 tensor_0->name = "tensor_0";
291 tensor_0->shape = {};
292 tensor_0->type = TensorType_FLOAT32;
293
294 auto tensor_1 = std::make_unique<TensorT>();
295 tensor_1->name = "tensor_1";
296 tensor_1->shape = {};
297 tensor_1->type = TensorType_FLOAT32;
298
299 model->subgraphs[0]->tensors.push_back(std::move(tensor_0));
300 model->subgraphs[0]->tensors.push_back(std::move(tensor_1));
301
302 // Buffer
303 model->buffers.push_back(std::move(buffer));
304
305 return model;
306 }
307
308 struct ModelInterface : ::testing::TestWithParam<tflite::TensorType> {};
309
TEST_P(ModelInterface,SingleInputOutput)310 TEST_P(ModelInterface, SingleInputOutput) {
311 TensorType quantization_type = GetParam();
312
313 auto model = CreateQuantizedModelSingleInputOutput(quantization_type);
314
315 // Change model type.
316 flatbuffers::FlatBufferBuilder builder;
317 EXPECT_EQ(ModifyModelInterface(&builder, model.get(), quantization_type,
318 quantization_type),
319 kTfLiteOk);
320
321 // Verify results.
322 EXPECT_EQ(model->subgraphs.size(), 1);
323 EXPECT_EQ(model->subgraphs[0]->tensors.size(), 3);
324 EXPECT_EQ(model->subgraphs[0]->inputs.size(), 1);
325 EXPECT_EQ(model->subgraphs[0]->inputs[0], 1);
326 EXPECT_EQ(model->subgraphs[0]->outputs.size(), 1);
327 EXPECT_EQ(model->subgraphs[0]->outputs[0], 2);
328 EXPECT_EQ(model->operator_codes.size(), 3);
329 EXPECT_EQ(model->subgraphs[0]->operators.size(), 1);
330 EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 1);
331
332 auto fc_op = model->subgraphs[0]->operators[0].get();
333
334 auto input = model->subgraphs[0]->tensors[fc_op->inputs[0]].get();
335 EXPECT_EQ(input->name, "tensor_1");
336 EXPECT_EQ(input->type, quantization_type);
337 EXPECT_FLOAT_EQ(input->quantization->scale[0], 0.35);
338 EXPECT_EQ(input->quantization->zero_point[0], 28);
339
340 auto output = model->subgraphs[0]->tensors[fc_op->outputs[0]].get();
341 EXPECT_EQ(output->name, "tensor_2");
342 EXPECT_EQ(output->type, quantization_type);
343 EXPECT_FLOAT_EQ(output->quantization->scale[0], 0.12);
344 EXPECT_EQ(output->quantization->zero_point[0], 50);
345 }
346
TEST_P(ModelInterface,MutipleInputOutput)347 TEST_P(ModelInterface, MutipleInputOutput) {
348 TensorType quantization_type = GetParam();
349
350 auto model = CreateQuantizedModelMultipleInputOutput(quantization_type);
351
352 // Change model type.
353 flatbuffers::FlatBufferBuilder builder;
354 EXPECT_EQ(ModifyModelInterface(&builder, model.get(), quantization_type,
355 quantization_type),
356 kTfLiteOk);
357
358 // Verify results.
359 EXPECT_EQ(model->subgraphs.size(), 1);
360 EXPECT_EQ(model->subgraphs[0]->tensors.size(), 6);
361 EXPECT_EQ(model->subgraphs[0]->inputs.size(), 2);
362 EXPECT_EQ(model->subgraphs[0]->inputs[0], 2);
363 EXPECT_EQ(model->subgraphs[0]->inputs[1], 3);
364 EXPECT_EQ(model->subgraphs[0]->outputs.size(), 2);
365 EXPECT_EQ(model->subgraphs[0]->outputs[0], 4);
366 EXPECT_EQ(model->subgraphs[0]->outputs[1], 5);
367 EXPECT_EQ(model->operator_codes.size(), 3);
368 EXPECT_EQ(model->subgraphs[0]->operators.size(), 1);
369 EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 1);
370
371 auto fc_op = model->subgraphs[0]->operators[0].get();
372
373 auto input_1 = model->subgraphs[0]->tensors[fc_op->inputs[0]].get();
374 EXPECT_EQ(input_1->name, "tensor_2");
375 EXPECT_EQ(input_1->type, quantization_type);
376 EXPECT_FLOAT_EQ(input_1->quantization->scale[0], 0.35);
377 EXPECT_EQ(input_1->quantization->zero_point[0], 28);
378
379 auto input_2 = model->subgraphs[0]->tensors[fc_op->inputs[1]].get();
380 EXPECT_EQ(input_2->name, "tensor_3");
381 EXPECT_EQ(input_2->type, quantization_type);
382 EXPECT_FLOAT_EQ(input_2->quantization->scale[0], 0.12);
383 EXPECT_EQ(input_2->quantization->zero_point[0], 50);
384
385 auto output_1 = model->subgraphs[0]->tensors[fc_op->outputs[0]].get();
386 EXPECT_EQ(output_1->name, "tensor_4");
387 EXPECT_EQ(output_1->type, quantization_type);
388 EXPECT_FLOAT_EQ(output_1->quantization->scale[0], 0.45);
389 EXPECT_EQ(output_1->quantization->zero_point[0], 28);
390
391 auto output_2 = model->subgraphs[0]->tensors[fc_op->outputs[1]].get();
392 EXPECT_EQ(output_2->name, "tensor_5");
393 EXPECT_EQ(output_2->type, quantization_type);
394 EXPECT_FLOAT_EQ(output_2->quantization->scale[0], 0.22);
395 EXPECT_EQ(output_2->quantization->zero_point[0], 50);
396 }
397
398 INSTANTIATE_TEST_SUITE_P(MultipleInputOutputTests, ModelInterface,
399 ::testing::Values(TensorType_INT8, TensorType_INT16));
400
TEST(ModelInterface,MixedTypeSingleInputOutput)401 TEST(ModelInterface, MixedTypeSingleInputOutput) {
402 auto model = CreateQuantizedModelSingleInputOutput(TensorType_INT8);
403
404 // Change model type.
405 flatbuffers::FlatBufferBuilder builder;
406 EXPECT_EQ(ModifyModelInterface(&builder, model.get(), TensorType_UINT8,
407 TensorType_INT8),
408 kTfLiteOk);
409
410 // Verify results.
411 EXPECT_EQ(model->subgraphs.size(), 1);
412 EXPECT_EQ(model->subgraphs[0]->tensors.size(), 3);
413 EXPECT_EQ(model->subgraphs[0]->inputs.size(), 1);
414 EXPECT_EQ(model->subgraphs[0]->inputs[0], 0);
415 EXPECT_EQ(model->subgraphs[0]->outputs.size(), 1);
416 EXPECT_EQ(model->subgraphs[0]->outputs[0], 2);
417 EXPECT_EQ(model->operator_codes.size(), 3);
418 EXPECT_EQ(model->subgraphs[0]->operators.size(), 2);
419 EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 0);
420 EXPECT_EQ(model->subgraphs[0]->operators[1]->opcode_index, 1);
421
422 auto quant_op = model->subgraphs[0]->operators[0].get();
423 auto input = model->subgraphs[0]->tensors[quant_op->inputs[0]].get();
424 EXPECT_EQ(input->name, "tensor_0");
425 EXPECT_EQ(input->type, TensorType_UINT8);
426 EXPECT_FLOAT_EQ(input->quantization->scale[0], 0.35);
427 EXPECT_EQ(input->quantization->zero_point[0], 156);
428
429 auto fc_op = model->subgraphs[0]->operators[1].get();
430 auto output = model->subgraphs[0]->tensors[fc_op->outputs[0]].get();
431 EXPECT_EQ(output->name, "tensor_2");
432 EXPECT_EQ(output->type, TensorType_INT8);
433 EXPECT_FLOAT_EQ(output->quantization->scale[0], 0.12);
434 EXPECT_EQ(output->quantization->zero_point[0], 50);
435 }
436
TEST(ModelInterface,Uint8SingleInputOutput)437 TEST(ModelInterface, Uint8SingleInputOutput) {
438 auto model = CreateQuantizedModelSingleInputOutput(TensorType_INT8);
439
440 // Change model type.
441 flatbuffers::FlatBufferBuilder builder;
442 EXPECT_EQ(ModifyModelInterface(&builder, model.get(), TensorType_UINT8,
443 TensorType_UINT8),
444 kTfLiteOk);
445
446 // Verify results.
447 EXPECT_EQ(model->subgraphs.size(), 1);
448 EXPECT_EQ(model->subgraphs[0]->tensors.size(), 4);
449 EXPECT_EQ(model->subgraphs[0]->inputs.size(), 1);
450 EXPECT_EQ(model->subgraphs[0]->inputs[0], 0);
451 EXPECT_EQ(model->subgraphs[0]->outputs.size(), 1);
452 EXPECT_EQ(model->subgraphs[0]->outputs[0], 3);
453 EXPECT_EQ(model->operator_codes.size(), 3);
454 EXPECT_EQ(model->subgraphs[0]->operators.size(), 3);
455 EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 0);
456 EXPECT_EQ(model->subgraphs[0]->operators[1]->opcode_index, 1);
457 EXPECT_EQ(model->subgraphs[0]->operators[2]->opcode_index, 0);
458
459 auto input_quant_op = model->subgraphs[0]->operators[0].get();
460 auto input = model->subgraphs[0]->tensors[input_quant_op->inputs[0]].get();
461 EXPECT_EQ(input->name, "tensor_0");
462 EXPECT_EQ(input->type, TensorType_UINT8);
463 EXPECT_FLOAT_EQ(input->quantization->scale[0], 0.35);
464 EXPECT_EQ(input->quantization->zero_point[0], 156);
465
466 auto output_quant_op = model->subgraphs[0]->operators[2].get();
467 auto output = model->subgraphs[0]->tensors[output_quant_op->outputs[0]].get();
468 EXPECT_EQ(output->name, "tensor_3");
469 EXPECT_EQ(output->type, TensorType_UINT8);
470 EXPECT_FLOAT_EQ(output->quantization->scale[0], 0.12);
471 EXPECT_EQ(output->quantization->zero_point[0], 178);
472 }
473
TEST(ModelInterface,Uint8MutipleInputOutput)474 TEST(ModelInterface, Uint8MutipleInputOutput) {
475 auto model = CreateQuantizedModelMultipleInputOutput(TensorType_INT8);
476
477 // Change model type.
478 flatbuffers::FlatBufferBuilder builder;
479 EXPECT_EQ(ModifyModelInterface(&builder, model.get(), TensorType_UINT8,
480 TensorType_UINT8),
481 kTfLiteOk);
482
483 // Verify results.
484 EXPECT_EQ(model->subgraphs.size(), 1);
485 EXPECT_EQ(model->subgraphs[0]->tensors.size(), 8);
486 EXPECT_EQ(model->subgraphs[0]->inputs.size(), 2);
487 EXPECT_EQ(model->subgraphs[0]->inputs[0], 0);
488 EXPECT_EQ(model->subgraphs[0]->inputs[1], 1);
489 EXPECT_EQ(model->subgraphs[0]->outputs.size(), 2);
490 EXPECT_EQ(model->subgraphs[0]->outputs[0], 6);
491 EXPECT_EQ(model->subgraphs[0]->outputs[1], 7);
492 EXPECT_EQ(model->operator_codes.size(), 3);
493 EXPECT_EQ(model->subgraphs[0]->operators.size(), 5);
494 EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 0);
495 EXPECT_EQ(model->subgraphs[0]->operators[1]->opcode_index, 0);
496 EXPECT_EQ(model->subgraphs[0]->operators[2]->opcode_index, 1);
497 EXPECT_EQ(model->subgraphs[0]->operators[3]->opcode_index, 0);
498 EXPECT_EQ(model->subgraphs[0]->operators[4]->opcode_index, 0);
499
500 auto input_quant_1 = model->subgraphs[0]->operators[0].get();
501 auto input_1 = model->subgraphs[0]->tensors[input_quant_1->inputs[0]].get();
502 EXPECT_EQ(input_1->name, "tensor_0");
503 EXPECT_EQ(input_1->type, TensorType_UINT8);
504 EXPECT_FLOAT_EQ(input_1->quantization->scale[0], 0.35);
505 EXPECT_EQ(input_1->quantization->zero_point[0], 156);
506
507 auto input_quant_2 = model->subgraphs[0]->operators[1].get();
508 auto input_2 = model->subgraphs[0]->tensors[input_quant_2->inputs[0]].get();
509 EXPECT_EQ(input_2->name, "tensor_1");
510 EXPECT_EQ(input_2->type, TensorType_UINT8);
511 EXPECT_FLOAT_EQ(input_2->quantization->scale[0], 0.12);
512 EXPECT_EQ(input_2->quantization->zero_point[0], 178);
513
514 auto output_quant_1 = model->subgraphs[0]->operators[3].get();
515 auto output_1 =
516 model->subgraphs[0]->tensors[output_quant_1->outputs[0]].get();
517 EXPECT_EQ(output_1->name, "tensor_6");
518 EXPECT_EQ(output_1->type, TensorType_UINT8);
519 EXPECT_FLOAT_EQ(output_1->quantization->scale[0], 0.45);
520 EXPECT_EQ(output_1->quantization->zero_point[0], 156);
521
522 auto output_quant_2 = model->subgraphs[0]->operators[4].get();
523 auto output_2 =
524 model->subgraphs[0]->tensors[output_quant_2->outputs[0]].get();
525 EXPECT_EQ(output_2->name, "tensor_7");
526 EXPECT_EQ(output_2->type, TensorType_UINT8);
527 EXPECT_FLOAT_EQ(output_2->quantization->scale[0], 0.22);
528 EXPECT_EQ(output_2->quantization->zero_point[0], 178);
529 }
530
TEST(ModelInterface,Int8MutipleInputOutput)531 TEST(ModelInterface, Int8MutipleInputOutput) {
532 auto model = CreateQuantizedModelMultipleInputOutput(TensorType_INT8);
533
534 // Change model type.
535 flatbuffers::FlatBufferBuilder builder;
536 EXPECT_EQ(ModifyModelInterface(&builder, model.get(), TensorType_INT8,
537 TensorType_INT8),
538 kTfLiteOk);
539
540 // Verify results.
541 EXPECT_EQ(model->subgraphs.size(), 1);
542 EXPECT_EQ(model->subgraphs[0]->tensors.size(), 6);
543 EXPECT_EQ(model->subgraphs[0]->inputs.size(), 2);
544 EXPECT_EQ(model->subgraphs[0]->inputs[0], 2);
545 EXPECT_EQ(model->subgraphs[0]->inputs[1], 3);
546 EXPECT_EQ(model->subgraphs[0]->outputs.size(), 2);
547 EXPECT_EQ(model->subgraphs[0]->outputs[0], 4);
548 EXPECT_EQ(model->subgraphs[0]->outputs[1], 5);
549 EXPECT_EQ(model->operator_codes.size(), 3);
550 EXPECT_EQ(model->subgraphs[0]->operators.size(), 1);
551 EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 1);
552
553 auto fc_op = model->subgraphs[0]->operators[0].get();
554
555 auto input_1 = model->subgraphs[0]->tensors[fc_op->inputs[0]].get();
556 EXPECT_EQ(input_1->name, "tensor_2");
557 EXPECT_EQ(input_1->type, TensorType_INT8);
558 EXPECT_FLOAT_EQ(input_1->quantization->scale[0], 0.35);
559 EXPECT_EQ(input_1->quantization->zero_point[0], 28);
560
561 auto input_2 = model->subgraphs[0]->tensors[fc_op->inputs[1]].get();
562 EXPECT_EQ(input_2->name, "tensor_3");
563 EXPECT_EQ(input_2->type, TensorType_INT8);
564 EXPECT_FLOAT_EQ(input_2->quantization->scale[0], 0.12);
565 EXPECT_EQ(input_2->quantization->zero_point[0], 50);
566
567 auto output_1 = model->subgraphs[0]->tensors[fc_op->outputs[0]].get();
568 EXPECT_EQ(output_1->name, "tensor_4");
569 EXPECT_EQ(output_1->type, TensorType_INT8);
570 EXPECT_FLOAT_EQ(output_1->quantization->scale[0], 0.45);
571 EXPECT_EQ(output_1->quantization->zero_point[0], 28);
572
573 auto output_2 = model->subgraphs[0]->tensors[fc_op->outputs[1]].get();
574 EXPECT_EQ(output_2->name, "tensor_5");
575 EXPECT_EQ(output_2->type, TensorType_INT8);
576 EXPECT_FLOAT_EQ(output_2->quantization->scale[0], 0.22);
577 EXPECT_EQ(output_2->quantization->zero_point[0], 50);
578 }
579
TEST(ModelInterface,Float)580 TEST(ModelInterface, Float) {
581 // Create the model.
582 std::unique_ptr<ModelT> input_model_t = CreateFloatModel();
583 flatbuffers::FlatBufferBuilder builder_temp;
584 flatbuffers::Offset<Model> output_model_location =
585 Model::Pack(builder_temp, input_model_t.get());
586 FinishModelBuffer(builder_temp, output_model_location);
587 const uint8_t* buffer_temp = builder_temp.GetBufferPointer();
588 const Model* input_model = GetModel(buffer_temp);
589
590 // Change model type.
591 flatbuffers::FlatBufferBuilder builder;
592 EXPECT_EQ(Uint8QuantizeModelInputsOutputs(&builder, input_model,
593 {{"tensor_0", {0.4, 2}}},
594 {{"tensor_1", {0.5, -5}}}),
595 kTfLiteOk);
596
597 const uint8_t* buffer = builder.GetBufferPointer();
598 const Model* output_model = GetModel(buffer);
599 std::unique_ptr<ModelT> model;
600 model.reset(output_model->UnPack());
601
602 // Verify results.
603 EXPECT_EQ(model->subgraphs.size(), 1);
604 EXPECT_EQ(model->subgraphs[0]->tensors.size(), 4);
605 EXPECT_EQ(model->subgraphs[0]->inputs.size(), 1);
606 EXPECT_EQ(model->subgraphs[0]->inputs[0], 0);
607 EXPECT_EQ(model->subgraphs[0]->outputs.size(), 1);
608 EXPECT_EQ(model->subgraphs[0]->outputs[0], 1);
609 EXPECT_EQ(model->operator_codes.size(), 3);
610 EXPECT_EQ(GetBuiltinCode(model->operator_codes[0].get()),
611 BuiltinOperator_FULLY_CONNECTED);
612 EXPECT_EQ(GetBuiltinCode(model->operator_codes[1].get()),
613 BuiltinOperator_DEQUANTIZE);
614 EXPECT_EQ(GetBuiltinCode(model->operator_codes[2].get()),
615 BuiltinOperator_QUANTIZE);
616 EXPECT_EQ(model->subgraphs[0]->operators.size(), 3);
617
618 auto dequantize_op = model->subgraphs[0]->operators[0].get();
619 auto input = model->subgraphs[0]->tensors[dequantize_op->inputs[0]].get();
620 EXPECT_EQ(input->name, "tensor_0_uint8");
621 EXPECT_EQ(input->type, TensorType_UINT8);
622 EXPECT_FLOAT_EQ(input->quantization->scale[0], 0.4);
623 EXPECT_EQ(input->quantization->zero_point[0], 2);
624
625 auto quantize_op = model->subgraphs[0]->operators[2].get();
626 auto output = model->subgraphs[0]->tensors[quantize_op->outputs[0]].get();
627 EXPECT_EQ(output->name, "tensor_1_uint8");
628 EXPECT_EQ(output->type, TensorType_UINT8);
629 EXPECT_FLOAT_EQ(output->quantization->scale[0], 0.5);
630 EXPECT_EQ(output->quantization->zero_point[0], -5);
631 }
632
633 } // namespace
634 } // namespace optimize
635 } // namespace tflite
636