2 * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #ifndef __ONERT_IR_NNPKG_H__
18 #define __ONERT_IR_NNPKG_H__
21 #include <unordered_set>
33 using IODesc = std::tuple<ModelIndex, SubgraphIndex, IOIndex>;
43 bool operator()(const onert::ir::ModelEdge &lhs, const onert::ir::ModelEdge &rhs) const
45 return lhs.from == rhs.from && lhs.to == rhs.to;
51 size_t operator()(const ::onert::ir::ModelEdge &edge) const noexcept
53 unsigned long long h1 = (std::get<0>(edge.from).value() << 24) |
54 (std::get<1>(edge.from).value() << 16) | std::get<2>(edge.from).value();
55 unsigned long long h2 = (std::get<0>(edge.to).value() << 24) |
56 (std::get<1>(edge.to).value() << 16) | std::get<2>(edge.to).value();
61 inline std::ostream &operator<<(std::ostream &o, const IODesc &od)
63 o << std::get<0>(od).value() << ":" << std::get<1>(od).value() << ":" << std::get<2>(od).value();
67 using ModelEdgeSet = std::unordered_set<ir::ModelEdge, ir::ModelEdgeHash, ir::ModelEdgeEqual>;
70 * @brief Struct to gather model I/O information in multimodel NN package
71 * Model I/O will have role one of below
72 * - Package input/output
73 * - Edge's start/finish point between model
77 std::vector<ir::IODesc> pkg_inputs;
78 std::vector<ir::IODesc> pkg_outputs;
86 NNPkg(const NNPkg &obj) = default;
87 NNPkg(NNPkg &&) = default;
88 NNPkg &operator=(const NNPkg &) = default;
89 NNPkg &operator=(NNPkg &&) = default;
92 NNPkg(std::shared_ptr<Model> model) { _models[ModelIndex{0}] = model; }
93 std::shared_ptr<Model> primary_model() const { return _models.at(onert::ir::ModelIndex{0}); }
96 * @brief Put model at index
98 * @param[in] model Model to be pushed
99 * @param[in] index Index where Model is to be pushed
101 void push(ModelIndex index, const std::shared_ptr<Model> &model) { _models[index] = model; }
104 * @brief Get the count of model
106 * @return the count of models
108 size_t model_count() const { return _models.size(); }
111 * @brief Get model at index
113 * @param[in] index Index of the model to be returned
114 * @return Model at index
116 const std::shared_ptr<Model> &model(const ModelIndex &index) const { return _models.at(index); }
118 * @brief Get model at index
120 * @param[in] index Index of the model to be returned
121 * @return Model at index
123 std::shared_ptr<Model> &model(const ModelIndex &index) { return _models.at(index); }
126 * @brief Get pkg_input at index
128 * @param[in] index Index of pkg_input to be returned
129 * @return IODesc at index
131 const IODesc &input(uint32_t index) const { return _edges.pkg_inputs[index]; }
133 * @brief Get pkg_input at index
135 * @param[in] index Index of pkg_input to be returned
136 * @return IODesc at index
138 IODesc &input(uint32_t index) { return _edges.pkg_inputs[index]; }
140 * @brief Add input at the end
142 * @param[in] input Input IODesc to be pushed
144 void addInput(const IODesc &input) { _edges.pkg_inputs.push_back(input); }
147 * @brief Get pkg_output at index
149 * @param[in] index Index of pkg_output to be returned
150 * @return IODesc at index
152 const IODesc &output(uint32_t index) const { return _edges.pkg_outputs[index]; }
154 * @brief Get pkg_output at index
156 * @param[in] index Index of pkg_output to be returned
157 * @return IODesc at index
159 IODesc &output(uint32_t index) { return _edges.pkg_outputs[index]; }
161 * @brief Add output at the end
163 * @param[in] output Output IODesc to be pushed
165 void addOutput(const IODesc &output) { _edges.pkg_outputs.push_back(output); }
168 * @brief Add edge between models at the end
170 * @param[in] from from IODesc
171 * @param[in] to to IODesc
173 void addEdge(const IODesc &from, const IODesc &to)
175 std::cout << from << " -> " << to << std::endl;
176 _edges.edges.insert(ModelEdge{from, to});
179 * @brief Get model edge set
180 * @return Edge set reference
182 const ModelEdges &model_edges() { return _edges; }
185 * @brief Verify NNPkg
190 // Verify edges information
192 // Only duplicates of nnpkg output and Edge `from` are possible.
193 // | Whether duplicates are possible | Edge `to` | Edge `from` |
194 // | nnpkg input (input of subgraph) | X (*1) | X (*2) |
195 // | nnpkg output (output of subgraph) | X (*2) | O |
196 // *1. The subjects who determine values of each buffer are different.
197 // - nnpkg input : user input
198 // - Edge `to` : output of another subgraph
199 // *2. `IOIndex` of inputs and outputs of subgraph is distinct.
201 for (const auto &edge : _edges.edges)
203 if (std::find(_edges.pkg_inputs.begin(), _edges.pkg_inputs.end(), edge.to) !=
204 _edges.pkg_inputs.end())
206 throw std::runtime_error{
207 "Invalid edge information. NNPkg inputs and Edge `to` cannot be duplicated"};
212 // TODO Find better way to handle single model NNPackage and multi model NNPackage on inputSize(),
213 // outputSize(), inputInfo(), outputInfo()
216 * @brief Get model input size
218 uint32_t inputSize() const
220 return _models.size() == 1 ? primary_model()->primary_subgraph()->getInputs().size()
221 : _edges.pkg_inputs.size();
225 * @brief Get model output size
227 uint32_t outputSize() const
229 return _models.size() == 1 ? primary_model()->primary_subgraph()->getOutputs().size()
230 : _edges.pkg_outputs.size();
234 * @brief Get model input info
236 OperandInfo &inputInfo(uint32_t index) const
238 if (_models.size() == 1)
240 auto const graph = primary_model()->primary_subgraph();
241 auto const operand_index = graph->getInputs().at(index);
242 return graph->operands().at(operand_index).info();
245 auto const &desc = input(index);
246 auto const graph = model(std::get<ModelIndex>(desc))->primary_subgraph();
247 auto const operand_index = graph->getInputs().at(std::get<IOIndex>(desc).value());
248 return graph->operands().at(operand_index).info();
252 * @brief Get model output info
254 OperandInfo &outputInfo(uint32_t index) const
256 if (_models.size() == 1)
258 auto const graph = primary_model()->primary_subgraph();
259 auto const operand_index = graph->getOutputs().at(index);
260 return graph->operands().at(operand_index).info();
263 auto const &desc = output(index);
264 auto const graph = model(std::get<ModelIndex>(desc))->primary_subgraph();
265 auto const operand_index = graph->getOutputs().at(std::get<IOIndex>(desc).value());
266 return graph->operands().at(operand_index).info();
269 // TODO: Add iterate() or getter for edges
272 std::unordered_map<ModelIndex, std::shared_ptr<Model>> _models;
282 template <> struct hash<onert::ir::IODesc>
284 size_t operator()(const ::onert::ir::IODesc &iodesc) const noexcept
286 return (std::get<0>(iodesc).value() << 24) | (std::get<1>(iodesc).value() << 16) |
287 std::get<2>(iodesc).value();
293 #endif // __ONERT_IR_NNPKG_H__