ONE - On-device Neural Engine
Loading...
Searching...
No Matches
onert::compiler::StaticShapeInferer Class Reference

Class to infer shape before running kernels. It does the following: More...

#include <StaticShapeInferer.h>

Collaboration diagram for onert::compiler::StaticShapeInferer:

Public Member Functions

 StaticShapeInferer (compiler::ILoweredGraph *lowered_subg)
 
virtual ~StaticShapeInferer ()=default
 
void appendSubgInputObserver (const ir::SubgraphIndex &subg_idx, std::unique_ptr< OperandObserver > &&subg_input_observer) noexcept
 
void setControlflowOutputObserver (std::unique_ptr< OperandObserver > &&output_observer) noexcept
 
void appendChildInferer (const ir::SubgraphIndex &subg_idx, compiler::StaticShapeInferer *inferer)
 
void infer (void)
 Infer shape of operands belonging to ops and set the output shape. If output shape cannot be known without running op, mark it so that it can be allocated when running kernel.
 
void dump ()
 
- Public Member Functions inherited from onert::ir::OperationVisitor
virtual ~OperationVisitor ()=default
 

Static Public Member Functions

static std::unordered_map< ir::SubgraphIndex, std::unique_ptr< StaticShapeInferer > > createStaticShapeInferers (const std::unordered_map< ir::SubgraphIndex, ILoweredGraph * > &lowered_subgs)
 Create a shape inferer map for a lowered model.
 

Detailed Description

Class to infer shape before running kernels. It does the following:

  • re-calculate and set output shape at compile time (before running kernels)
  • if calculation cannot be done at compile time, mark the outputs to be dynamic, meaning shapes of outputs will be calculated during running kernels

Definition at line 68 of file StaticShapeInferer.h.

Constructor & Destructor Documentation

◆ StaticShapeInferer()

onert::compiler::StaticShapeInferer::StaticShapeInferer ( compiler::ILoweredGraph lowered_subg)
inline

Definition at line 71 of file StaticShapeInferer.h.

72 : _lowered_subg{lowered_subg}, _subg_input_observers{}, _controlflow_output_observer{nullptr},
73 _child_inferers{}
74 {
75 }

◆ ~StaticShapeInferer()

virtual onert::compiler::StaticShapeInferer::~StaticShapeInferer ( )
virtualdefault

Member Function Documentation

◆ appendChildInferer()

void onert::compiler::StaticShapeInferer::appendChildInferer ( const ir::SubgraphIndex subg_idx,
compiler::StaticShapeInferer inferer 
)
inline

Definition at line 90 of file StaticShapeInferer.h.

91 {
92 _child_inferers[subg_idx] = inferer;
93 }

Referenced by createStaticShapeInferers().

◆ appendSubgInputObserver()

void onert::compiler::StaticShapeInferer::appendSubgInputObserver ( const ir::SubgraphIndex subg_idx,
std::unique_ptr< OperandObserver > &&  subg_input_observer 
)
inlinenoexcept

Definition at line 79 of file StaticShapeInferer.h.

81 {
82 _subg_input_observers[subg_idx] = std::move(subg_input_observer);
83 }

◆ createStaticShapeInferers()

std::unordered_map< ir::SubgraphIndex, std::unique_ptr< StaticShapeInferer > > onert::compiler::StaticShapeInferer::createStaticShapeInferers ( const std::unordered_map< ir::SubgraphIndex, ILoweredGraph * > &  lowered_subgs)
static

Create a shape inferer map for a lowered model.

Parameters
[in]lowered_subgslowered model map
Returns
Shape inferer map

Definition at line 194 of file StaticShapeInferer.cc.

