ONE - On-device Neural Engine
Loading...
Searching...
No Matches
onert::exec::DynamicShapeInferer Class Reference

Class to infer shape of output tensor at execution time and allocate memory fo output tensor if needed. More...

#include <DynamicShapeInferer.h>

Collaboration diagram for onert::exec::DynamicShapeInferer:

Public Member Functions

 DynamicShapeInferer (const std::shared_ptr< backend::ITensorRegistry > &tensor_registry)
 
void visit (const ir::operation::ArgMinMax &op) override
 
void visit (const ir::operation::BatchMatMul &op) override
 
void visit (const ir::operation::BCQFullyConnected &op) override
 
void visit (const ir::operation::BCQGather &op) override
 
void visit (const ir::operation::BinaryArithmetic &op) override
 
void visit (const ir::operation::BroadcastTo &op) override
 
void visit (const ir::operation::Comparison &op) override
 
void visit (const ir::operation::Concat &op) override
 
void visit (const ir::operation::Conv2D &op) override
 
void visit (const ir::operation::ElementwiseActivation &op) override
 
void visit (const ir::operation::ElementwiseBinary &op) override
 
void visit (const ir::operation::ElementwiseUnary &op) override
 
void visit (const ir::operation::ExpandDims &op) override
 
void visit (const ir::operation::Fill &op) override
 
void visit (const ir::operation::FullyConnected &op) override
 
void visit (const ir::operation::FusedBatchNorm &op) override
 
void visit (const ir::operation::Gather &op) override
 
void visit (const ir::operation::L2Normalization &op) override
 
void visit (const ir::operation::LSTM &op) override
 
void visit (const ir::operation::MatrixBandPart &op) override
 
void visit (const ir::operation::DetectionPostProcess &op) override
 
void visit (const ir::operation::OneHot &op) override
 
void visit (const ir::operation::Pack &op) override
 
void visit (const ir::operation::Pad &op) override
 
void visit (const ir::operation::Permute &op) override
 
void visit (const ir::operation::Pool2D &op) override
 
void visit (const ir::operation::Pow &op) override
 
void visit (const ir::operation::Range &op) override
 
void visit (const ir::operation::Reduce &op) override
 
void visit (const ir::operation::Reshape &op) override
 
void visit (const ir::operation::ResizeBilinear &op) override
 
void visit (const ir::operation::Reverse &op) override
 
void visit (const ir::operation::Select &op) override
 
void visit (const ir::operation::Shape &op) override
 
void visit (const ir::operation::Slice &op) override
 
void visit (const ir::operation::Softmax &op) override
 
void visit (const ir::operation::SpaceToBatchND &op) override
 
void visit (const ir::operation::Split &op) override
 
void visit (const ir::operation::Squeeze &op) override
 
void visit (const ir::operation::StridedSlice &op) override
 
void visit (const ir::operation::SquaredDifference &op) override
 
void visit (const ir::operation::Tile &op) override
 
void visit (const ir::operation::Transpose &op) override
 
void visit (const ir::operation::Unpack &op) override
 
- Public Member Functions inherited from onert::ir::OperationVisitor
virtual ~OperationVisitor ()=default
 

Detailed Description

Class to infer shape of output tensor at execution time and allocate memory fo output tensor if needed.

Definition at line 36 of file DynamicShapeInferer.h.

Constructor & Destructor Documentation

◆ DynamicShapeInferer()

onert::exec::DynamicShapeInferer::DynamicShapeInferer ( const std::shared_ptr< backend::ITensorRegistry > &  tensor_registry)
inline

Definition at line 39 of file DynamicShapeInferer.h.

40 : _tensor_registry(tensor_registry)
41 {
42 // DO NOTHING
43 }

Member Function Documentation

◆ visit() [1/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::ArgMinMax op)
override

Definition at line 95 of file DynamicShapeInferer.cc.

96{
97 const auto input_idx{op.getInputs().at(ir::operation::ArgMinMax::Input::INPUT)};
98 const auto input = _tensor_registry->getITensor(input_idx);
99
100 const auto axis_idx{op.getInputs().at(ir::operation::ArgMinMax::Input::AXIS)};
101 const auto axis = _tensor_registry->getITensor(axis_idx);
102
103 auto output_ind = op.getOutputs().at(0);
104 auto output = _tensor_registry->getITensor(output_ind);
105
106 if (!input->is_dynamic() && !output->is_dynamic())
107 return;
108
109 auto input_shape = input->getShape();
110 auto axis_value = *reinterpret_cast<const int32_t *>(axis->buffer());
111 const auto rank = input_shape.rank();
112 axis_value = axis_value < 0 ? axis_value + rank : axis_value;
113
114 ir::Shape new_shape = shape_inference::inferArgMinMaxShape(input_shape, axis_value, rank);
115
116 output->applyShape(new_shape);
117 assert(output->buffer() != nullptr);
118}
ir::Shape inferArgMinMaxShape(const ir::Shape &input_shape, int axis, int rank)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::ArgMinMax::AXIS, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferArgMinMaxShape(), and onert::ir::operation::ArgMinMax::INPUT.

◆ visit() [2/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::BatchMatMul op)
override

Definition at line 120 of file DynamicShapeInferer.cc.

121{
122 const auto lhs_index = op.getInputs().at(ir::operation::BatchMatMul::Input::LHS);
123 const auto rhs_index = op.getInputs().at(ir::operation::BatchMatMul::Input::RHS);
124 auto lhs = _tensor_registry->getITensor(lhs_index);
125 auto rhs = _tensor_registry->getITensor(rhs_index);
126
127 if (!lhs->is_dynamic() && !rhs->is_dynamic())
128 return;
129
130 const auto output_index = op.getOutputs().at(0);
131 auto output = _tensor_registry->getITensor(output_index);
132
133 auto lhs_shape = lhs->getShape();
134 auto rhs_shape = rhs->getShape();
135 // TODO
136
137 auto new_shape = shape_inference::inferBatchMatMulShape(lhs_shape, rhs_shape, op.param());
138 output->applyShape(new_shape);
139}
ir::Shape inferBatchMatMulShape(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape, const ir::operation::BatchMatMul::Param &param)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferBatchMatMulShape(), onert::ir::operation::BatchMatMul::LHS, onert::ir::operation::BatchMatMul::param(), and onert::ir::operation::BatchMatMul::RHS.

◆ visit() [3/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::BCQFullyConnected op)
override

Definition at line 141 of file DynamicShapeInferer.cc.

