| 133 | } // namespace |
| 134 | |
| 135 | ::tensorflow::Status IdentifyLstmCell::Run(Model* model, std::size_t op_index, |
| 136 | bool* modified) { |
| 137 | *modified = false; |
| 138 | // This LSTM cell identification method is not invariant to commutation of |
| 139 | // commutative operator inputs. For example, if input[0] and input[1] of the |
| 140 | // final output multiplication were swapped, this method would not identify it |
| 141 | // as an LSTM cell. This is OK in most cases, because |
| 142 | // tf.rnn.contrib.BasicLSTMCell always generates LSTM cells the same way. |
| 143 | |
| 144 | // Final output multiply |
| 145 | auto op_it = model->operators.begin() + op_index; |
| 146 | Operator* final_output_mul = op_it->get(); |
| 147 | if (final_output_mul->type != OperatorType::kMul) { |
| 148 | return ::tensorflow::Status::OK(); |
| 149 | } |
| 150 | // final_output_mul->outputs[0] would be one of the two outputs of our |
| 151 | // LstmCell. Exit if it does not already have a data type. |
| 152 | // We won't be able to propagate data types through a fused LstmCell. |
| 153 | if (model->GetArray(final_output_mul->outputs[0]).data_type == |
| 154 | ArrayDataType::kNone) { |
| 155 | return ::tensorflow::Status::OK(); |
| 156 | } |
| 157 | Operator *state_output_tanh, *fc_output_sig; |
| 158 | if (!MatchOperatorInputs(*final_output_mul, *model, OperatorType::kTanh, |
| 159 | &state_output_tanh, OperatorType::kLogistic, |
| 160 | &fc_output_sig)) { |
| 161 | return ::tensorflow::Status::OK(); |
| 162 | } |
| 163 | // state_output_tanh->inputs[0] would be one of the two outputs of our |
| 164 | // LstmCell. Exit if it does not already have a data type. |
| 165 | // We won't be able to propagate data types through a fused LstmCell. |
| 166 | if (model->GetArray(state_output_tanh->inputs[0]).data_type == |
| 167 | ArrayDataType::kNone) { |
| 168 | return ::tensorflow::Status::OK(); |
| 169 | } |
| 170 | |
| 171 | // State output TanH |
| 172 | // (We don't count an operator as ID'd until we verify it has the correct |
| 173 | // operator types feeding into it.) |
| 174 | Operator* state_combine_add; |
| 175 | if (!MatchOperatorInputs(*state_output_tanh, *model, OperatorType::kAdd, |
| 176 | &state_combine_add)) { |
| 177 | return ::tensorflow::Status::OK(); |
| 178 | } |
| 179 | |
| 180 | // State forget & remember addition |
| 181 | Operator *state_forget_mul, *state_remember_mul; |
| 182 | if (!MatchOperatorInputs(*state_combine_add, *model, OperatorType::kMul, |
| 183 | &state_forget_mul, OperatorType::kMul, |
| 184 | &state_remember_mul)) { |
| 185 | return ::tensorflow::Status::OK(); |
| 186 | } |
| 187 | const string prev_state = state_forget_mul->inputs[0]; |
| 188 | |
| 189 | // State forget gate |
| 190 | Operator* state_forget_sig; |
| 191 | if (!MatchOperatorInputs(*state_forget_mul, *model, OperatorType::kNone, |
| 192 | nullptr, OperatorType::kLogistic, |
nothing calls this directly
no test coverage detected