196{
197 // Allocate StaticShapeInferer per each subgraph
198 std::unordered_map<ir::SubgraphIndex, std::unique_ptr<StaticShapeInferer>> inferers;
199 for (auto &&[subg_index, lowered_subg] : lowered_subgs)
200 {
201 inferers[subg_index] = std::make_unique<StaticShapeInferer>(lowered_subg);
202 }
203
204 // Append observers in all StaticShapeInferers
205 for (auto &&pair : lowered_subgs)
206 {
207 const auto &subg_index = pair.first;
208 auto &lowered_subg = pair.second;
209
210 // TODO: Change this iteration for all to controlflow iteration
211 lowered_subg->graph().operations().iterate(
212 [&](const ir::OperationIndex &, const ir::IOperation &op) {
213 // A Function to append child inferers. These make it possible for a StaticShapeInferer to
214 // call StaticShapeInferes of child subgraphs recursively
215 auto appendChildInferer = [&](const ir::SubgraphIndex &child_subg_idx) {
216 auto *child_inferer = inferers.at(child_subg_idx).get();
217 inferers.at(subg_index)->appendChildInferer(child_subg_idx, child_inferer);
218 };
219
220 // A Function to appaend subg input observers. This makes it possible for a
221 // StaticShapeInferer to update inputs of child subgraphs
222 auto appendSubgraphInputObserver = [&](const ir::SubgraphIndex &child_subg_idx) {
223 std::vector<ir::Operand *> child_subg_inputs;
224 auto &child_subg = lowered_subgs.at(child_subg_idx)->graph();
225 for (const auto &input_idx : child_subg.getInputs())
226 {
227 auto operand_ptr = child_subg.operands().getRawPtr(input_idx);
228 child_subg_inputs.emplace_back(operand_ptr);
229 }
230 inferers.at(subg_index)
231 ->appendSubgInputObserver(child_subg_idx,
232 std::make_unique<OperandObserver>(child_subg_inputs));
233 };
234
235 // A Function to set controlflow output observers. This makes it possible for a
236 // StaticShapeInferer to update outputs of parent controlflow opeerations
237 auto setControlFlowOutputObserver = [&](const ir::SubgraphIndex &child_subg_idx) {
238 std::vector<ir::Operand *> cf_outputs;
239 auto &subg = lowered_subg->graph();
240 for (const auto &output_idx : op.getOutputs())
241 {
242 auto operand_ptr = subg.operands().getRawPtr(output_idx);
243 cf_outputs.emplace_back(operand_ptr);
244 }
245 inferers.at(child_subg_idx)
246 ->setControlflowOutputObserver(std::make_unique<OperandObserver>(cf_outputs));
247 };
248
249 // Append Observers in a StaticShapeInferer
250 if (op.opcode() == ir::OpCode::If)
251 {
252 // TODO Remove dynamic_cast
253 // An virtual base class cannot be downcasted by static_cast
254 try
255 {
256 const auto &if_op = dynamic_cast<const ir::operation::If &>(op);
257
258 appendChildInferer(if_op.param().then_subg_index);
259 appendChildInferer(if_op.param().else_subg_index);
260
261 appendSubgraphInputObserver(if_op.param().then_subg_index);
262 appendSubgraphInputObserver(if_op.param().else_subg_index);
263
264 setControlFlowOutputObserver(if_op.param().then_subg_index);
265 }
266 catch (const std::bad_cast &)
267 {
268 throw std::runtime_error("StaticShapeInferer: Invalid If operation");
269 }
270 }
271 else if (op.opcode() == ir::OpCode::While)
272 {
273 // TODO Remove dynamic_cast
274 try
275 {
276 const auto &while_op = dynamic_cast<const ir::operation::While &>(op);
277
278 appendChildInferer(while_op.param().cond_subg_index);
279 appendChildInferer(while_op.param().body_subg_index);
280
281 appendSubgraphInputObserver(while_op.param().cond_subg_index);
282 appendSubgraphInputObserver(while_op.param().body_subg_index);
283
284 setControlFlowOutputObserver(while_op.param().body_subg_index);
285 }
286 catch (const std::bad_cast &)
287 {
288 throw std::runtime_error("StaticShapeInferer: Invalid While operation");
289 }
290 }
291 });
292 }
293
294 return inferers;
295}
void appendChildInferer(const ir::SubgraphIndex &subg_idx, compiler::StaticShapeInferer *inferer)
::onert::util::Index< uint32_t, OperationIndexTag > OperationIndex
Definition Index.h:32
::onert::util::Index< uint16_t, SubgraphIndexTag > SubgraphIndex
Definition Index.h:41

References appendChildInferer(), onert::ir::IOperation::getOutputs(), and onert::ir::IOperation::opcode().

