Imported Upstream version 1.8.0
[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, CircleLoader>
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         return true;
89       default:
90         return false;
91     }
92   }
93
94   std::unique_ptr<ir::Graph> loadSubgraph(const circle::SubGraph *circle_subg)
95   {
96     auto subg = std::make_unique<ir::Graph>();
97     // Load tensors
98     _tensor_to_operand.resize(circle_subg->tensors()->size());
99     for (flatbuffers::uoffset_t i = 0; i < circle_subg->tensors()->size(); ++i)
100     {
101       _tensor_to_operand[i] = loadOperand(circle_subg->tensors()->Get(i), *subg);
102     }
103     // Set inputs
104     for (const std::int32_t input_ind : *circle_subg->inputs())
105     {
106       subg->addInput(tensorIdxToOperandIdx(input_ind));
107     }
108     // Set outputs
109     for (const std::int32_t output_ind : *circle_subg->outputs())
110     {
111       subg->addOutput(tensorIdxToOperandIdx(output_ind));
112     }
113     // Create operations
114     for (const auto *op : *circle_subg->operators())
115     {
116       CircleLoader::loadOperation(op, *subg);
117     }
118
119     subg->setLayout(convertDataFormat(circle_subg->data_format()));
120
121     subg->finishBuilding();
122
123     return subg;
124   }
125
126   void loadOperation(const circle::Operator *op, ir::Graph &subg)
127   {
128     const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
129
130     switch (builtin_op)
131     {
132       case circle::BuiltinOperator::BuiltinOperator_INSTANCE_NORM:
133         loadInstanceNorm(op, subg);
134         return;
135       case circle::BuiltinOperator::BuiltinOperator_BCQ_FULLY_CONNECTED:
136         loadBCQFullyConnected(op, subg);
137         return;
138       case circle::BuiltinOperator::BuiltinOperator_BCQ_GATHER:
139         loadBCQGather(op, subg);
140         return;
141       default:
142         BaseLoader::loadOperation(op, subg);
143         return;
144     }
145   }
146 };
147
148 void CircleLoader::loadInstanceNorm(const Operator *op, ir::Graph &subg)
149 {
150   ir::OperandIndexSequence inputs;
151   ir::OperandIndexSequence outputs;
152
153   loadOperationIO(op, inputs, outputs);
154
155   ir::operation::InstanceNorm::Param param;
156   const auto *options = op->builtin_options_as_InstanceNormOptions();
157
158   param.activation = convertActivation(options->fused_activation_function());
159   // Use default value 1e-5 if value of epsilon is zero
160   param.epsilon = options->epsilon() == 0.f ? 1e-5 : options->epsilon();
161
162   std::unique_ptr<ir::Operation> new_op(new ir::operation::InstanceNorm(inputs, outputs, param));
163   subg.addOperation(std::move(new_op));
164 }
165
166 void CircleLoader::loadBCQGather(const Operator *op, ir::Graph &subg)
167 {
168   ir::OperandIndexSequence inputs;
169   ir::OperandIndexSequence outputs;
170
171   loadOperationIO(op, inputs, outputs);
172
173   ir::operation::BCQGather::Param param;
174   const auto *options = op->builtin_options_as_BCQGatherOptions();
175   param.input_hidden_size = options->input_hidden_size();
176   param.axis = options->axis();
177
178   std::unique_ptr<ir::Operation> new_op(new ir::operation::BCQGather(inputs, outputs, param));
179   subg.addOperation(std::move(new_op));
180 }
181
182 void CircleLoader::loadBCQFullyConnected(const Operator *op, ir::Graph &subg)
183 {
184   ir::OperandIndexSequence inputs;
185   ir::OperandIndexSequence outputs;
186
187   loadOperationIO(op, inputs, outputs);
188
189   ir::operation::BCQFullyConnected::Param param;
190   const auto *options = op->builtin_options_as_BCQFullyConnectedOptions();
191   param.weights_hidden_size = options->weights_hidden_size();
192   param.activation = convertActivation(options->fused_activation_function());
193
194   std::unique_ptr<ir::Operation> new_op(
195       new ir::operation::BCQFullyConnected(inputs, outputs, param));
196   subg.addOperation(std::move(new_op));
197 }
198
199 } // namespace
200
201 std::unique_ptr<ir::Subgraphs> loadModel(const char *filename)
202 {
203   auto subgraphs = std::make_unique<ir::Subgraphs>();
204   CircleLoader loader(subgraphs);
205   loader.loadFromFile(filename);
206   return subgraphs;
207 }
208
209 std::unique_ptr<ir::Subgraphs> loadModel(uint8_t *buffer, size_t size)
210 {
211   auto subgraphs = std::make_unique<ir::Subgraphs>();
212   CircleLoader loader(subgraphs);
213   loader.loadFromBuffer(buffer, size);
214   return subgraphs;
215 }
216
217 } // namespace circle_loader
218 } // namespace onert