Resize the output, state tensors based on the sizes of the input tensors. Allocate a temporary scratch tensor. Also check that the sizes of the input tensors match each other.
| 659 | // Allocate a temporary scratch tensor. Also check that the sizes of the input |
| 660 | // tensors match each other. |
| 661 | TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { |
| 662 | OpData* op_data = reinterpret_cast<OpData*>(node->user_data); |
| 663 | |
| 664 | TF_LITE_ENSURE_EQ(context, node->outputs->size, 1); |
| 665 | // Logic for determining regular lstm and layer norm lstm: |
| 666 | // input_size, forget_gate_layer_norm_tensor (20) null? is_layer_norm? |
| 667 | // 20, N/A, No. |
| 668 | // 24, null, No. |
| 669 | // 24, not null, Yes. |
| 670 | // 20-inputs lstm are deprecated and is only kept here for backward |
| 671 | // compatibility. |
| 672 | if (node->inputs->size == 24) { |
| 673 | const TfLiteTensor* forget_layer_norm_coefficients = GetOptionalInputTensor( |
| 674 | context, node, kForgetLayerNormCoefficientsTensor); |
| 675 | if (forget_layer_norm_coefficients == nullptr) { |
| 676 | op_data->is_layer_norm_lstm = false; |
| 677 | } else { |
| 678 | op_data->is_layer_norm_lstm = true; |
| 679 | } |
| 680 | } else if (node->inputs->size == 20) { |
| 681 | // This is deprecated and is only kept here for backward compatibility. |
| 682 | op_data->is_layer_norm_lstm = false; |
| 683 | } else { |
| 684 | context->ReportError( |
| 685 | context, "The LSTM Full kernel expects 20 or 24 inputs. Got %d inputs", |
| 686 | node->inputs->size); |
| 687 | return kTfLiteError; |
| 688 | } |
| 689 | |
| 690 | const bool is_layer_norm_lstm = op_data->is_layer_norm_lstm; |
| 691 | op_data->activation_state_tensor_index = |
| 692 | node->inputs->data[kInputActivationStateTensor]; |
| 693 | op_data->cell_state_tensor_index = node->inputs->data[kInputCellStateTensor]; |
| 694 | |
| 695 | // Inferring batch size, number of outputs and number of cells from the |
| 696 | // input tensors. |
| 697 | const TfLiteTensor* input = GetInput(context, node, kInputTensor); |
| 698 | const bool is_fully_quantized = input->type == kTfLiteInt8; |
| 699 | TF_LITE_ENSURE(context, input->dims->size > 1); |
| 700 | const int n_batch = input->dims->data[0]; |
| 701 | const int n_input = input->dims->data[1]; |
| 702 | |
| 703 | const TfLiteTensor* input_to_output_weights = |
| 704 | GetInput(context, node, kInputToOutputWeightsTensor); |
| 705 | const int n_cell = input_to_output_weights->dims->data[0]; |
| 706 | TF_LITE_ENSURE_EQ(context, input_to_output_weights->dims->size, 2); |
| 707 | TF_LITE_ENSURE_EQ(context, input_to_output_weights->dims->data[1], n_input); |
| 708 | |
| 709 | const TfLiteTensor* recurrent_to_output_weights = |
| 710 | GetInput(context, node, kRecurrentToOutputWeightsTensor); |
| 711 | TF_LITE_ENSURE_EQ(context, recurrent_to_output_weights->dims->size, 2); |
| 712 | TF_LITE_ENSURE_EQ(context, recurrent_to_output_weights->dims->data[0], |
| 713 | n_cell); |
| 714 | const int n_output = recurrent_to_output_weights->dims->data[1]; |
| 715 | |
| 716 | // Check that input tensor dimensions matches with each other. |
| 717 | TF_LITE_ENSURE_OK(context, CheckInputTensorDimensions( |
| 718 | context, node, n_input, n_output, n_cell, |
nothing calls this directly
no test coverage detected