142{
143 const auto input_idx{op.getInputs().at(ir::operation::BCQFullyConnected::Input::INPUT)};
144 const auto &input = _tensor_registry->getITensor(input_idx);
145
146 const auto cluster_idx{
148 const auto &cluster = _tensor_registry->getITensor(cluster_idx);
149 assert(cluster->is_constant());
150
151 if (!input->is_dynamic())
152 return;
153
154 auto input_shape = input->getShape();
155 auto cluster_shape = cluster->getShape();
156
157 auto cluster_buf = reinterpret_cast<const int32_t *>(cluster->buffer());
158 assert(cluster_buf);
159
160 ir::Shape new_shape =
161 shape_inference::inferBCQFullyConnectedShape(input_shape, cluster_shape, cluster_buf);
162
163 auto output_ind = op.getOutputs().at(0);
164 auto output = _tensor_registry->getITensor(output_ind);
165
166 output->applyShape(new_shape);
167 assert(output->buffer() != nullptr);
168}
ir::Shape inferBCQFullyConnectedShape(const ir::Shape &in_shape, const ir::Shape &cluster_shape, const int32_t *cluster_buf)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferBCQFullyConnectedShape(), onert::ir::operation::BCQFullyConnected::INPUT, and onert::ir::operation::BCQFullyConnected::WEIGHTS_CLUSTERS.

◆ visit() [4/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::BCQGather op)
override

Definition at line 170 of file DynamicShapeInferer.cc.

171{
172 const auto indices_idx{op.getInputs().at(ir::operation::BCQGather::Input::INDICES)};
173 const auto &indices = _tensor_registry->getITensor(indices_idx);
174
175 const auto input_binary_idx{op.getInputs().at(ir::operation::BCQGather::Input::INPUT_BINARY)};
176 const auto &input_binary = _tensor_registry->getITensor(input_binary_idx);
177
178 const auto cluster_idx{op.getInputs().at(ir::operation::BCQGather::Input::INPUT_CLUSTERS)};
179 const auto &cluster = _tensor_registry->getITensor(cluster_idx);
180 assert(cluster->is_constant());
181
182 if (!indices->is_dynamic())
183 return;
184
185 auto indices_shape = indices->getShape();
186 auto cluster_shape = cluster->getShape();
187 auto rank = input_binary->getShape().rank();
188
189 auto cluster_buf = reinterpret_cast<const int32_t *>(cluster->buffer());
190 assert(cluster_buf);
191
192 ir::Shape new_shape = shape_inference::inferBCQGatherShape(indices_shape, cluster_shape,
193 cluster_buf, rank, op.param());
194
195 auto output_ind = op.getOutputs().at(0);
196 auto output = _tensor_registry->getITensor(output_ind);
197
198 output->applyShape(new_shape);
199 assert(output->buffer() != nullptr);
200}
ir::Shape inferBCQGatherShape(const ir::Shape &indices_shape, const ir::Shape &cluster_shape, const int32_t *cluster_buf, int rank, const ir::operation::BCQGather::Param &param)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::ir::operation::BCQGather::INDICES, onert::shape_inference::inferBCQGatherShape(), onert::ir::operation::BCQGather::INPUT_BINARY, onert::ir::operation::BCQGather::INPUT_CLUSTERS, and onert::ir::operation::BCQGather::param().

◆ visit() [5/44]

◆ visit() [6/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::BroadcastTo op)
override

Definition at line 208 of file DynamicShapeInferer.cc.

209{
210 auto output_ind = op.getOutputs().at(0);
211 auto output = _tensor_registry->getITensor(output_ind);
212
213 auto input_idx = op.getInputs().at(ir::operation::BroadcastTo::INPUT);
214 auto input = _tensor_registry->getITensor(input_idx);
215
216 if ((!input->is_dynamic()) && (!output->is_dynamic()))
217 return;
218
219 auto shape_idx = op.getInputs().at(ir::operation::Tile::Input::MULTIPLES);
220 const auto &shape = _tensor_registry->getITensor(shape_idx);
221
222 assert(shape); // It shouldn't be 0.
223
225 shape->getShape(), reinterpret_cast<const int32_t *>(shape->buffer()));
226
227 // set output shape and output buffer
228 output->applyShape(output_shape);
229 assert(output->buffer() != nullptr);
230}
const luci_interpreter::RuntimeShape output_shape
ir::Shape inferBroadcastToShape(const ir::Shape shp_shape, const int32_t *shp_buf)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferBroadcastToShape(), onert::ir::operation::BroadcastTo::INPUT, onert::ir::operation::Tile::MULTIPLES, and output_shape.

◆ visit() [7/44]

◆ visit() [8/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Concat op)
override

Definition at line 238 of file DynamicShapeInferer.cc.

239{
240 /*
241 The state after compilation (satic shape inference) could be one of the following:
242
243 inputs output execution-time shape inf required
244 ------------------------------------------ ---------------------------------
245 case 1) all static static X
246 case 2) at least on is dynamic dynamic O
247
248 Then nnfw_apply_tensorinf() could change one or both inputs dynamic.
249 So, in this method, we have one more state and we have to re-calculate shape for this shape.
250
251 case 3) at least on is dynamic static O
252
253 So, only when all inputs are static, we can skip dynamic shape inference.
254 */
255 bool all_static = true;
256 for (auto &&input_ind : op.getInputs())
257 {
258 auto input = _tensor_registry->getITensor(input_ind);
259 if (input->is_dynamic())
260 {
261 all_static = false;
262 break;
263 }
264 }
265
266 if (all_static)
267 return;
268
269 // sanity check
270 {
271 auto isConcatible = [](const backend::ITensor *input1, const backend::ITensor *input2,
272 int32_t axis) {
273 auto shape1 = input1->getShape();
274 auto shape2 = input2->getShape();
275 if (shape1.rank() != shape2.rank())
276 return false;
277
278 for (int i = 0; i < shape1.rank(); i++)
279 {
280 auto positive_axis = (axis >= 0) ? axis : axis + input1->getShape().rank();
281
282 if (i != positive_axis)
283 if (shape1.dim(i) != shape2.dim(i))
284 return false;
285 }
286
287 return true;
288 };
289
290 auto first_input_ind = op.getInputs().at(0);
291 auto first_input = _tensor_registry->getITensor(first_input_ind);
292
293 for (auto &&input_ind : op.getInputs())
294 {
295 auto input = _tensor_registry->getITensor(input_ind);
296 if (input != first_input && !isConcatible(first_input, input, op.param().axis))
297 throw std::runtime_error("input shapes does not matched for concat");
298 }
299 }
300
301 // getting output shape
303 for (auto &&input_ind : op.getInputs())
304 {
305 auto input = _tensor_registry->getITensor(input_ind);
306 ir::Shape shape = input->getShape();
307
308 in_shapes.emplace_back(shape);
309 }
310
311 auto output_ind = op.getOutputs().at(0);
312 auto output = _tensor_registry->getITensor(output_ind);
313 auto output_shape = shape_inference::inferConcatShape(in_shapes, op.param());
314
315 output->applyShape(output_shape);
316}
nnfw::cker::Shape getShape(const IPortableTensor *tensor)
std::vector< ir::Shape > Shapes
ir::Shape inferConcatShape(const Shapes &in_shapes, const ir::operation::Concat::Param &param)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::Concat::Param::axis, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::backend::ITensor::getShape(), onert::shape_inference::inferConcatShape(), output_shape, and onert::ir::operation::Concat::param().

◆ visit() [9/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Conv2D op)
override

Definition at line 318 of file DynamicShapeInferer.cc.

319{
320 // check if input is not dynamic
321 auto input_ind = op.getInputs().at(ir::operation::Conv2D::INPUT);
322 auto input = _tensor_registry->getITensor(input_ind);
323
324 auto ker_ind = op.getInputs().at(ir::operation::Conv2D::KERNEL);
325 auto ker = _tensor_registry->getITensor(ker_ind);
326
327 if ((!input->is_dynamic()) && (!ker->is_dynamic()))
328 return;
329
330 ir::Shape input_shape = input->getShape();
331 ir::Shape ker_shape = ker->getShape();
332
333 auto output_ind = op.getOutputs().at(0);
334 auto output = _tensor_registry->getITensor(output_ind);
335
336 ir::Shape output_shape = shape_inference::inferConv2DShape(input_shape, ker_shape, op.param());
337
338 output->applyShape(output_shape);
339 assert(output->buffer() != nullptr);
340}
ir::Shape inferConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape, const ir::operation::Conv2D::Param &param)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferConv2DShape(), onert::ir::operation::Conv2D::INPUT, onert::ir::operation::Conv2D::KERNEL, output_shape, and onert::ir::operation::Conv2D::param().

