| 107 | |
| 108 | namespace { |
| 109 | TfLiteStatus PopulateQuantizedLstmParams( |
| 110 | TfLiteContext* context, TfLiteNode* node, |
| 111 | lstm_eval::QuantizedLstmParameter* quantized_lstm_param) { |
| 112 | std::vector<float> intermediate_scale; |
| 113 | std::vector<int32> intermediate_zp; |
| 114 | for (int i = 0; i < 12; ++i) { |
| 115 | // Calculate intermediate tensors. |
| 116 | TfLiteTensor* intermediate = |
| 117 | &context->tensors[node->intermediates->data[i]]; |
| 118 | auto* params = reinterpret_cast<TfLiteAffineQuantization*>( |
| 119 | intermediate->quantization.params); |
| 120 | intermediate_scale.push_back(params->scale->data[0]); |
| 121 | intermediate_zp.push_back(params->zero_point->data[0]); |
| 122 | } |
| 123 | |
| 124 | // Calculate quantized clip for projection and cell. |
| 125 | const auto* params = reinterpret_cast<TfLiteLSTMParams*>(node->builtin_data); |
| 126 | const float cell_clip = params->cell_clip; |
| 127 | const float proj_clip = params->proj_clip; |
| 128 | |
| 129 | const TfLiteTensor* cell_tensor = |
| 130 | GetInput(context, node, kInputCellStateTensor); |
| 131 | const TfLiteTensor* output_tensor = GetOutput(context, node, kOutputTensor); |
| 132 | |
| 133 | auto* cell_params = reinterpret_cast<TfLiteAffineQuantization*>( |
| 134 | cell_tensor->quantization.params); |
| 135 | auto* proj_params = reinterpret_cast<TfLiteAffineQuantization*>( |
| 136 | output_tensor->quantization.params); |
| 137 | if (cell_clip > 0.0) { |
| 138 | quantized_lstm_param->quantized_cell_clip = |
| 139 | static_cast<int32_t>(cell_clip / cell_params->scale->data[0]); |
| 140 | } else { |
| 141 | quantized_lstm_param->quantized_cell_clip = 0; |
| 142 | } |
| 143 | if (proj_clip > 0.0) { |
| 144 | quantized_lstm_param->quantized_proj_clip = |
| 145 | static_cast<int32_t>(proj_clip / proj_params->scale->data[0]); |
| 146 | } else { |
| 147 | quantized_lstm_param->quantized_proj_clip = 0; |
| 148 | } |
| 149 | |
| 150 | // Calculate effective scales. |
| 151 | OpData* op_data = reinterpret_cast<OpData*>(node->user_data); |
| 152 | const bool is_layer_norm_lstm = op_data->is_layer_norm_lstm; |
| 153 | |
| 154 | const TfLiteTensor* input = GetInput(context, node, kInputTensor); |
| 155 | |
| 156 | const TfLiteTensor* input_to_input_weights = |
| 157 | GetOptionalInputTensor(context, node, kInputToInputWeightsTensor); |
| 158 | const TfLiteTensor* input_to_forget_weights = |
| 159 | GetInput(context, node, kInputToForgetWeightsTensor); |
| 160 | const TfLiteTensor* input_to_cell_weights = |
| 161 | GetInput(context, node, kInputToCellWeightsTensor); |
| 162 | const TfLiteTensor* input_to_output_weights = |
| 163 | GetInput(context, node, kInputToOutputWeightsTensor); |
| 164 | |
| 165 | const TfLiteTensor* recurrent_to_input_weights = |
| 166 | GetOptionalInputTensor(context, node, kRecurrentToInputWeightsTensor); |
no test coverage detected