| 26 | namespace toco { |
| 27 | |
| 28 | ::tensorflow::Status RemoveUnusedOp::Run(Model* model, std::size_t op_index, |
| 29 | bool* modified) { |
| 30 | *modified = false; |
| 31 | const auto it = model->operators.begin() + op_index; |
| 32 | const auto* op = it->get(); |
| 33 | |
| 34 | // Bail if any output is used, and is not an input_array of |
| 35 | // the model. We allow specifying an arbitrary input_array, |
| 36 | // treating the part of the graph leading up to it as unused. |
| 37 | for (const auto& output : op->outputs) { |
| 38 | CHECK(model->HasArray(output)); |
| 39 | // If this output is provided as the model's input array, |
| 40 | // then we don't need this operator to produce its contents. |
| 41 | if (IsInputArray(*model, output)) { |
| 42 | continue; |
| 43 | } |
| 44 | // If this output is provided as a RNN's state array, |
| 45 | // then we don't need this operator to produce its contents. |
| 46 | // So far this case has only been encountered with TensorFlow |
| 47 | // Fill ops used to zero-initialize RNN states, which is |
| 48 | // redundant for us as we zero-initialize RNN states anyway. |
| 49 | bool found_output_as_rnn_state_array = false; |
| 50 | for (const auto& rnn_state : model->flags.rnn_states()) { |
| 51 | if (output == rnn_state.state_array()) { |
| 52 | CHECK(op->type == OperatorType::kFill || |
| 53 | op->type == OperatorType::kIdentity); |
| 54 | found_output_as_rnn_state_array = true; |
| 55 | break; |
| 56 | } |
| 57 | } |
| 58 | if (found_output_as_rnn_state_array) { |
| 59 | continue; |
| 60 | } |
| 61 | for (const string& output_array : model->flags.output_arrays()) { |
| 62 | if (output == output_array) { |
| 63 | return ::tensorflow::Status::OK(); |
| 64 | } |
| 65 | } |
| 66 | for (const auto& rnn_state : model->flags.rnn_states()) { |
| 67 | if (output == rnn_state.back_edge_source_array()) { |
| 68 | // The output is consumed by a RNN back-edge.. |
| 69 | if (!IsDiscardableArray(*model, rnn_state.back_edge_source_array()) || |
| 70 | !IsDiscardableArray(*model, rnn_state.state_array()) || |
| 71 | CountOpsWithInput(*model, rnn_state.state_array())) { |
| 72 | return ::tensorflow::Status::OK(); |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | if (CountOpsWithInput(*model, output)) { |
| 77 | return ::tensorflow::Status::OK(); |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | if (op->unresolved_outputs) { |
| 82 | AddMessageF("Not discarding %s because it has unresolved outputs.", |
| 83 | LogName(*op)); |
| 84 | return ::tensorflow::Status::OK(); |
| 85 | } |
nothing calls this directly
no test coverage detected