◆ visit() [10/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::DetectionPostProcess op)
override

Definition at line 604 of file DynamicShapeInferer.cc.

605{
606 // NOTE DetectionPostProcess's undefined outputs' shape are decided on compile time
607 // by static shape inferer.
608 // DetectionPostProcess's outputs' shape are independent with input shape
609 // and decided by parameter value.
610}

◆ visit() [11/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::ElementwiseActivation op)
override

◆ visit() [12/44]

◆ visit() [13/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::ElementwiseUnary op)
override

◆ visit() [14/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::ExpandDims op)
override

Definition at line 358 of file DynamicShapeInferer.cc.

359{
360 // check if input is not dynamic
361 auto input_ind = op.getInputs().at(ir::operation::ExpandDims::INPUT);
362 auto input = _tensor_registry->getITensor(input_ind);
363
364 // check if output is not dynamic, meaning when 1st input is static and 2nd input is const
365 auto output_ind = op.getOutputs().at(0);
366 auto output = _tensor_registry->getITensor(output_ind);
367
368 /*
369 Here, the state after compilation (satic shape inference) could be one of the following:
370
371 input1 input2 output execution-time shape inf required
372 ----------------------------- --------------------------------
373 case 1) static const static X
374 case 2) static placeholder dynamic O
375 case 3) dynamic const dynamic O
376 case 4) dynamic placeholder dynamic O
377
378 Then nnfw_apply_tensorinf() could change input dynamic.
379 So, in this method, we could have one more state and we have to re-calculate shape
380 for this shape.
381
382 case 5) dynamic const static O
383
384 So, only when input1 and ouput are static, we can skip dynamic shape inference.
385 */
386 if ((!input->is_dynamic()) && (!output->is_dynamic()))
387 return;
388
389 ir::Shape input_shape = input->getShape();
390
391 auto axis_ind = op.getInputs().at(ir::operation::ExpandDims::AXIS);
392 auto axis = _tensor_registry->getITensor(axis_ind);
393 auto axis_type = axis->data_type();
394 assert(axis_type == ir::DataType::INT32 || axis_type == ir::DataType::INT64);
395
396 assert(axis->buffer());
397 int32_t axis_value =
398 (axis_type == ir::DataType::INT32)
399 ? reinterpret_cast<const int32_t *>(axis->buffer())[0]
400 : static_cast<int32_t>(reinterpret_cast<const int64_t *>(axis->buffer())[0]);
401
402 auto output_shape = shape_inference::inferExpandDimsShape(input_shape, axis_value);
403
404 output->applyShape(output_shape);
405 assert(output->buffer() != nullptr);
406}
ir::Shape inferExpandDimsShape(const ir::Shape &in_shape, int32_t axis)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::ExpandDims::AXIS, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferExpandDimsShape(), onert::ir::operation::ExpandDims::INPUT, and output_shape.

◆ visit() [15/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Fill op)
override

Definition at line 408 of file DynamicShapeInferer.cc.

409{
410 // check if output is not dynamic
411 auto output_ind = op.getOutputs().at(0);
412 auto output = _tensor_registry->getITensor(output_ind);
413 auto shape_ind = op.getInputs().at(ir::operation::Fill::Input::SHAPE);
414 auto shape = _tensor_registry->getITensor(shape_ind);
415
416 if ((!shape->is_dynamic()) && (!output->is_dynamic()))
417 return;
418
419 const auto dims_type = shape->data_type();
420 assert(dims_type == ir::DataType::INT32 || dims_type == ir::DataType::INT64);
421
422 auto dims_buf = shape->buffer();
423 assert(dims_buf);
424
425 const auto &dims_shape = shape->getShape();
426 const auto &output_shape = ((dims_type == ir::DataType::INT32)
427 ? shape_inference::inferFillShape<int32_t>(
428 dims_shape, reinterpret_cast<const int32_t *>(dims_buf))
429 : shape_inference::inferFillShape<int64_t>(
430 dims_shape, reinterpret_cast<const int64_t *>(dims_buf)));
431
432 output->applyShape(output_shape);
433 assert(output->buffer() != nullptr);
434}
ir::Shape inferFillShape(const ir::Shape &fill_shape, const T *shape_buf)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), output_shape, and onert::ir::operation::Fill::SHAPE.

◆ visit() [16/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::FullyConnected op)
override

Definition at line 436 of file DynamicShapeInferer.cc.

437{
438 const auto input_idx{op.getInputs().at(ir::operation::FullyConnected::Input::INPUT)};
439 const auto &input = _tensor_registry->getITensor(input_idx);
440
441 const auto ker_idx{op.getInputs().at(ir::operation::FullyConnected::Input::WEIGHT)};
442 const auto &ker = _tensor_registry->getITensor(ker_idx);
443
444 if (!input->is_dynamic() && !ker->is_dynamic())
445 return;
446
447 auto input_shape = input->getShape();
448 auto ker_shape = ker->getShape();
449
450 ir::Shape new_shape = shape_inference::inferFullyConnectedShape(input_shape, ker_shape);
451
452 auto output_ind = op.getOutputs().at(0);
453 auto output = _tensor_registry->getITensor(output_ind);
454
455 output->applyShape(new_shape);
456 assert(output->buffer() != nullptr);
457}
ir::Shape inferFullyConnectedShape(const ir::Shape &in_shape, const ir::Shape &ker_shape)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferFullyConnectedShape(), onert::ir::operation::FullyConnected::INPUT, and onert::ir::operation::FullyConnected::WEIGHT.

◆ visit() [17/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::FusedBatchNorm op)
override

◆ visit() [18/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Gather op)
override

Definition at line 464 of file DynamicShapeInferer.cc.

465{
466 const auto input_idx{op.getInputs().at(ir::operation::Gather::Input::INPUT)};
467 const auto &input = _tensor_registry->getITensor(input_idx);
468 auto input_shape = input->getShape();
469
470 const auto indices_idx{op.getInputs().at(ir::operation::Gather::Input::INDICES)};
471 const auto &indices = _tensor_registry->getITensor(indices_idx);
472 auto indices_shape = indices->getShape();
473
474 if (!(input->is_dynamic()) && !(indices->is_dynamic()))
475 return;
476
477 const auto rank = input_shape.rank();
478 const auto axis = ((op.param().axis < 0) ? rank + op.param().axis : op.param().axis);
479
480 assert(0 <= axis && axis < rank);
481
482 ir::Shape new_shape = shape_inference::inferGatherShape(input_shape, indices_shape, axis, rank);
483
484 auto output_ind = op.getOutputs().at(0);
485 auto output = _tensor_registry->getITensor(output_ind);
486
487 output->applyShape(new_shape);
488 assert(output->buffer() != nullptr);
489}
ir::Shape inferGatherShape(const ir::Shape &input_shape, const ir::Shape &indices_shape, int axis, int rank)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::Gather::Param::axis, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::ir::operation::Gather::INDICES, onert::shape_inference::inferGatherShape(), onert::ir::operation::Gather::INPUT, and onert::ir::operation::Gather::param().

◆ visit() [19/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::L2Normalization op)
override

◆ visit() [20/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::LSTM op)
override

Definition at line 496 of file DynamicShapeInferer.cc.

