ONE - On-device Neural Engine
Loading...
Searching...
No Matches
nnfw::cker::Einsum Class Reference

#include <Einsum.h>

Public Member Functions

 Einsum ()
 
void prepare (std::string &equation)
 
void operator() (std::string &equation, const std::vector< Shape > &input_shapes, const std::vector< const float * > &input_data, const Shape &output_shape, float *output_data)
 

Detailed Description

Definition at line 182 of file Einsum.h.

Constructor & Destructor Documentation

◆ Einsum()

nnfw::cker::Einsum::Einsum ( )
inline

Definition at line 185 of file Einsum.h.

185 : _prepared(false)
186 {
187 // DO NOTHING
188 }

Member Function Documentation

◆ operator()()

void nnfw::cker::Einsum::operator() ( std::string &  equation,
const std::vector< Shape > &  input_shapes,
const std::vector< const float * > &  input_data,
const Shape output_shape,
float *  output_data 
)
inline

Definition at line 202 of file Einsum.h.

205 {
206 if (!_prepared)
207 {
208 prepare(equation);
209 }
210
211 const int num_inputs = input_shapes.size();
212 std::vector<InputTensor<float>> inputs(num_inputs);
213 for (int i = 0; i < num_inputs; i++)
214 {
215 inputs[i].shape.ReplaceWith(input_shapes[i].DimensionsCount(), input_shapes[i].DimsData());
216 inputs[i].buffer = input_data[i];
217 }
218
219 OperandLabels input_labels(_input_labels);
220 Labels output_labels(_output_labels);
221 std::vector<DimensionType> label_types(_label_types);
222 OperandLabelCounts input_label_counts(_input_label_counts);
223 LabelCounts output_label_counts(_output_label_counts);
224 LabelToDimSizes label_to_dim_sizes;
225
226 processDimensions(inputs, &input_labels, &output_labels, &label_types, &input_label_counts,
227 &output_label_counts, &label_to_dim_sizes);
228
229 // The reduction phase (a) sums across reduction dimensions, (b) takes
230 // generalized diagonals, and (c) reshapes it into shape
231 // [(broadcasting) batch shape] + [F,C]
232 // where F and C denote the total (compacted) size of free and contract
233 // dimensions, respectively.
234
235 OperandLabels free_labels(num_inputs);
236 std::vector<Tensor> inputs_reduced(num_inputs);
237 std::vector<bool> swap_free_and_contract(num_inputs);
238 for (int i = 0; i < num_inputs; ++i)
239 {
240 bool temp_swap_free_and_contract = false;
241 reduceOperand<float>(inputs[i], label_types, input_label_counts[i], &input_labels[i],
242 &free_labels[i], &temp_swap_free_and_contract, &inputs_reduced[i]);
243 swap_free_and_contract[i] = temp_swap_free_and_contract;
244 }
245
246 // After reduction, the inputs should be reshaped to Tensors suitable for
247 // contraction. If num_inputs is 1, the reduced input is simply forwarded to
248 // the output.
249 Tensor contraction_output_reshaped;
250 contractOperands(inputs_reduced, swap_free_and_contract, &contraction_output_reshaped);
251
252 // Copy the batch labels from the contraction output. Recover the batch
253 // shape, which may have been broadcasted.
254 std::vector<int32_t> result_shape_dims(contraction_output_reshaped.shape.DimensionsCount() - 2);
255
256 for (size_t i = 0; i < result_shape_dims.size(); i++)
257 {
258 result_shape_dims[i] = contraction_output_reshaped.shape.Dims(i);
259 }
260
261 int num_labels = label_types.size();
262 Labels result_labels;
263 // All batch dimensions should be present in the contracted result. First
264 // the broadcasting dimensions, then the named batch dimensions.
265 for (int label = 0; label < num_labels; ++label)
266 {
267 if (label_types[label] == kBroadcasting)
268 result_labels.push_back(label);
269 }
270 for (int label = 0; label < num_labels; ++label)
271 {
272 if (label_types[label] == kBatch)
273 result_labels.push_back(label);
274 }
275 for (int i = 0; i < num_inputs; ++i)
276 {
277 for (auto &&label : free_labels[i])
278 {
279 result_labels.push_back(label);
280 result_shape_dims.push_back(label_to_dim_sizes[label]);
281 }
282 }
283
284 Shape result_shape(result_shape_dims.size(), result_shape_dims.data());
285
286 // Reshape the contraction (or reduction) result to its expanded shape:
287 // [(broadcasted) batch shape] + [free shape 0] + [free shape 1].
288 Tensor contraction_output;
289 copyFrom(contraction_output_reshaped, result_shape, &contraction_output);
290
291 // Inflate the output if necessary. (E.g. for the equation 'i->iii' which
292 // may arise while computing gradient of a regular Einsum).
293 // TODO(anudhyan): It's possible that Eigen's contract and inflate can be
294 // chained here to avoid materializing an intermediate.
295 Tensor output_inflated;
296 strideOrInflate<float>(contraction_output, result_labels, output_label_counts,
297 true /* should_inflate */, &output_inflated);
298
299 if (output_inflated.shape.DimensionsCount() > contraction_output.shape.DimensionsCount())
300 {
301 // We inflated the output. Modify result labels accordingly.
302 Labels inflated_labels;
303 for (auto &&label : result_labels)
304 {
305 inflated_labels.insert(inflated_labels.end(), output_label_counts[label], label);
306 }
307 result_labels.swap(inflated_labels);
308 }
309
310 // Find the permutation to map the result labels to the output labels. Note
311 // that both the result and the final output may have the repeated labels,
312 // in which case the permutation preserves the left-to-right ordering.
313 // E.g. if result labels are [0, 0, 1] and output is [0, l, 0] then the
314 // permutation should be [0, 2, 1]. We also use the fact that repeated
315 // labels in the result are adjacent to each other.
316 std::vector<int32_t> output_permutation(output_labels.size());
317 std::vector<int32_t> label_to_position(num_labels, -1);
318 for (size_t i = 0; i < result_labels.size(); ++i)
319 {
320 // Remember the position of only the leftmost result label.
321 if (label_to_position[result_labels[i]] == -1)
322 {
323 label_to_position[result_labels[i]] = i;
324 }
325 }
326 for (size_t i = 0; i < output_labels.size(); ++i)
327 {
328 output_permutation[i] = label_to_position[output_labels[i]];
329 // We have found the leftmost occurrence. The next one would be adjacent.
330 label_to_position[output_labels[i]] += 1;
331 }
332
333 InputTensor<float> temp_inflated;
334 temp_inflated.shape.ReplaceWith(output_inflated.shape.DimensionsCount(),
335 output_inflated.shape.DimsData());
336 temp_inflated.buffer = (reinterpret_cast<const float *>(output_inflated.buffer));
337 ;
338
340 transposeOperand<float>(temp_inflated, output_permutation, &output);
341
342 memcpy(output_data, output.buffer, output_shape.FlatSize() * sizeof(float));
343
344 temp_operand.clear();
345 }
void prepare(std::string &equation)
Definition Einsum.h:190
const luci_interpreter::RuntimeShape output_shape
list input_data
Definition infer.py:29
std::vector< Labels > OperandLabels
Definition Einsum.h:108
std::vector< int32_t > LabelCounts
Definition Einsum.h:109
std::vector< LabelCounts > OperandLabelCounts
Definition Einsum.h:110
@ kBroadcasting
Definition Einsum.h:123
std::vector< int32_t > Labels
Definition Einsum.h:107
std::vector< int32_t > LabelToDimSizes
Definition Einsum.h:111
Definition Shape.h:28

References nnfw::cker::InputTensor< T >::buffer, nnfw::cker::Tensor::buffer, nnfw::cker::Shape::DimensionsCount(), nnfw::cker::Shape::Dims(), nnfw::cker::Shape::DimsData(), nnfw::cker::kBatch, nnfw::cker::kBroadcasting, output_shape, prepare(), nnfw::cker::Shape::ReplaceWith(), nnfw::cker::InputTensor< T >::shape, and nnfw::cker::Tensor::shape.

◆ prepare()

void nnfw::cker::Einsum::prepare ( std::string &  equation)
inline

Definition at line 190 of file Einsum.h.

191 {
192 if (_prepared)
193 {
194 return;
195 }
196
197 // Parse equation
198 parseEquation(equation);
199 _prepared = true;
200 }

Referenced by onert::backend::cpu::ops::EinsumLayer::einsumFloat32(), and operator()().


The documentation for this class was generated from the following file: