| 44 | namespace toco { |
| 45 | |
| 46 | ::tensorflow::Status IdentifyPRelu::Run(Model* model, std::size_t op_index, |
| 47 | bool* modified) { |
| 48 | *modified = false; |
| 49 | const auto add_op_it = model->operators.begin() + op_index; |
| 50 | const auto* add_op = add_op_it->get(); |
| 51 | if (add_op == nullptr || add_op->type != OperatorType::kAdd || |
| 52 | add_op->inputs.size() != 2 || |
| 53 | add_op->fused_activation_function != FusedActivationFunctionType::kNone) { |
| 54 | return ::tensorflow::Status::OK(); |
| 55 | } |
| 56 | |
| 57 | const auto* relu_input_op = GetOpWithOutput(*model, add_op->inputs[0]); |
| 58 | if (relu_input_op == nullptr || relu_input_op->type != OperatorType::kRelu || |
| 59 | relu_input_op->inputs.size() != 1 || |
| 60 | relu_input_op->fused_activation_function != |
| 61 | FusedActivationFunctionType::kNone) { |
| 62 | return ::tensorflow::Status::OK(); |
| 63 | } |
| 64 | |
| 65 | // TODO(ycling): Both Add and Mul are commutative. Support the case where |
| 66 | // the position of operands are exchanged. |
| 67 | const auto* mul_op = GetOpWithOutput(*model, add_op->inputs[1]); |
| 68 | if (mul_op == nullptr || mul_op->type != OperatorType::kMul || |
| 69 | mul_op->inputs.size() != 2 || |
| 70 | mul_op->fused_activation_function != FusedActivationFunctionType::kNone) { |
| 71 | return ::tensorflow::Status::OK(); |
| 72 | } |
| 73 | |
| 74 | const auto neg_alpha_tensor_name = mul_op->inputs[0]; |
| 75 | |
| 76 | const auto* relu_neg_input_op = GetOpWithOutput(*model, mul_op->inputs[1]); |
| 77 | |
| 78 | if (relu_neg_input_op == nullptr || |
| 79 | relu_neg_input_op->inputs.size() != 1) { |
| 80 | return ::tensorflow::Status::OK(); |
| 81 | } |
| 82 | |
| 83 | const Operator* final_input_op; |
| 84 | if (relu_neg_input_op->type == OperatorType::kNeg && |
| 85 | relu_neg_input_op->fused_activation_function == |
| 86 | FusedActivationFunctionType::kRelu) { |
| 87 | // This detects a Neg op with fused Relu activation function. |
| 88 | final_input_op = relu_neg_input_op; |
| 89 | } else { |
| 90 | // This detects a Neg op followed by a separated Relu op. |
| 91 | const auto* neg_input_op = |
| 92 | GetOpWithOutput(*model, relu_neg_input_op->inputs[0]); |
| 93 | if (neg_input_op == nullptr || neg_input_op->inputs.size() != 1 || |
| 94 | relu_neg_input_op->type != OperatorType::kRelu || |
| 95 | relu_neg_input_op->fused_activation_function != |
| 96 | FusedActivationFunctionType::kNone) { |
| 97 | return ::tensorflow::Status::OK(); |
| 98 | } |
| 99 | final_input_op = neg_input_op; |
| 100 | } |
| 101 | |
| 102 | if (relu_input_op->inputs[0] != final_input_op->inputs[0]) { |
| 103 | return ::tensorflow::Status::OK(); |
nothing calls this directly
no test coverage detected