| 136 | } |
| 137 | |
| 138 | TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { |
| 139 | auto* params = |
| 140 | reinterpret_cast<TfLiteEmbeddingLookupSparseParams*>(node->builtin_data); |
| 141 | TfLiteTensor* output = GetOutput(context, node, 0); |
| 142 | const TfLiteTensor* ids = GetInput(context, node, 0); |
| 143 | const TfLiteTensor* indices = GetInput(context, node, 1); |
| 144 | const TfLiteTensor* dense_shape = GetInput(context, node, 2); |
| 145 | const TfLiteTensor* weights = GetInput(context, node, 3); |
| 146 | const TfLiteTensor* value = GetInput(context, node, 4); |
| 147 | |
| 148 | const int lookup_rank = SizeOfDimension(indices, 1); |
| 149 | const int embedding_rank = NumDimensions(value); |
| 150 | const int num_lookups = SizeOfDimension(ids, 0); |
| 151 | const int num_rows = SizeOfDimension(value, 0); |
| 152 | |
| 153 | // The last dimension gets replaced by the embedding. |
| 154 | const int output_rank = (lookup_rank - 1) + (embedding_rank - 1); |
| 155 | |
| 156 | // Make sure that the actual dense shape of the sparse tensor represented by |
| 157 | // (loopkup, indices, dense_shape) is consistent. |
| 158 | TF_LITE_ENSURE_EQ(context, SizeOfDimension(dense_shape, 0), lookup_rank); |
| 159 | |
| 160 | // Resize output tensor. |
| 161 | TfLiteIntArray* output_shape = TfLiteIntArrayCreate(output_rank); |
| 162 | TF_LITE_ENSURE(context, output_shape != nullptr); |
| 163 | int k = 0; |
| 164 | int embedding_size = 1; |
| 165 | int lookup_size = 1; |
| 166 | for (int i = 0; i < lookup_rank - 1; i++, k++) { |
| 167 | const int dim = dense_shape->data.i32[i]; |
| 168 | lookup_size *= dim; |
| 169 | output_shape->data[k] = dim; |
| 170 | } |
| 171 | for (int i = 1; i < embedding_rank; i++, k++) { |
| 172 | const int dim = SizeOfDimension(value, i); |
| 173 | embedding_size *= dim; |
| 174 | output_shape->data[k] = dim; |
| 175 | } |
| 176 | TF_LITE_ENSURE_STATUS(context->ResizeTensor(context, output, output_shape)); |
| 177 | const int output_size = lookup_size * embedding_size; |
| 178 | TfLiteTensorRealloc(output_size * sizeof(float), output); |
| 179 | |
| 180 | std::fill_n(output->data.f, output_size, 0.0f); |
| 181 | |
| 182 | // Keep track of the current bucket for aggregation/combination. |
| 183 | int current_output_offset = 0; |
| 184 | float current_total_weight = 0.0; |
| 185 | float current_squares_weight = 0.0; |
| 186 | int num_elements = 0; |
| 187 | |
| 188 | for (int i = 0; i < num_lookups; i++) { |
| 189 | int idx = ids->data.i32[i]; |
| 190 | if (idx >= num_rows || idx < 0) { |
| 191 | context->ReportError(context, |
| 192 | "Embedding Lookup Sparse: index out of bounds. " |
| 193 | "Got %d, and bounds are [0, %d]", |
| 194 | idx, num_rows - 1); |
| 195 | return kTfLiteError; |
nothing calls this directly
no test coverage detected