◆ dump()

void onert::compiler::StaticShapeInferer::dump ( )

Definition at line 169 of file StaticShapeInferer.cc.

170{
171 auto get_shape_str = [](const ir::Shape &shape) {
172 std::stringstream sstream;
173 sstream << "shape : {";
174 for (int i = 0; i < shape.rank(); i++)
175 {
176 if (i == 0)
177 sstream << shape.dim(i);
178 else
179 sstream << " " << shape.dim(i);
180 }
181 sstream << "}";
182 return sstream.str();
183 };
184
185 _lowered_subg->graph().operands().iterate(
186 [&](const ir::OperandIndex &ind, const ir::Operand &operand) {
187 VERBOSE(StaticShapeInferer) << " " << ind << ", "
188 << (operand.info().isDynamic() ? "Dynamic" : "Static") << ", "
189 << get_shape_str(operand.info().shape()) << std::endl;
190 });
191}
const Operands & operands() const override
Definition Graph.h:112
void iterate(const std::function< void(const Index &, const Object &)> &fn) const
Iterate over the container with given function.
#define VERBOSE(name, lv)
Definition Log.h:71
::onert::util::Index< uint32_t, OperandIndexTag > OperandIndex
Definition Index.h:35
virtual ir::Graph & graph()=0

References onert::compiler::ILoweredGraph::graph(), onert::ir::Operand::info(), onert::ir::OperandInfo::isDynamic(), onert::util::ObjectManager< Index, Object >::iterate(), onert::ir::Graph::operands(), onert::ir::OperandInfo::shape(), and VERBOSE.

◆ infer()

void onert::compiler::StaticShapeInferer::infer ( void  )

Infer shape of operands belonging to ops and set the output shape. If output shape cannot be known without running op, mark it so that it can be allocated when running kernel.

Definition at line 58 of file StaticShapeInferer.cc.

59{
60 for (const auto &op_idx : _lowered_subg->graph().topolSortOperations())
61 {
62 const auto &op = _lowered_subg->graph().operations().at(op_idx);
63 bool has_dynamic_tensor = false;
64 const auto opcode = op.opcode();
65 // IF: requires shape inference for then, else
66 // While: requires shape inference for condition, body
67 if (opcode == ir::OpCode::If || opcode == ir::OpCode::While)
68 {
69 op.accept(*this);
70 }
71 else
72 {
73 has_dynamic_tensor = checkDynamicInput(op);
74 if (has_dynamic_tensor)
75 {
76 setDynamicOutput(op);
77 }
78 else
79 {
80 op.accept(*this);
81 }
82 }
83 has_dynamic_tensor = has_dynamic_tensor || checkDynamicOutput(op);
84 _lowered_subg->setHasDynamicTensor(op_idx, has_dynamic_tensor);
85 }
86
87 if (_controlflow_output_observer != nullptr)
88 {
89 // re-sizing output shapes of the controflow operation branching to this subgraph
90 std::vector<ir::OperandInfo> outputs_info;
91 const auto &graph = _lowered_subg->graph();
92 const auto &outputs = graph.getOutputs();
93 for (size_t i = 0; i < outputs.size(); ++i)
94 {
95 const auto &operand_info = graph.operands().at(outputs.at(i)).info();
96 outputs_info.emplace_back(operand_info);
97 }
98 _controlflow_output_observer->updateShapes(outputs_info);
99 }
100}
const Operations & operations() const override
Definition Graph.h:114
const Object & at(const Index &index) const
Get the object that is associated with the given index.
virtual void setHasDynamicTensor(ir::OperationIndex ind, bool val)=0

References onert::util::ObjectManager< Index, Object >::at(), onert::compiler::ILoweredGraph::graph(), onert::ir::Graph::operations(), onert::compiler::ILoweredGraph::setHasDynamicTensor(), and onert::ir::Graph::topolSortOperations().

◆ setControlflowOutputObserver()

void onert::compiler::StaticShapeInferer::setControlflowOutputObserver ( std::unique_ptr< OperandObserver > &&  output_observer)
inlinenoexcept

Definition at line 85 of file StaticShapeInferer.h.

86 {
87 _controlflow_output_observer = std::move(output_observer);
88 }

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