497{
498 const auto output_index{op.getOutputs().at(ir::operation::LSTM::Output::OUTPUT)};
499 auto output = _tensor_registry->getITensor(output_index);
500
501 const auto output_state_out_index{
503
504 const auto cell_state_out_index{op.getOutputs().at(ir::operation::LSTM::Output::CELL_STATE_OUT)};
505
506 const auto scratch_buffer_index{op.getOutputs().at(ir::operation::LSTM::Output::SCRATCH_BUFFER)};
507
508 if (!output->is_dynamic() &&
509 !(_tensor_registry->getITensor(output_state_out_index) != nullptr &&
510 _tensor_registry->getITensor(output_state_out_index)->is_dynamic()) &&
511 !(_tensor_registry->getITensor(cell_state_out_index) != nullptr &&
512 _tensor_registry->getITensor(cell_state_out_index)->is_dynamic()) &&
513 !(_tensor_registry->getITensor(scratch_buffer_index) != nullptr &&
514 _tensor_registry->getITensor(cell_state_out_index)->is_dynamic()))
515 return;
516
517 const auto input_index{op.getInputs().at(ir::operation::LSTM::Input::INPUT)};
518 const auto input = _tensor_registry->getITensor(input_index);
519 const auto input_shape = input->getShape();
520
521 const auto input_to_output_weights_index{
523 const auto input_to_output_weights = _tensor_registry->getITensor(input_to_output_weights_index);
524 const auto input_to_output_weights_shape = input_to_output_weights->getShape();
525
526 const auto recurrent_to_output_weights_index{
528 const auto recurrent_to_output_weights =
529 _tensor_registry->getITensor(recurrent_to_output_weights_index);
530 const auto recurrent_to_output_weights_shape = recurrent_to_output_weights->getShape();
531
532 // re-sizing outputs
533 const int n_batch =
534 (input_shape.rank() == 3 && op.param().time_major) ? input_shape.dim(1) : input_shape.dim(0);
535 const int n_cell = input_to_output_weights_shape.dim(0);
536 const int n_output = recurrent_to_output_weights_shape.dim(1);
537 if (input_shape.rank() == 3)
538 {
539 if (op.param().time_major)
540 output->applyShape(ir::Shape{input_shape.dim(0), n_batch, n_output});
541 else
542 output->applyShape(ir::Shape{n_batch, input_shape.dim(1), n_output});
543 }
544 else
545 {
546 assert(input_shape.rank() == 2);
547 output->applyShape(ir::Shape{n_batch, n_output});
548 }
549 assert(output->buffer() != nullptr);
550
551 auto output_state_out = _tensor_registry->getITensor(output_state_out_index);
552 if (output_state_out != nullptr)
553 {
554 output_state_out->applyShape(ir::Shape{n_batch, n_output});
555 assert(output_state_out->buffer() != nullptr);
556 }
557
558 auto cell_state_out = _tensor_registry->getITensor(cell_state_out_index);
559 if (cell_state_out != nullptr)
560 {
561 cell_state_out->applyShape(ir::Shape{n_batch, n_cell});
562 assert(cell_state_out->buffer() != nullptr);
563 }
564
565 auto scratch_buffer = _tensor_registry->getITensor(scratch_buffer_index);
566 if (scratch_buffer != nullptr)
567 {
568 const auto input_to_input_weights_index{
570 const auto recurrent_to_input_weights_index{
572
573 const auto input_to_input_weights_shape =
574 _tensor_registry->getITensor(input_to_input_weights_index)->getShape();
575 bool has_input_to_input_weights =
576 input_to_input_weights_shape.dim(0) != 0 && input_to_input_weights_shape.dim(1) != 0;
577
578 const auto recurrent_to_input_weights_shape =
579 _tensor_registry->getITensor(recurrent_to_input_weights_index)->getShape();
580 bool has_recurrent_to_input_weights =
581 recurrent_to_input_weights_shape.dim(0) != 0 && recurrent_to_input_weights_shape.dim(1) != 0;
582
583 // NOTE The cell_to_input_weights do not exist in non-peephole although regular LSTM(non-CIFG).
584 // true: no CIFG
585 // false: CIFG
586 bool has_cifg_param = has_input_to_input_weights && has_recurrent_to_input_weights;
587 if (has_cifg_param)
588 {
589 scratch_buffer->applyShape(ir::Shape{n_batch, n_cell * 4});
590 }
591 else
592 {
593 scratch_buffer->applyShape(ir::Shape{n_batch, n_cell * 3});
594 }
595 assert(scratch_buffer->buffer() != nullptr);
596 }
597}

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::LSTM::CELL_STATE_OUT, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::ir::operation::LSTM::INPUT, onert::ir::operation::LSTM::INPUT_TO_OUTPUT_WEIGHTS, onert::ir::operation::LSTM::OUTPUT, onert::ir::operation::LSTM::OUTPUT_STATE_OUT, onert::ir::operation::LSTM::param(), onert::ir::operation::LSTM::RECURRENT_TO_OUTPUT_WEIGHTS, onert::ir::operation::LSTM::SCRATCH_BUFFER, and onert::ir::operation::LSTM::Param::time_major.

◆ visit() [21/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::MatrixBandPart op)
override

◆ visit() [22/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::OneHot op)
override

Definition at line 612 of file DynamicShapeInferer.cc.

613{
614 auto output_ind = op.getOutputs().at(0);
615 auto output = _tensor_registry->getITensor(output_ind);
616
617 auto indices_ind = op.getInputs().at(ir::operation::OneHot::INDICES);
618 const auto &indices = _tensor_registry->getITensor(indices_ind);
619 auto indices_shape = indices->getShape();
620
621 auto depth_ind = op.getInputs().at(ir::operation::OneHot::DEPTH);
622 const auto &depth = _tensor_registry->getITensor(depth_ind);
623
624 if (!indices->is_dynamic() && !depth->is_dynamic())
625 {
626 return;
627 }
628
629 int32_t *depth_buf = reinterpret_cast<int32_t *>(depth->buffer());
630 assert(depth_buf);
631 const auto axis_val = op.param().axis;
632
633 ir::Shape new_shape = shape_inference::inferOnehotShape(indices_shape, *depth_buf, axis_val);
634 output->applyShape(new_shape);
635 assert(output->buffer() != nullptr);
636}
ir::Shape inferOnehotShape(const ir::Shape &input_shape, const int depth, int axis)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::OneHot::Param::axis, onert::ir::operation::OneHot::DEPTH, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::ir::operation::OneHot::INDICES, onert::shape_inference::inferOnehotShape(), and onert::ir::operation::OneHot::param().

◆ visit() [23/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Pack op)
override

Definition at line 638 of file DynamicShapeInferer.cc.

639{
640 bool is_any_of_inputs_dynamic = [&]() -> bool {
641 for (uint32_t i = 0; i < op.getInputs().size(); ++i)
642 {
643 const auto &input = _tensor_registry->getITensor(op.getInputs().at(i));
644 if (input->is_dynamic())
645 {
646 return true;
647 }
648 }
649 return false;
650 }();
651
652 const auto input_idx{op.getInputs().at(0)};
653 const auto &input = _tensor_registry->getITensor(input_idx);
654 auto input_shape = input->getShape();
655
656 auto output_ind = op.getOutputs().at(0);
657 auto output = _tensor_registry->getITensor(output_ind);
658
659 if (!is_any_of_inputs_dynamic && !output->is_dynamic())
660 return;
661
662 const auto rank = input_shape.rank() + 1;
663 const auto axis = ((op.param().axis < 0) ? rank + op.param().axis : op.param().axis);
664 const auto num = op.param().num;
665
666 assert(0 <= axis && axis < rank);
667
668 ir::Shape new_shape = shape_inference::inferPackShape(input_shape, axis, rank, num);
669
670 output->applyShape(new_shape);
671 assert(output->buffer() != nullptr);
672}
ir::Shape inferPackShape(const ir::Shape &input_shape, int axis, int rank, int num)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::Pack::Param::axis, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferPackShape(), onert::ir::operation::Pack::Param::num, onert::ir::operation::Pack::param(), and onert::ir::OperandIndexSequence::size().

◆ visit() [24/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Pad op)
override

Definition at line 674 of file DynamicShapeInferer.cc.

675{
676 // check if output is not dynamic
677 auto output_ind = op.getOutputs().at(0);
678 auto output = _tensor_registry->getITensor(output_ind);
679
680 auto input_ind = op.getInputs().at(ir::operation::Pad::Input::INPUT);
681 auto input = _tensor_registry->getITensor(input_ind);
682
683 auto pad_ind = op.getInputs().at(ir::operation::Pad::Input::PAD);
684 auto pad = _tensor_registry->getITensor(pad_ind);
685
686 // check if input and output are not dynamic
687 if ((!input->is_dynamic()) && (!output->is_dynamic()))
688 return;
689
690 int32_t *pad_buf = reinterpret_cast<int32_t *>(pad->buffer());
691 assert(pad_buf);
692
693 auto output_shape =
694 shape_inference::inferPadShape(input->getShape(), pad_buf, pad->getShape().num_elements());
695
696 // change output shape and reallocate output tensor memory
697 output->applyShape(output_shape);
698 assert(output->buffer() != nullptr);
699}
ir::Shape inferPadShape(const ir::Shape &in_shape, const int32_t *pad_buf, const size_t num_pads)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferPadShape(), onert::ir::operation::Pad::INPUT, output_shape, and onert::ir::operation::Pad::PAD.

◆ visit() [25/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Permute op)
override

Definition at line 701 of file DynamicShapeInferer.cc.

702{
703 // NOTE Permute is a special operation which does not do shape inference before the actual
704 // function(kernel) execution. Shape inference and output allocation will be done in the kernel
705 // on-the-fly, as it must support inter-backend inference/allocation.
706}

◆ visit() [26/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Pool2D op)
override

Definition at line 708 of file DynamicShapeInferer.cc.

709{
710 // check if input is not dynamic
711 auto input_ind = op.getInputs().at(ir::operation::Pool2D::INPUT);
712 auto input = _tensor_registry->getITensor(input_ind);
713
714 if (!input->is_dynamic())
715 return;
716
717 ir::Shape input_shape = input->getShape();
718
719 auto output_ind = op.getOutputs().at(0);
720 auto output = _tensor_registry->getITensor(output_ind);
721
722 ir::Shape output_shape = shape_inference::inferPoolShape(input_shape, op.param());
723
724 output->applyShape(output_shape);
725 assert(output->buffer() != nullptr);
726}
ir::Shape inferPoolShape(const ir::Shape &in_shape, const ir::operation::Pool2D::Param &param)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferPoolShape(), onert::ir::operation::Pool2D::INPUT, output_shape, and onert::ir::operation::Pool2D::param().

◆ visit() [27/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Pow op)
override

◆ visit() [28/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Range op)
override

Definition at line 734 of file DynamicShapeInferer.cc.

735{
736 // check if output is not dynamic
737 auto output_ind = op.getOutputs().at(0);
738 auto output = _tensor_registry->getITensor(output_ind);
739
740 // from op, access the buffer of second input to read new shape
741 auto start_idx = op.getInputs().at(ir::operation::Range::Input::START);
742 auto start_tensor = _tensor_registry->getITensor(start_idx);
743
744 auto limit_idx = op.getInputs().at(ir::operation::Range::Input::LIMIT);
745 auto limit_tensor = _tensor_registry->getITensor(limit_idx);
746
747 auto delta_idx = op.getInputs().at(ir::operation::Range::Input::DELTA);
748 auto delta_tensor = _tensor_registry->getITensor(delta_idx);
749
750 if (!start_tensor->is_dynamic() && !limit_tensor->is_dynamic() && !delta_tensor->is_dynamic() &&
751 !output->is_dynamic())
752 return;
753
754 ir::Shape new_shape;
755 if (output->data_type() == ir::DataType::FLOAT32)
756 {
757 new_shape =
758 shape_inference::inferRangeShape<float>(*reinterpret_cast<float *>(start_tensor->buffer()),
759 *reinterpret_cast<float *>(limit_tensor->buffer()),
760 *reinterpret_cast<float *>(delta_tensor->buffer()));
761 }
762 else if (output->data_type() == ir::DataType::INT32)
763 {
764 new_shape = shape_inference::inferRangeShape<int32_t>(
765 *reinterpret_cast<int32_t *>(start_tensor->buffer()),
766 *reinterpret_cast<int32_t *>(limit_tensor->buffer()),
767 *reinterpret_cast<int32_t *>(delta_tensor->buffer()));
768 }
769 output->applyShape(new_shape);
770 assert(output->buffer() != nullptr);
771}

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::Range::DELTA, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::ir::operation::Range::LIMIT, and onert::ir::operation::Range::START.

◆ visit() [29/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Reduce op)
override

Definition at line 773 of file DynamicShapeInferer.cc.

774{
775 const auto input_idx{op.getInputs().at(ir::operation::Reduce::Input::INPUT)};
776 const auto &input = _tensor_registry->getITensor(input_idx);
777 auto input_shape = input->getShape();
778
779 const auto axes_idx{op.getInputs().at(ir::operation::Reduce::Input::AXES)};
780 const auto &axes = _tensor_registry->getITensor(axes_idx);
781
782 if (!input->is_dynamic())
783 return;
784
785 std::vector<int32_t> axes_vec;
786 for (uint32_t i = 0; i < axes->getShape().num_elements(); ++i)
787 {
788 const auto buffer = axes->buffer() + axes->calcOffset({i});
789 switch (axes->data_type())
790 {
791 case ir::DataType::INT32:
792 {
793 axes_vec.emplace_back(*reinterpret_cast<const int32_t *>(buffer));
794 break;
795 }
796 case ir::DataType::INT64:
797 {
798 axes_vec.emplace_back(*reinterpret_cast<const int64_t *>(buffer));
799 break;
800 }
801 default:
802 throw std::runtime_error("DynamicShapeInferer " + op.name() + ": Not supported data type");
803 break;
804 }
805 }
806 const auto keep_dims = op.param().keep_dims;
807
808 auto output_ind = op.getOutputs().at(0);
809 auto output = _tensor_registry->getITensor(output_ind);
810
811 ir::Shape new_shape = shape_inference::inferReduceShape(input_shape, axes_vec, keep_dims);
812
813 output->applyShape(new_shape);
814 assert(output->buffer() != nullptr);
815}
uint32_t num_elements(const Shape &shape)
The number of elements of a feature map of a given shape.
Definition Shape.h:59
ir::Shape inferReduceShape(const ir::Shape &input_shape, const std::vector< int > &axes, bool keep_dims)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::Reduce::AXES, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferReduceShape(), onert::ir::operation::Reduce::INPUT, onert::ir::operation::Reduce::Param::keep_dims, onert::ir::operation::Reduce::name(), and onert::ir::operation::Reduce::param().

◆ visit() [30/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Reshape op)
override

Definition at line 817 of file DynamicShapeInferer.cc.

818{
819 // check if output is not dynamic
820 auto output_ind = op.getOutputs().at(0);
821 auto output = _tensor_registry->getITensor(output_ind);
822
823 auto input_ind = op.getInputs().at(ir::operation::Reshape::Input::INPUT);
824 auto input = _tensor_registry->getITensor(input_ind);
825
826 /*
827 Here, the state after compilation (satic shape inference) could be one of the following:
828
829 input1 input2 (or option) output execution-time shape inf required
830 ------------------------------------ --------------------------------
831 case 1) static const static X
832 case 2) static placeholder dynamic O
833 case 3) dynamic const dynamic O
834 case 4) dynamic placeholder dynamic O
835
836 Then nnfw_apply_tensorinf() could change input dynamic.
837 So, in this method, we could have one more state and we have to re-calculate shape
838 for this shape.
839
840 case 5) dynamic const static O
841
842 So, only when both input1 and ouput are static, we can skip dynamic shape inference.
843 */
844 if ((!input->is_dynamic()) && (!output->is_dynamic()))
845 return;
846
847 // New shape is given by second input tensor
848 if (op.getInputs().size() == 2)
849 {
850 // from op, access the buffer of second input to read new shape
851 auto new_shape_ind = op.getInputs().at(ir::operation::Reshape::Input::SHAPE);
852
853 // getting output shape by reading new_shape tensor buffer
854 auto new_shape = _tensor_registry->getITensor(new_shape_ind);
855 assert(new_shape);
856
857 int32_t *new_shape_buf = reinterpret_cast<int32_t *>(new_shape->buffer());
858 assert(new_shape_buf);
859
860 auto output_shape = shape_inference::inferReshapeShape(input->getShape(), new_shape_buf,
861 new_shape->getShape().num_elements());
862
863 // if shape is changed, change output shape and reallocate output tensor memory
864 if (output_shape != output->getShape() || output->buffer() == nullptr)
865 {
866 // change on output shape
867 output->applyShape(output_shape);
868 }
869 assert(output->buffer() != nullptr);
870 }
871 // New shape is given by option
872 else if (op.param().new_shape.size() != 0)
873 {
874 // Let's check the new_shape option
875 auto shape = op.param().new_shape;
876 auto output_shape =
877 shape_inference::inferReshapeShape(input->getShape(), shape.data(), shape.size());
878
879 // if shape is changed, change output shape and reallocate output tensor memory
880 if (output_shape != output->getShape() || output->buffer() == nullptr)
881 {
882 // change on output shape
883 output->applyShape(output_shape);
884 }
885 assert(output->buffer() != nullptr);
886 }
887 else
888 {
889 throw std::runtime_error("Reshape: new shape is missing");
890 return;
891 }
892}
ir::Shape inferReshapeShape(const ir::Shape &input_shape, const int32_t *shape_buf, const int32_t shape_num_elements)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferReshapeShape(), onert::ir::operation::Reshape::INPUT, onert::ir::operation::Reshape::Param::new_shape, output_shape, onert::ir::operation::Reshape::param(), onert::ir::operation::Reshape::SHAPE, and onert::ir::OperandIndexSequence::size().

◆ visit() [31/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::ResizeBilinear op)
override

Definition at line 894 of file DynamicShapeInferer.cc.

895{
896 // check if output is not dynamic
897 auto output_ind = op.getOutputs().at(0);
898 auto output = _tensor_registry->getITensor(output_ind);
899
900 auto input_ind = op.getInputs().at(ir::operation::Reshape::Input::INPUT);
901 auto input = _tensor_registry->getITensor(input_ind);
902
903 if ((!input->is_dynamic()) && (!output->is_dynamic()))
904 return;
905
906 // getting output shape from input shape and Params
907 int32_t height_out, width_out;
908 if (op.getInputs().size() == 2)
909 {
910 auto size_ind = op.getInputs().at(ir::operation::ResizeBilinear::Input::SIZE);
911 auto size = _tensor_registry->getITensor(size_ind);
912 if (size->data_type() == ir::DataType::INT32)
913 {
914 auto size_buf = reinterpret_cast<const int32_t *>(size->buffer());
915 height_out = size_buf[0];
916 width_out = size_buf[1];
917 }
918 else
919 {
920 throw std::runtime_error("DynamicShapeInferer ResizeBilinear : Unsupported data type");
921 }
922 }
923 else
924 {
925 height_out = op.param().height_out;
926 width_out = op.param().width_out;
927 }
928 auto output_shape =
929 shape_inference::inferResizeBilinearShape(input->getShape(), height_out, width_out);
930
931 // if shape is changed, change output shape and reallocate output tensor memory
932 if (output_shape != output->getShape() || output->buffer() == nullptr)
933 {
934 // change on output shape
935 output->applyShape(output_shape);
936 }
937 assert(output->buffer() != nullptr);
938}
ir::Shape inferResizeBilinearShape(const ir::Shape &in_shape, const int32_t output_height, const int32_t output_width)
int32_t size[5]
Definition Slice.cpp:35

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::ir::operation::ResizeBilinear::Param::height_out, onert::shape_inference::inferResizeBilinearShape(), onert::ir::operation::Reshape::INPUT, output_shape, onert::ir::operation::ResizeBilinear::param(), onert::ir::OperandIndexSequence::size(), size, onert::ir::operation::ResizeBilinear::SIZE, and onert::ir::operation::ResizeBilinear::Param::width_out.

◆ visit() [32/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Reverse op)
override

◆ visit() [33/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Select op)
override

Definition at line 945 of file DynamicShapeInferer.cc.

946{
947 const auto input_cond_idx = op.getInputs().at(ir::operation::Select::Input::CONDITION);
948 const auto &input_cond = _tensor_registry->getITensor(input_cond_idx);
949
950 const auto input_true_idx = op.getInputs().at(ir::operation::Select::Input::INPUT_TRUE);
951 const auto &input_true = _tensor_registry->getITensor(input_true_idx);
952
953 const auto input_false_idx = op.getInputs().at(ir::operation::Select::Input::INPUT_FALSE);
954 const auto &input_false = _tensor_registry->getITensor(input_false_idx);
955
956 if ((!input_cond->is_dynamic()) && (!input_true->is_dynamic()) && (!input_false->is_dynamic()))
957 {
958 return;
959 }
960
961 auto input_cond_shape = input_cond->getShape();
962 auto input_true_shape = input_true->getShape();
963 auto input_false_shape = input_false->getShape();
964
965 // Select output shpae
966 ir::Shape new_shape =
967 shape_inference::inferSelectShape(input_cond_shape, input_true_shape, input_false_shape);
968
969 auto output_ind = op.getOutputs().at(0);
970 auto output = _tensor_registry->getITensor(output_ind);
971
972 output->applyShape(new_shape);
973 assert(output->buffer() != nullptr);
974}
ir::Shape inferSelectShape(const ir::Shape &input_cond_shape, const ir::Shape &input_true_shape, const ir::Shape &input_false_shape)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::Select::CONDITION, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferSelectShape(), onert::ir::operation::Select::INPUT_FALSE, and onert::ir::operation::Select::INPUT_TRUE.

◆ visit() [34/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Shape op)
override

Definition at line 976 of file DynamicShapeInferer.cc.

977{
978 const auto input_idx{op.getInputs().at(0)};
979 const auto &input = _tensor_registry->getITensor(input_idx);
980 auto input_shape = input->getShape();
981
982 if (!input->is_dynamic())
983 return;
984
985 auto output_ind = op.getOutputs().at(0);
986 auto output = _tensor_registry->getITensor(output_ind);
987
988 ir::Shape output_shape;
989 output_shape.append(input_shape.rank());
990
991 output->applyShape(output_shape);
992 assert(output->buffer() != nullptr);
993}

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), and output_shape.

◆ visit() [35/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Slice op)
override

Definition at line 995 of file DynamicShapeInferer.cc.

996{
997 const auto input_index{op.getInputs().at(ir::operation::Slice::Input::INPUT)};
998 const auto input = _tensor_registry->getITensor(input_index);
999 const auto begins_index{op.getInputs().at(ir::operation::Slice::Input::BEGINS)};
1000 const auto begins = _tensor_registry->getITensor(begins_index);
1001 const auto sizes_index{op.getInputs().at(ir::operation::Slice::Input::SIZES)};
1002 const auto sizes = _tensor_registry->getITensor(sizes_index);
1003 auto output_index = op.getOutputs().at(0);
1004 auto output = _tensor_registry->getITensor(output_index);
1005
1006 if (!(input->is_dynamic() || begins->is_dynamic() || sizes->is_dynamic() || output->is_dynamic()))
1007 {
1008 return;
1009 }
1010
1011 ir::Shape input_shape = input->getShape();
1012 auto begins_buf = reinterpret_cast<const int32_t *>(begins->buffer());
1013 auto sizes_buf = reinterpret_cast<const int32_t *>(sizes->buffer());
1014
1015 ir::Shape new_shape = shape_inference::inferSliceShape(input_shape, begins_buf, sizes_buf);
1016
1017 output->applyShape(new_shape);
1018 assert(output->buffer() != nullptr);
1019}
ir::Shape inferSliceShape(const ir::Shape &input_shape, const T *begins_buf, const T *sizes_buf)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::Slice::BEGINS, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferSliceShape(), onert::ir::operation::Slice::INPUT, and onert::ir::operation::Slice::SIZES.

◆ visit() [36/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Softmax op)
override

◆ visit() [37/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::SpaceToBatchND op)
override

Definition at line 1026 of file DynamicShapeInferer.cc.

1027{
1028 const auto input_idx{op.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)};
1029 const auto block_shape_idx{op.getInputs().at(ir::operation::SpaceToBatchND::Input::BLOCK_SIZE)};
1030 const auto padding_idx{op.getInputs().at(ir::operation::SpaceToBatchND::Input::PADDINGS)};
1031 auto output_idx{op.getOutputs().at(0)};
1032
1033 const auto &input = _tensor_registry->getITensor(input_idx);
1034 const auto &block_shape = _tensor_registry->getITensor(block_shape_idx);
1035 const auto &padding = _tensor_registry->getITensor(padding_idx);
1036 auto output = _tensor_registry->getITensor(output_idx);
1037
1038 if (!(input->is_dynamic() || block_shape->is_dynamic() || padding->is_dynamic() ||
1039 output->is_dynamic()))
1040 {
1041 return;
1042 }
1043
1044 auto input_shape = input->getShape();
1045 auto block_shape_shape = block_shape->getShape();
1046 auto padding_shape = padding->getShape();
1047
1048 auto block_shape_data = reinterpret_cast<int32_t *>(block_shape->buffer());
1049 auto padding_data = reinterpret_cast<int32_t *>(padding->buffer());
1050
1051 ir::Shape new_shape = shape_inference::inferSpaceToBatchNDShape(
1052 input_shape, block_shape_shape, padding_shape, block_shape_data, padding_data);
1053
1054 output->applyShape(new_shape);
1055 assert(output->buffer() != nullptr);
1056}
ir::Shape inferSpaceToBatchNDShape(const ir::Shape &input_shape, const ir::Shape &block_shape_shape, const ir::Shape &padding_shape, const int32_t *block_shape_buf, const int32_t *padding_buf)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::SpaceToBatchND::BLOCK_SIZE, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferSpaceToBatchNDShape(), onert::ir::operation::SpaceToBatchND::INPUT, and onert::ir::operation::SpaceToBatchND::PADDINGS.

◆ visit() [38/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Split op)
override

Definition at line 1058 of file DynamicShapeInferer.cc.

1059{
1060 const auto input_idx{op.getInputs().at(ir::operation::Split::Input::INPUT)};
1061 const auto &input = _tensor_registry->getITensor(input_idx);
1062
1063 // Return if all tensors are not dynamic
1064 bool has_dynamic = false;
1065 for (const auto &output_idx : op.getOutputs())
1066 {
1067 auto output = _tensor_registry->getITensor(output_idx);
1068 has_dynamic |= output->is_dynamic();
1069 }
1070 if (!input->is_dynamic() && !has_dynamic)
1071 {
1072 return;
1073 }
1074
1075 auto input_shape = input->getShape();
1076
1077 const auto axis_idx{op.getInputs().at(ir::operation::Split::Input::AXIS)};
1078 const auto &axis = _tensor_registry->getITensor(axis_idx);
1079
1080 auto axis_value = *reinterpret_cast<const int32_t *>(axis->buffer());
1081 const auto num_splits = op.param().num_splits;
1082 const auto rank = input_shape.rank();
1083 axis_value = axis_value < 0 ? axis_value + rank : axis_value;
1084
1085 assert(0 <= axis_value && axis_value < rank);
1086
1087 ir::Shape new_shape = shape_inference::inferSplitShape(input_shape, axis_value, num_splits);
1088 for (int out_tensor_idx = 0; out_tensor_idx < num_splits; out_tensor_idx++)
1089 {
1090 auto output_ind = op.getOutputs().at(out_tensor_idx);
1091 auto output = _tensor_registry->getITensor(output_ind);
1092
1093 output->applyShape(new_shape);
1094 assert(output->buffer() != nullptr);
1095 }
1096}
ir::Shape inferSplitShape(const ir::Shape input_shape, int axis_value, int num_splits)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::Split::AXIS, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferSplitShape(), onert::ir::operation::Split::INPUT, onert::ir::operation::Split::Param::num_splits, and onert::ir::operation::Split::param().

◆ visit() [39/44]

◆ visit() [40/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Squeeze op)
override

Definition at line 1104 of file DynamicShapeInferer.cc.

1105{
1106 const auto input_idx{op.getInputs().at(ir::operation::Squeeze::Input::INPUT)};
1107 const auto &input = _tensor_registry->getITensor(input_idx);
1108
1109 if (!input->is_dynamic())
1110 {
1111 return;
1112 }
1113
1114 auto input_shape = input->getShape();
1115
1116 // Squeeze output shpae
1117 ir::Shape new_shape = shape_inference::inferSqueezeShape(input_shape, op.param());
1118
1119 auto output_ind = op.getOutputs().at(0);
1120 auto output = _tensor_registry->getITensor(output_ind);
1121
1122 output->applyShape(new_shape);
1123 assert(output->buffer() != nullptr);
1124}
ir::Shape inferSqueezeShape(const ir::Shape &in_shape, const ir::operation::Squeeze::Param &param)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferSqueezeShape(), onert::ir::operation::Squeeze::INPUT, and onert::ir::operation::Squeeze::param().

◆ visit() [41/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::StridedSlice op)
override

Definition at line 1126 of file DynamicShapeInferer.cc.

1127{
1128
1129 const auto input_index{op.getInputs().at(ir::operation::StridedSlice::Input::INPUT)};
1130 auto input = _tensor_registry->getITensor(input_index);
1131 ir::Shape input_shape = input->getShape();
1132
1133 const auto starts_index{op.getInputs().at(ir::operation::StridedSlice::Input::STARTS)};
1134 auto starts = _tensor_registry->getITensor(starts_index);
1135
1136 const auto ends_index{op.getInputs().at(ir::operation::StridedSlice::Input::ENDS)};
1137 auto ends = _tensor_registry->getITensor(ends_index);
1138
1139 const auto strides_index{op.getInputs().at(ir::operation::StridedSlice::Input::STRIDES)};
1140 auto strides = _tensor_registry->getITensor(strides_index);
1141
1142 if (!(input->is_dynamic() || starts->is_dynamic() || ends->is_dynamic() || strides->is_dynamic()))
1143 {
1144 return;
1145 }
1146
1147 const auto begin_mask = op.param().begin_mask;
1148 const auto end_mask = op.param().end_mask;
1149 const auto shrink_axis_mask = op.param().shrink_axis_mask;
1150 const auto rank = input_shape.rank();
1151
1153 reinterpret_cast<uint32_t *>(starts->buffer()), reinterpret_cast<uint32_t *>(ends->buffer()),
1154 reinterpret_cast<uint32_t *>(strides->buffer()), begin_mask, end_mask, shrink_axis_mask, rank);
1155
1156 auto output_index = op.getOutputs().at(0);
1157 auto output = _tensor_registry->getITensor(output_index);
1158
1159 ir::Shape output_shape =
1160 onert::shape_inference::inferStridedSliceShape(input_shape, op_params, rank);
1161
1162 output->applyShape(output_shape);
1163 assert(output->buffer() != nullptr);
1164}
StridedSliceParams buildStridedSliceParams(const T *begin, const T *end, const T *strides, const uint32_t begin_mask, const uint32_t end_mask, const uint32_t shrink_axis_mask, const uint8_t rank)
ir::Shape inferStridedSliceShape(const ir::Shape &input_shape, const StridedSliceParams &op_params, uint32_t rank)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::StridedSlice::Param::begin_mask, onert::shape_inference::buildStridedSliceParams(), onert::ir::operation::StridedSlice::Param::end_mask, onert::ir::operation::StridedSlice::ENDS, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferStridedSliceShape(), onert::ir::operation::StridedSlice::INPUT, output_shape, onert::ir::operation::StridedSlice::param(), onert::ir::operation::StridedSlice::Param::shrink_axis_mask, onert::ir::operation::StridedSlice::STARTS, and onert::ir::operation::StridedSlice::STRIDES.

◆ visit() [42/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Tile op)
override

Definition at line 1166 of file DynamicShapeInferer.cc.

1167{
1168 auto output_ind = op.getOutputs().at(0);
1169 auto output = _tensor_registry->getITensor(output_ind);
1170
1171 auto input_idx = op.getInputs().at(ir::operation::Tile::Input::INPUT);
1172 auto input = _tensor_registry->getITensor(input_idx);
1173
1174 auto multiplier_idx = op.getInputs().at(ir::operation::Tile::Input::MULTIPLES);
1175 auto multiplier = _tensor_registry->getITensor(multiplier_idx);
1176
1177 if ((!input->is_dynamic()) && (!output->is_dynamic()))
1178 return;
1179
1180 auto input_shape = input->getShape();
1181 auto multiplier_buffer = reinterpret_cast<const int32_t *>(multiplier->buffer());
1182 assert(multiplier_buffer);
1183
1184 auto mult_shape = multiplier->getShape();
1186 input_shape, multiplier_buffer, mult_shape.rank() == 0 ? 1 : mult_shape.dim(0));
1187
1188 // set output shape and output buffer
1189 output->applyShape(output_shape);
1190 assert(output->buffer() != nullptr);
1191}
ir::Shape inferTileShape(const ir::Shape &in_shape, const int32_t *multiplier_buf, const int32_t multiplier_size)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferTileShape(), onert::ir::operation::Tile::INPUT, onert::ir::operation::Tile::MULTIPLES, and output_shape.

◆ visit() [43/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Transpose op)
override

Definition at line 1193 of file DynamicShapeInferer.cc.

1194{
1195 // check if output is not dynamic
1196 auto output_ind = op.getOutputs().at(0);
1197 auto output = _tensor_registry->getITensor(output_ind);
1198
1199 // from op, access the buffer of second input to read new shape
1200 auto input_ind = op.getInputs().at(ir::operation::Transpose::Input::INPUT);
1201 auto input = _tensor_registry->getITensor(input_ind);
1202 auto input_shape = input->getShape();
1203
1204 /*
1205 Here, the state after compilation (static shape inference) could be one of the following:
1206
1207 input perms output execution-time shape inf required
1208 ------------------------------------ --------------------------------
1209 case 1) static const static X
1210 case 2) static non-const dynamic O
1211 case 3) dynamic const dynamic O
1212 case 4) dynamic non-const dynamic O
1213
1214 So, only when both input1 and ouput are static, we can skip dynamic shape inference.
1215 */
1216 if ((!input->is_dynamic()) && (!output->is_dynamic()))
1217 return;
1218
1219 auto perm_ind = op.getInputs().at(ir::operation::Transpose::Input::PERMUTATION);
1220 auto perm = _tensor_registry->getITensor(perm_ind);
1221
1222 ir::Shape new_shape;
1223 // TODO Change perm->dimension(0) == 0 to perm->num_elements() == 0
1224 if (perm->getShape().dim(0) == 0) // This condition means that perm is (n-1...0)
1225 {
1226 // Call by (n-1...0)
1227 new_shape = shape_inference::inferTransposeShape(input_shape, nullptr, 0);
1228 }
1229 else
1230 {
1231 // Check rank
1232 if (static_cast<size_t>(input->getShape().rank()) != perm->getShape().num_elements())
1233 {
1234 throw std::runtime_error("DynamicShapeInferer failed, bad rank size: " +
1235 std::to_string(perm->getShape().num_elements()));
1236 }
1237
1238 // set output shape, based on input and params
1239 const auto perm_buffer = reinterpret_cast<const int32_t *>(perm->buffer());
1240 new_shape =
1241 shape_inference::inferTransposeShape(input_shape, perm_buffer, perm->getShape().dim(0));
1242 }
1243 output->applyShape(new_shape);
1244 assert(output->buffer() != nullptr);
1245}
ir::Shape inferTransposeShape(const ir::Shape &in_shape, const int32_t *perm_buf, const int32_t rank)

References onert::ir::OperandIndexSequence::at(), onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferTransposeShape(), onert::ir::operation::Transpose::INPUT, and onert::ir::operation::Transpose::PERMUTATION.

◆ visit() [44/44]

void onert::exec::DynamicShapeInferer::visit ( const ir::operation::Unpack op)
override

Definition at line 1247 of file DynamicShapeInferer.cc.

1248{
1249 // check if output is not dynamic
1250 const auto input_idx{op.getInputs().at(0)};
1251 const auto &input = _tensor_registry->getITensor(input_idx);
1252
1253 if (!input->is_dynamic())
1254 return;
1255
1256 auto input_shape = input->getShape();
1257
1258 const auto rank = input_shape.rank();
1259 const auto axis = ((op.param().axis < 0) ? rank + op.param().axis : op.param().axis);
1260 const auto num = op.param().num;
1261
1262 assert(0 <= axis && axis < rank);
1263
1264 ir::Shape new_shape = shape_inference::inferUnpackShape(input_shape, axis, rank);
1265
1266 for (int out_tensor_idx = 0; out_tensor_idx < num; out_tensor_idx++)
1267 {
1268 auto output_ind = op.getOutputs().at(out_tensor_idx);
1269 auto output = _tensor_registry->getITensor(output_ind);
1270
1271 output->applyShape(new_shape);
1272
1273 assert(output->buffer() != nullptr);
1274 }
1275}
ir::Shape inferUnpackShape(const ir::Shape &input_shape, int axis, int rank)

References onert::ir::OperandIndexSequence::at(), onert::ir::operation::Unpack::Param::axis, onert::ir::Operation::getInputs(), onert::ir::Operation::getOutputs(), onert::shape_inference::inferUnpackShape(), onert::ir::operation::Unpack::Param::num, and onert::ir::operation::Unpack::param().


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