ONE - On-device Neural Engine
Loading...
Searching...
No Matches
CircleExporterImpl.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include "CircleExporterImpl.h"
18
19#include "Convert.h"
20#include "ExoOptimize.h"
21
24#include "CircleExporterUtils.h"
25
26#include "Log.h"
27#include "Knob.h"
28
29#include <oops/InternalExn.h>
30
31#include <cassert>
32#include <unordered_map>
33#include <string>
34#include <stdexcept>
35
36namespace
37{
38
39using namespace exo::circle_detail;
40
41void registerGraphInputTensors(loco::Graph *graph, SubGraphContext &ctx)
42{
43 for (uint32_t n = 0; n < graph->inputs()->size(); ++n)
44 {
45 auto node = loco::pull_node(graph, n);
46 assert(node != nullptr);
47 ctx._inputs.push_back(get_tensor_index(node));
48 }
49}
50
51void registerGraphOutputTensors(loco::Graph *graph, SubGraphContext &ctx)
52{
53 for (uint32_t n = 0; n < graph->outputs()->size(); ++n)
54 {
55 auto push = loco::push_node(graph, n);
56 assert(push != nullptr);
57 auto node = push->from();
58 assert(node != nullptr);
59 ctx._outputs.push_back(get_tensor_index(node));
60 }
61}
62
63} // namespace
64
65namespace
66{
67
68using namespace circle;
69using namespace flatbuffers;
70
72encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map<OpCode, uint32_t> &opcodes,
73 std::unordered_map<OpCode, std::string> &custom_opcodes)
74{
75 std::vector<Offset<OperatorCode>> operator_codes_vec(opcodes.size());
76 for (auto it : opcodes)
77 {
78 uint32_t idx = it.second;
79 if (it.first.opcode != BuiltinOperator_CUSTOM)
80 {
81 operator_codes_vec[idx] = CreateOperatorCode(builder, it.first.opcode);
82 }
83 else // custom op
84 {
85 auto opCode = it.first;
86 auto custom_code = custom_opcodes.find(opCode);
87 if (custom_code == custom_opcodes.end())
88 INTERNAL_EXN("Cannot find code for customop even though opcode is BuiltinOperator_CUSTOM");
89
90 operator_codes_vec[idx] =
91 CreateOperatorCode(builder, it.first.opcode, builder.CreateString(custom_code->second));
92 }
93 }
94 return builder.CreateVector(operator_codes_vec);
95}
96
97} // namespace
98
99namespace exo
100{
101
102using namespace exo::circle_detail;
103using namespace circle;
104using namespace flatbuffers;
105
106CircleExporter::Impl::Impl(loco::Graph *graph) { exportGraph(graph); }
107
109CircleExporter::Impl::exportSubgraph(SerializedModelData &gd)
110{
111 auto tensors = _builder.CreateVector(gd._tensors);
112 auto inputs = _builder.CreateVector(gd._inputs);
113 auto outputs = _builder.CreateVector(gd._outputs);
114 auto operators = _builder.CreateVector(gd._operators);
115 auto df = gd._data_format;
116 auto subgraph = CreateSubGraph(_builder, tensors, inputs, outputs, operators, df);
117 return subgraph;
118}
119
120void CircleExporter::Impl::exportGraph(loco::Graph *graph)
121{
122 LOGGER(l);
123
124 // IR-level conversion and optimization
125 {
126 convert_to_TFLNodes(graph);
128 optimize(graph);
129 }
130
131 _builder.Clear();
132
134
135 // This version is taken from comment in fbs
136 constexpr uint32_t version = 0;
137
138 registerGraphIOName(graph, gd);
139
140 // parse graph into SerializedModelData structure
141 exportOpDefinedTensors(graph, _builder, gd);
142
143 // NOTE Invoke these register functions only after each node is annotated with its tensor_index
144 registerGraphInputTensors(graph, gd);
145 registerGraphOutputTensors(graph, gd);
146
147 exportNodes(graph, _builder, gd);
148
149 // encode operator codes
150 auto operator_codes =
151 encodeOperatorCodes(_builder, gd._operator_codes, gd._custom_operator_codes);
152
153 // Subgraphs
154 Offset<SubGraph> subgraph = exportSubgraph(gd);
155 auto subgraphs = _builder.CreateVector(std::vector<Offset<SubGraph>>{subgraph});
156
157 // Description
158 std::string description_str = "nnpackage";
159 auto description = _builder.CreateString(description_str);
160
161 // create array of buffers
162 auto buffers = _builder.CreateVector(gd._buffers);
163
164 // empty metadata
165 std::vector<int> metadata_buffer_vec;
166 auto metadata_buffer = _builder.CreateVector(metadata_buffer_vec);
167
168 // Model
169 auto model_offset = CreateModel(_builder, version, operator_codes, subgraphs, description,
170 buffers, metadata_buffer);
171 FinishModelBuffer(_builder, model_offset);
172}
173
175{
176 return reinterpret_cast<const char *>(_builder.GetBufferPointer());
177}
178
179size_t CircleExporter::Impl::getBufferSize() const { return _builder.GetSize(); }
180
181} // namespace exo
#define INTERNAL_EXN(msg)
@ brief throw internal exception with message
Definition InternalExn.h:25
#define LOGGER(name)
Definition Log.h:65
const char * getBufferPointer() const
Helper class to hold data needed in creation of a FlatBuffer. To serialize data, you typically call o...
Offset< String > CreateString(const char *str, size_t len)
Store a string in the buffer, which can contain any binary data.
Offset< Vector< T > > CreateVector(const T *v, size_t len)
Serialize an array into a FlatBuffer vector.
A neural network graph.
Definition Graph.h:161
void exportOpDefinedTensors(loco::Graph *g, FlatBufferBuilder &builder, SerializedModelData &gd)
create Tensors corresponding to results of all nodes in graph
void registerGraphIOName(loco::Graph *graph, SerializedModelData &gd)
Register graph input and output names to SerializedModelData.
TFLTensorIndex get_tensor_index(loco::Node *node)
void convert_to_TFLNodes(loco::Graph *graph)
Definition Convert.cpp:40
void set(Dialect d)
Definition Knob.cpp:100
void optimize(loco::Graph *g)
Run passes for a graph after completion of converting canonical nodes into TFL nodes.
Pull * pull_node(Graph *g, const GraphInputIndex &index)
Find a Pull node with a given input index.
Definition Nodes.cpp:162
Push * push_node(Graph *g, const GraphOutputIndex &index)
Find a Push node with a given output index.
Definition Nodes.cpp:67
int32_t size[5]
Definition Slice.cpp:35
std::unordered_map< OpCode, std::string > _custom_operator_codes
std::vector< flatbuffers::Offset< circle::Tensor > > _tensors
std::vector< flatbuffers::Offset< circle::Operator > > _operators
std::vector< flatbuffers::Offset< circle::Buffer > > _buffers
std::unordered_map< OpCode, uint32_t > _operator_codes
Record the information of T/F Lite SubGraph and its mapping to loco.
std::vector< int32_t > _outputs
SubGraph output tensor id.
circle::DataFormat _data_format
@DataFormat for SubGraph
std::vector< int32_t > _inputs
SubGraph input tensor id.