Quantize the op output.
| 449 | |
| 450 | // Quantize the op output. |
| 451 | TfLiteStatus QuantizeOpOutput( |
| 452 | ModelT* model, int32_t subgraph_idx, int32_t op_idx, |
| 453 | operator_property::OperatorProperty property, |
| 454 | const std::pair<int32_t, operator_property::TensorProperty>& output, |
| 455 | ErrorReporter* error_reporter) { |
| 456 | int32_t output_idx = output.first; |
| 457 | operator_property::TensorProperty tensor_property = output.second; |
| 458 | // If the operator is not quantizable, we don't need to do anything for the |
| 459 | // output. |
| 460 | if (!property.quantizable) { |
| 461 | return kTfLiteOk; |
| 462 | } |
| 463 | SubGraphT* subgraph = model->subgraphs.at(subgraph_idx).get(); |
| 464 | OperatorT* op = subgraph->operators[op_idx].get(); |
| 465 | const BuiltinOperator op_code = |
| 466 | model->operator_codes[op->opcode_index]->builtin_code; |
| 467 | if (output_idx >= op->outputs.size()) { |
| 468 | error_reporter->Report( |
| 469 | "Required output index %d is larger than the output length of " |
| 470 | "op %s at index %d in subgraph %d", |
| 471 | output_idx, op->outputs.size(), EnumNameBuiltinOperator(op_code), |
| 472 | op_idx, subgraph_idx); |
| 473 | return kTfLiteError; |
| 474 | } |
| 475 | |
| 476 | TensorT* output_tensor = subgraph->tensors[op->outputs[output_idx]].get(); |
| 477 | if (ShouldRestrictSameInputOutputScale(property)) { |
| 478 | // Copy quantization parameter. For average pool, max pool, etc |
| 479 | // min/max can be different but we want them to be the same. |
| 480 | // Get scale and zero point of input. |
| 481 | if (property.inputs[0].first >= op->inputs.size()) { |
| 482 | error_reporter->Report( |
| 483 | "Required input index %d is larger than the input length of " |
| 484 | "op %s at index %d in subgraph %d", |
| 485 | property.inputs[0].first, op->inputs.size(), |
| 486 | EnumNameBuiltinOperator(op_code), op_idx, subgraph_idx); |
| 487 | return kTfLiteError; |
| 488 | } |
| 489 | const int input_tensor_idx = op->inputs[property.inputs[0].first]; |
| 490 | TensorT* input_tensor = subgraph->tensors[input_tensor_idx].get(); |
| 491 | if (input_tensor->quantization->scale.size() != 1 || |
| 492 | input_tensor->quantization->zero_point.size() != 1 || |
| 493 | input_tensor->quantization->min.size() != 1 || |
| 494 | input_tensor->quantization->max.size() != 1) { |
| 495 | error_reporter->Report( |
| 496 | "Invalid quantization params for op %s at index %d " |
| 497 | "in subgraph %d", |
| 498 | EnumNameBuiltinOperator(op_code), op_idx, subgraph_idx); |
| 499 | return kTfLiteError; |
| 500 | } |
| 501 | |
| 502 | const float input_scale = input_tensor->quantization->scale[0]; |
| 503 | const int32_t input_zero_point = input_tensor->quantization->zero_point[0]; |
| 504 | |
| 505 | const float min = input_tensor->quantization->min[0]; |
| 506 | const float max = input_tensor->quantization->max[0]; |
| 507 | if (utils::HasMinMax(output_tensor)) { |
| 508 | if (output_tensor->quantization->min[0] != min || |
no test coverage detected