| 242 | } |
| 243 | |
| 244 | tensorflow::Status TransformWithStatus(const TocoFlags& toco_flags, |
| 245 | Model* model) { |
| 246 | const FileFormat output_format = toco_flags.output_format(); |
| 247 | const IODataType inference_type = toco_flags.inference_type(); |
| 248 | |
| 249 | const bool quantize_output = |
| 250 | SupportsQuantization(output_format) && |
| 251 | (inference_type == QUANTIZED_UINT8 || inference_type == QUANTIZED_INT16); |
| 252 | |
| 253 | if (quantize_output) { |
| 254 | QCHECK_NE(toco_flags.inference_input_type(), FLOAT) |
| 255 | << "Quantized inference is not allowed with float inputs."; |
| 256 | } |
| 257 | |
| 258 | // Clean up after import. |
| 259 | SetFinalDataTypeOnInputs(toco_flags, model); |
| 260 | UseArraysExtraInfo(model, quantize_output); |
| 261 | FinishBuildingRNNStates(model); |
| 262 | |
| 263 | // Remove unused ops before performing any other optimizations. This is to |
| 264 | // stop optimizations from crossing the input/output boundaries. For example |
| 265 | // this will stop BatchNorm fusing if the output node is in between a conv |
| 266 | // and BatchNorm layers. |
| 267 | TF_RETURN_IF_ERROR(RunGraphTransformationsWithStatus( |
| 268 | model, "Removing unused ops", {new toco::RemoveUnusedOp})); |
| 269 | |
| 270 | GraphTransformationsSet transformations; |
| 271 | MakeGeneralGraphTransformationsSet(&transformations); |
| 272 | auto* remove_trivial_reshape = new RemoveTrivialReshape; |
| 273 | transformations.Add(remove_trivial_reshape); |
| 274 | auto* resolve_constant_fake_quant = new ResolveConstantFakeQuant; |
| 275 | if (quantize_output) { |
| 276 | resolve_constant_fake_quant->set_propagate_fake_quant_num_bits( |
| 277 | toco_flags.propagate_fake_quant_num_bits()); |
| 278 | } |
| 279 | transformations.Add(resolve_constant_fake_quant); |
| 280 | if (SupportsFusedActivationFunction(output_format)) { |
| 281 | transformations.Add(new FuseActivationFunctions); |
| 282 | } else { |
| 283 | transformations.Add(new UnfuseActivationFunctions); |
| 284 | } |
| 285 | if (toco_flags.drop_fake_quant()) { |
| 286 | transformations.Add(new DropFakeQuant); |
| 287 | } else { |
| 288 | // See the doc for --reorder_across_fake_quant: that flag is needed to |
| 289 | // support some existing models, e.g. WordLens, that have FakeQuant |
| 290 | // nodes in the wrong places. |
| 291 | // TODO(benoitjacob): drop special casing when we can. |
| 292 | if ((quantize_output && toco_flags.reorder_across_fake_quant())) { |
| 293 | transformations.Add(new DropFakeQuant); |
| 294 | } |
| 295 | } |
| 296 | transformations.Add(new ConvertPureConvToDepthwise); |
| 297 | if (SupportsLstmCell(output_format)) { |
| 298 | if (!toco_flags.debug_disable_recurrent_cell_fusion()) { |
| 299 | transformations.Add(new IdentifyLstmCell); |
| 300 | } |
| 301 | if (output_format == TFLITE && toco_flags.split_tflite_lstm_inputs()) { |
no test coverage detected