33e1709a82ad7d9f82f458af9f273b0e444b9913
[platform/core/ml/nnfw.git] / runtime / onert / frontend / circle / src / circle_loader.cc
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 "circle_loader.h"
18 #include "base_loader.h"
19 #include "circle_schema_generated.h"
20
21 namespace onert
22 {
23 namespace circle_loader
24 {
25
26 namespace
27 {
28
29 ir::Layout convertDataFormat(circle::DataFormat data_format)
30 {
31   switch (data_format)
32   {
33     case circle::DataFormat::DataFormat_CHANNELS_FIRST:
34       return ir::Layout::NCHW;
35     case circle::DataFormat::DataFormat_CHANNELS_LAST:
36       return ir::Layout::NHWC;
37     default:
38       throw std::runtime_error("Unsupported DataFormat");
39   }
40 }
41
42 struct LoaderDomain
43 {
44   using Verifier = flatbuffers::Verifier;
45   using ActivationFunctionType = circle::ActivationFunctionType;
46   using Buffer = circle::Buffer;
47   using BuiltinOperator = circle::BuiltinOperator;
48   using CustomOptionsFormat = circle::CustomOptionsFormat;
49   using Model = circle::Model;
50   using Operator = circle::Operator;
51   using Padding = circle::Padding;
52   using Pool2DOptions = circle::Pool2DOptions;
53   using Tensor = circle::Tensor;
54   using TensorType = circle::TensorType;
55   using SubGraph = circle::SubGraph;
56   using DimensionType = circle::DimensionType;
57   using SparseIndexVector = circle::SparseIndexVector;
58
59   static const char *EnumNameBuiltinOperator(BuiltinOperator e)
60   {
61     return circle::EnumNameBuiltinOperator(e);
62   }
63   static const char *EnumNameActivationFunctionType(ActivationFunctionType e)
64   {
65     return circle::EnumNameActivationFunctionType(e);
66   }
67   static const char *EnumNameTensorType(TensorType e) { return circle::EnumNameTensorType(e); }
68   static const Model *GetModel(const void *buf) { return circle::GetModel(buf); }
69   static bool VerifyModelBuffer(Verifier &verifier) { return circle::VerifyModelBuffer(verifier); }
70 };
71
72 class CircleLoader final : public base_loader::BaseLoader<LoaderDomain>
73 {
74 protected:
75   void loadInstanceNorm(const Operator *op, ir::Graph &subg);
76   void loadBCQFullyConnected(const Operator *op, ir::Graph &subg);
77   void loadBCQGather(const Operator *op, ir::Graph &subg);
78
79 public:
80   using BaseLoader::BaseLoader;
81
82   bool allowOptionalInputTensor(BuiltinOperator op) override
83   {
84     switch (op)
85     {
86       case BuiltinOperator::BuiltinOperator_FULLY_CONNECTED:
87       case BuiltinOperator::BuiltinOperator_BCQ_FULLY_CONNECTED:
88       case BuiltinOperator::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM:
89         return true;
90       default:
91         return false;
92     }
93   }
94
95 private:
96   std::unique_ptr<ir::Graph> loadSubgraph(const circle::SubGraph *circle_subg) override
97   {
98     auto subg = std::make_unique<ir::Graph>();
99     // Load tensors
100     _tensor_to_operand.resize(circle_subg->tensors()->size());
101     for (flatbuffers::uoffset_t i = 0; i < circle_subg->tensors()->size(); ++i)
102     {
103       _tensor_to_operand[i] = loadOperand(circle_subg->tensors()->Get(i), *subg);
104     }
105     // Set inputs
106     for (const std::int32_t input_ind : *circle_subg->inputs())
107     {
108       subg->addInput(tensorIdxToOperandIdx(input_ind),
109                      _tensor_names.at(_tensor_to_operand[input_ind]));
110     }
111     // Set outputs
112     for (const std::int32_t output_ind : *circle_subg->outputs())
113     {
114       subg->addOutput(tensorIdxToOperandIdx(output_ind),
115                       _tensor_names.at(_tensor_to_operand[output_ind]));
116     }
117     // Create operations
118     for (const auto *op : *circle_subg->operators())
119     {
120       CircleLoader::loadOperation(op, *subg);
121     }
122
123     subg->setLayout(convertDataFormat(circle_subg->data_format()));
124
125     subg->finishBuilding();
126
127     return subg;
128   }
129
130   void loadOperation(const circle::Operator *op, ir::Graph &subg)
131   {
132     const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
133
134     switch (builtin_op)
135     {
136       case circle::BuiltinOperator::BuiltinOperator_INSTANCE_NORM:
137         loadInstanceNorm(op, subg);
138         return;
139       case circle::BuiltinOperator::BuiltinOperator_BCQ_FULLY_CONNECTED:
140         loadBCQFullyConnected(op, subg);
141         return;
142       case circle::BuiltinOperator::BuiltinOperator_BCQ_GATHER:
143         loadBCQGather(op, subg);
144         return;
145       default:
146         BaseLoader::loadOperation(op, subg);
147         return;
148     }
149   }
150 };
151
152 void CircleLoader::loadInstanceNorm(const Operator *op, ir::Graph &subg)
153 {
154   ir::OperandIndexSequence inputs;
155   ir::OperandIndexSequence outputs;
156
157   loadOperationIO(op, inputs, outputs);
158
159   ir::operation::InstanceNorm::Param param;
160   const auto *options = op->builtin_options_as_InstanceNormOptions();
161
162   param.activation = convertActivation(options->fused_activation_function());
163   // Use default value 1e-5 if value of epsilon is zero
164   param.epsilon = options->epsilon() == 0.f ? 1e-5 : options->epsilon();
165
166   std::unique_ptr<ir::Operation> new_op(new ir::operation::InstanceNorm(inputs, outputs, param));
167   subg.addOperation(std::move(new_op));
168 }
169
170 void CircleLoader::loadBCQGather(const Operator *op, ir::Graph &subg)
171 {
172   ir::OperandIndexSequence inputs;
173   ir::OperandIndexSequence outputs;
174
175   loadOperationIO(op, inputs, outputs);
176
177   ir::operation::BCQGather::Param param;
178   const auto *options = op->builtin_options_as_BCQGatherOptions();
179   param.input_hidden_size = options->input_hidden_size();
180   param.axis = options->axis();
181
182   std::unique_ptr<ir::Operation> new_op(new ir::operation::BCQGather(inputs, outputs, param));
183   subg.addOperation(std::move(new_op));
184 }
185
186 void CircleLoader::loadBCQFullyConnected(const Operator *op, ir::Graph &subg)
187 {
188   ir::OperandIndexSequence inputs;
189   ir::OperandIndexSequence outputs;
190
191   loadOperationIO(op, inputs, outputs);
192
193   ir::operation::BCQFullyConnected::Param param;
194   const auto *options = op->builtin_options_as_BCQFullyConnectedOptions();
195   param.weights_hidden_size = options->weights_hidden_size();
196   param.activation = convertActivation(options->fused_activation_function());
197
198   std::unique_ptr<ir::Operation> new_op(
199       new ir::operation::BCQFullyConnected(inputs, outputs, param));
200   subg.addOperation(std::move(new_op));
201 }
202
203 } // namespace
204
205 std::unique_ptr<ir::Subgraphs> loadModel(const char *filename)
206 {
207   auto subgraphs = std::make_unique<ir::Subgraphs>();
208   CircleLoader loader(subgraphs);
209   loader.loadFromFile(filename);
210   return subgraphs;
211 }
212
213 std::unique_ptr<ir::Subgraphs> loadModel(uint8_t *buffer, size_t size)
214 {
215   auto subgraphs = std::make_unique<ir::Subgraphs>();
216   CircleLoader loader(subgraphs);
217   loader.loadFromBuffer(buffer, size);
218   return subgraphs;
219 }
220
221 } // namespace circle_loader
222 } // namespace onert