message: Hardcode input range from output for relu
diff: @@ -63,6 +63,25 @@ bool HardcodeMinMaxForL2Normalization(Model* model, Operator* op) {
  return true;
  }
  +bool HardcodeInputMinMaxFromOutput(Model* model, Operator* op) {
  + auto& input = model->GetArray(op->inputs[0]);
  + if (input.minmax) {
  + const auto* minmax = input.minmax.get();
  + if (minmax) {
  + return false;
  + }
  + }
  + auto& output = model->GetArray(op->outputs[0]);
  + if (output.minmax) {
  + const auto* minmax = model->GetArray(op->outputs[0]).minmax.get();
  + if (minmax) {
  + input.GetOrCreateMinMax() = *minmax;
  + return true;
  + }
  + }
  + return false;
  +}
  +
  bool HardcodeMinMaxForConcatenation(Model* model, Operator* op) {
  // Do not early return if the output already has min/max:
  // we may still need to adjust the inputs min/max.
  @@ -366,6 +385,16 @@ bool HardcodeMinMax::Run(Model* model, std::size_t op_index) {
  changed = HardcodeMinMaxForL2Normalization(model, op);
  break;
  + case OperatorType::kRelu:
  + // For any normalization other than batch norm, the quantizations ranges
  + // before and after relu are expected to be known. Having a quantization
  + // op before relu would reduce the number of bits of precision for the
  + // activation in half. So we deduce the range before relu from that after
  + // the relu. This would eliminate the need for two fake quantization nodes
  + // and would not reduce the bits of precision available for activation.
  + changed = HardcodeInputMinMaxFromOutput(model, op);
  + break;
  +
  case OperatorType::kConcatenation:
  changed = HardcodeMinMaxForConcatenation(model, op);
  break;
  