tensorflow/lite/toco/graph_transformations/make_initial_dequantize_operator.cc
// This inserts an operator whose output is a float array (name:
// flags.input_array()).  It has to wait for any existing operators that
// generate this output to be removed by graph transformations.  Note that there
// may be more than one operator that takes the input_array as their input, and
// that some of these may be removed by graph transformations.
This inserts an operator whose output is a float array (name:
flags.input_array()).  It has to wait for any existing operators that
generate this output to be removed by graph transformations.  Note that there
may be more than one operator that takes the input_array as their input, and
that some of these may be removed by graph transformations.
This inserts an operator whose output is a float array ( name : flags . input_array () ) . It has to wait for any existing operators that generate this output to be removed by graph transformations . Note that there may be more than one operator that takes the input_array as their input and that some of these may be removed by graph transformations .
bool AddDequantizeOperatorToInput(const std::string& input_name,
                                  const Operator* op,
                                  GraphTransformation* transformation,
                                  Model* model) {
  if (GetOpWithOutput(*model, input_name)) {
    return false;
  }
  if (CountOpsWithInput(*model, input_name) > 1) {
    if (op != GetFirstOpWithInput(*model, input_name)) {
      return false;
    }
  }
  auto& input_array = model->GetArray(input_name);
  if (input_array.data_type != ArrayDataType::kFloat) {
    return false;
  }
  if (input_array.final_data_type == input_array.data_type ||
      input_array.final_data_type == ArrayDataType::kNone) {
    return false;
  }
  const auto& dequantized_input_name =
      AvailableArrayName(*model, input_name + "_dequantized");
  for (auto& other_op : model->operators) {
    for (std::string& other_op_input : other_op->inputs) {
      if (other_op_input == input_name) {
        other_op_input = dequantized_input_name;
      }
    }
  }
  auto& dequantized_input_array =
      model->GetOrCreateArray(dequantized_input_name);
  auto* image_input_op = new DequantizeOperator;
  image_input_op->inputs = {input_name};
  image_input_op->outputs = {dequantized_input_name};
  model->operators.emplace(model->operators.begin(), image_input_op);
  dequantized_input_array.data_type = ArrayDataType::kFloat;
  const auto& input_minmax = input_array.GetMinMax();
  auto& dequantized_input_minmax = dequantized_input_array.GetOrCreateMinMax();
  dequantized_input_minmax = input_minmax;
  auto& input_qparams = input_array.GetOrCreateQuantizationParams();
  input_array.data_type = input_array.final_data_type;
  ChooseQuantizationParamsForArrayAndQuantizedDataType(
      input_array, input_array.data_type, &input_qparams);
  transformation->AddMessageF(
      "Created %s"
      " to handle quantized input image data, taking over existing"
      " mean_value and std_value flags. Cleared those flags.",
      LogName(*image_input_op));
  return true;
}
bool AddDequantizeOperatorToInput ( const std :: string & input_name , const Operator * op , GraphTransformation * transformation , Model * model ) { if ( GetOpWithOutput ( * model , input_name ) ) { return false ; } if ( CountOpsWithInput ( * model , input_name ) > 1 ) { if ( op != GetFirstOpWithInput ( * model , input_name ) ) { return false ; } } auto & input_array = model -> GetArray ( input_name ) ; if ( input_array . data_type != ArrayDataType :: kFloat ) { return false ; } if ( input_array . final_data_type == input_array . data_type || input_array . final_data_type == ArrayDataType :: kNone ) { return false ; } const auto & dequantized_input_name = AvailableArrayName ( * model , input_name + " " ) ; for ( auto & other_op : model -> operators ) { for ( std :: string & other_op_input : other_op -> inputs ) { if ( other_op_input == input_name ) { other_op_input = dequantized_input_name ; } } } auto & dequantized_input_array = model -> GetOrCreateArray ( dequantized_input_name ) ; auto * image_input_op = new DequantizeOperator ; image_input_op -> inputs = { input_name } ; image_input_op -> outputs = { dequantized_input_name } ; model -> operators . emplace ( model -> operators . begin ( ) , image_input_op ) ; dequantized_input_array . data_type = ArrayDataType :: kFloat ; const auto & input_minmax = input_array . GetMinMax ( ) ; auto & dequantized_input_minmax = dequantized_input_array . GetOrCreateMinMax ( ) ; dequantized_input_minmax = input_minmax ; auto & input_qparams = input_array . GetOrCreateQuantizationParams ( ) ; input_array . data_type = input_array . final_data_type ; ChooseQuantizationParamsForArrayAndQuantizedDataType ( input_array , input_array . data_type , & input_qparams ) ; transformation -> AddMessageF ( " " " " " " , LogName ( * image_input_op ) ) ; return true ; }
This inserts an operator whose output is a float array (name:
flags.input_array()).
This inserts an operator whose output is a float array ( name : flags . input_array () ) .
// An operator with the required output may be a dequantize operator already // created.  Alternatively it may be an operator that needs to be removed // because it is unused, in which case we wait for RemoveUnusedOp to do its // work. // We only apply for the first operator if there is more than one.  This is // not strictly necessary for ordering correctness, since we insert the // dequant operator at the beginning of the op sequence, but it makes the // insertion more predictable (eg forward vs backwards operator sweep).