| 78 | } |
| 79 | |
| 80 | TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { |
| 81 | const auto* params = reinterpret_cast<TfLiteBidirectionalSequenceRNNParams*>( |
| 82 | node->builtin_data); |
| 83 | |
| 84 | // Check we have all the inputs and outputs we need. |
| 85 | TF_LITE_ENSURE_EQ(context, node->inputs->size, 12); |
| 86 | TF_LITE_ENSURE_EQ(context, node->outputs->size, |
| 87 | params->merge_outputs ? 1 : 2); |
| 88 | |
| 89 | const TfLiteTensor* input = GetInput(context, node, kInputTensor); |
| 90 | const TfLiteTensor* fw_input_weights = |
| 91 | GetInput(context, node, kFwWeightsTensor); |
| 92 | const TfLiteTensor* fw_recurrent_weights = |
| 93 | GetInput(context, node, kFwRecurrentWeightsTensor); |
| 94 | const TfLiteTensor* fw_bias = GetInput(context, node, kFwBiasTensor); |
| 95 | const TfLiteTensor* fw_hidden_state = |
| 96 | GetInput(context, node, kFwHiddenStateTensor); |
| 97 | const TfLiteTensor* bw_input_weights = |
| 98 | GetInput(context, node, kBwWeightsTensor); |
| 99 | const TfLiteTensor* bw_recurrent_weights = |
| 100 | GetInput(context, node, kBwRecurrentWeightsTensor); |
| 101 | const TfLiteTensor* bw_bias = GetInput(context, node, kBwBiasTensor); |
| 102 | const TfLiteTensor* bw_hidden_state = |
| 103 | GetInput(context, node, kBwHiddenStateTensor); |
| 104 | |
| 105 | const TfLiteTensor* aux_input = |
| 106 | GetOptionalInputTensor(context, node, kAuxInputTensor); |
| 107 | const TfLiteTensor* fw_aux_input_weights = |
| 108 | GetOptionalInputTensor(context, node, kFwAuxWeightsTensor); |
| 109 | const TfLiteTensor* bw_aux_input_weights = |
| 110 | GetOptionalInputTensor(context, node, kBwAuxWeightsTensor); |
| 111 | |
| 112 | const bool aux_inputs_weights_or_none = |
| 113 | ((fw_aux_input_weights != nullptr) && |
| 114 | (bw_aux_input_weights != nullptr)) || |
| 115 | ((fw_aux_input_weights == nullptr) && (bw_aux_input_weights == nullptr)); |
| 116 | TF_LITE_ENSURE(context, aux_inputs_weights_or_none); |
| 117 | const bool has_aux_input = (fw_aux_input_weights != nullptr); |
| 118 | |
| 119 | // Check all the parameters of tensor match within themselves and match the |
| 120 | // input configuration. |
| 121 | TF_LITE_ENSURE_EQ(context, input->type, kTfLiteFloat32); |
| 122 | |
| 123 | TF_LITE_ENSURE_EQ(context, input->dims->size, 3); |
| 124 | const bool time_major = params->time_major; |
| 125 | const int batch_size = |
| 126 | (time_major) ? input->dims->data[1] : input->dims->data[0]; |
| 127 | const int max_time = |
| 128 | (time_major) ? input->dims->data[0] : input->dims->data[1]; |
| 129 | const int fw_num_units = fw_input_weights->dims->data[0]; |
| 130 | const int bw_num_units = bw_input_weights->dims->data[0]; |
| 131 | TF_LITE_ENSURE_EQ(context, input->dims->data[2], |
| 132 | fw_input_weights->dims->data[1]); |
| 133 | TF_LITE_ENSURE_EQ(context, input->dims->data[2], |
| 134 | bw_input_weights->dims->data[1]); |
| 135 | TF_LITE_ENSURE_EQ(context, fw_input_weights->dims->data[0], |
| 136 | fw_bias->dims->data[0]); |
| 137 | TF_LITE_ENSURE_EQ(context, bw_input_weights->dims->data[0], |
nothing calls this directly
no test coverage detected