| 128 | } |
| 129 | |
| 130 | inline void EvalHybridSVDF( |
| 131 | TfLiteContext* context, TfLiteNode* node, const TfLiteTensor* input, |
| 132 | const TfLiteTensor* weights_feature, const TfLiteTensor* weights_time, |
| 133 | const TfLiteTensor* bias, const TfLiteSVDFParams* params, |
| 134 | TfLiteTensor* scratch, TfLiteTensor* scaling_factors, |
| 135 | TfLiteTensor* input_quantized, TfLiteTensor* state, TfLiteTensor* output) { |
| 136 | const int rank = params->rank; |
| 137 | const int batch_size = input->dims->data[0]; |
| 138 | const int input_size = input->dims->data[1]; |
| 139 | const int num_filters = weights_feature->dims->data[0]; |
| 140 | const int num_units = num_filters / rank; |
| 141 | const int memory_size = weights_time->dims->data[1]; |
| 142 | |
| 143 | // Initialize the pointer to input. |
| 144 | const float* input_ptr_batch = GetTensorData<float>(input); |
| 145 | |
| 146 | // Initialize the pointer to storage for quantized values and the weights |
| 147 | // feature. |
| 148 | int8_t* quantized_input_ptr_batch; |
| 149 | const int8_t* weights_feature_ptr; |
| 150 | if (weights_feature->type == kTfLiteUInt8) { |
| 151 | quantized_input_ptr_batch = |
| 152 | reinterpret_cast<int8_t*>(GetTensorData<uint8_t>(input_quantized)); |
| 153 | weights_feature_ptr = reinterpret_cast<const int8_t*>( |
| 154 | GetTensorData<uint8_t>(weights_feature)); |
| 155 | } else { |
| 156 | quantized_input_ptr_batch = GetTensorData<int8_t>(input_quantized); |
| 157 | weights_feature_ptr = GetTensorData<int8_t>(weights_feature); |
| 158 | } |
| 159 | |
| 160 | // Initialize the pointer to storage for scaling factors. |
| 161 | float* scaling_factors_ptr = GetTensorData<float>(scaling_factors); |
| 162 | |
| 163 | // Initialize the weights scale. |
| 164 | const float weights_feature_scale = weights_feature->params.scale; |
| 165 | |
| 166 | // Clear the activation (state's leftmost column). |
| 167 | // TODO(ghodrat): Add a test which initialize state with invalid values in |
| 168 | // the leftmost column and make sure it passes. |
| 169 | for (int b = 0; b < batch_size; ++b) { |
| 170 | float* state_ptr_batch = |
| 171 | GetTensorData<float>(state) + b * memory_size * num_filters; |
| 172 | for (int c = 0; c < num_filters; ++c) { |
| 173 | float* state_ptr = state_ptr_batch + c * memory_size; |
| 174 | state_ptr[memory_size - 1] = 0.0; |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | if (!tensor_utils::IsZeroVector(input_ptr_batch, batch_size * input_size)) { |
| 179 | // Quantize input from float to int8. |
| 180 | float unused_min, unused_max; |
| 181 | for (int b = 0; b < batch_size; ++b) { |
| 182 | const int offset = b * input_size; |
| 183 | tensor_utils::SymmetricQuantizeFloats( |
| 184 | input_ptr_batch + offset, input_size, |
| 185 | quantized_input_ptr_batch + offset, &unused_min, &unused_max, |
| 186 | &scaling_factors_ptr[b]); |
| 187 | scaling_factors_ptr[b] *= weights_feature_scale; |
no test coverage detected