899c800b8e321a204bede36bdcd82a4f45b2b4cc
[platform/core/ml/nnfw.git] / tests / nnfw_api / src / CircleGen.h
1 /*
2  * Copyright (c) 2020 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 #ifndef __NNFW_API_TEST_CIRCLE_GEN_H__
18 #define __NNFW_API_TEST_CIRCLE_GEN_H__
19
20 #include <circle_schema_generated.h>
21
22 #include <vector>
23
24 /**
25  * @brief Class for storing flatbuffer buffer
26  *
27  * This is a simple wrapper for a finished FlatBufferBuilder. It owns the buffer and a user can
28  * get the buffer pointer and size.
29  */
30 class CircleBuffer
31 {
32 public:
33   CircleBuffer() = default;
34   explicit CircleBuffer(flatbuffers::FlatBufferBuilder &&fbb) : _fbb{std::move(fbb)}
35   {
36     _fbb.Finished(); // The build must have been finished, so check that here
37   }
38
39   uint8_t *buffer() { return _fbb.GetBufferPointer(); }
40   size_t size() { return _fbb.GetSize(); }
41
42 private:
43   flatbuffers::FlatBufferBuilder _fbb;
44 };
45
46 /**
47  * @brief Circle flatbuffer file generator
48  *
49  * This is a helper class for generating circle file.
50  *
51  */
52 class CircleGen
53 {
54 public:
55   struct TensorParams
56   {
57     std::vector<int32_t> shape;
58     circle::TensorType tensor_type = circle::TensorType::TensorType_FLOAT32;
59     uint32_t buffer = 0;
60     std::string name;
61   };
62
63   struct OperatorParams
64   {
65     std::vector<int32_t> inputs;
66     std::vector<int32_t> outputs;
67     int version = 1;
68   };
69
70 public:
71   CircleGen()
72   {
73     // 0th buffer is always the empty buffer for non-const tensors
74     addBuffer(nullptr, 0);
75   }
76
77   template <typename T> uint32_t addBuffer(const std::vector<T> &buf_vec)
78   {
79     auto buf = reinterpret_cast<const uint8_t *>(buf_vec.data());
80     auto size = buf_vec.size() * sizeof(T);
81     return addBuffer(buf, size);
82   }
83
84   uint32_t addBuffer(const uint8_t *buf, size_t size)
85   {
86     uint32_t ind = _buffers.size();
87     _buffers.emplace_back(buildBuffer(buf, size));
88     return ind;
89   }
90
91   uint32_t addTensor(const TensorParams &params)
92   {
93     int ind = _tensors.size();
94     _tensors.emplace_back(buildTensor(params));
95     return ind;
96   }
97
98   uint32_t setInputsAndOutputs(const std::vector<int> &inputs, const std::vector<int> &outputs)
99   {
100     _inputs = inputs;
101     _outputs = outputs;
102   }
103
104   CircleBuffer finish()
105   {
106     // TODO Support multiple subgraphs, for now only single subgraph model is supported.
107     std::vector<flatbuffers::Offset<circle::SubGraph>> subgraphs{buildSubGraph()};
108     auto model =
109         circle::CreateModelDirect(_fbb, 3, &_opcodes, &subgraphs, "CircleGen generated", &_buffers);
110     _fbb.Finish(model);
111     return CircleBuffer{std::move(_fbb)};
112   }
113
114   // ===== Add Operator methods begin =====
115
116   uint32_t addOperatorAdd(const OperatorParams &params, circle::ActivationFunctionType actfn)
117   {
118     auto options = circle::CreateAddOptions(_fbb, actfn).Union();
119     return addOperatorWithOptions(params, circle::BuiltinOperator_ADD,
120                                   circle::BuiltinOptions_AddOptions, options);
121   }
122
123   uint32_t addOperatorAveragePool2D(const OperatorParams &params, circle::Padding padding,
124                                     int stride_w, int stride_h, int filter_w, int filter_h,
125                                     circle::ActivationFunctionType actfn)
126   {
127     auto options =
128         circle::CreatePool2DOptions(_fbb, padding, stride_w, stride_h, filter_w, filter_h, actfn)
129             .Union();
130     return addOperatorWithOptions(params, circle::BuiltinOperator_AVERAGE_POOL_2D,
131                                   circle::BuiltinOptions_Pool2DOptions, options);
132   }
133
134   // NOTE Please add addOperator functions ABOVE this lie
135   //
136   // %  How to add a new addOperatorXXX fuction
137   // 0. Copy code from one of the existing addOperatorXXX function
138   // 1. Change the function signature (need BuiltinOperator params)
139   // 2. Change enum BuiltinOperator
140   // 3. Change enum BuiltinOptions
141   // 4. Change CreateXXXOptions accordingly
142
143   // ===== Add Operator methods end =====
144
145 private:
146   uint32_t addOperatorWithOptions(const OperatorParams &params, circle::BuiltinOperator opcode,
147                                   circle::BuiltinOptions options_type,
148                                   flatbuffers::Offset<void> options)
149   {
150     uint32_t opcode_ind = addOperatorCode(opcode);
151     auto op = circle::CreateOperatorDirect(_fbb, opcode_ind, &params.inputs, &params.outputs,
152                                            options_type, options);
153
154     uint32_t ind = _operators.size();
155     _operators.emplace_back(op);
156     return ind;
157   }
158
159   uint32_t addOperatorCode(circle::BuiltinOperator opcode)
160   {
161     // TODO If the same OperatorCode is registered already, just return it
162     uint32_t ind = _opcodes.size();
163     _opcodes.emplace_back(circle::CreateOperatorCode(_fbb, opcode));
164     return ind;
165   }
166
167   flatbuffers::Offset<circle::Buffer> buildBuffer(const uint8_t *buf, size_t size)
168   {
169     if (buf == nullptr && size == 0)
170       return circle::CreateBuffer(_fbb);
171     auto buffer = _fbb.CreateVector(buf, size);
172     return circle::CreateBuffer(_fbb, buffer);
173   }
174
175   flatbuffers::Offset<circle::Tensor> buildTensor(const TensorParams &params)
176   {
177     auto shape = _fbb.CreateVector(params.shape);
178     auto name = _fbb.CreateString(params.name);
179     return circle::CreateTensor(_fbb, shape, params.tensor_type, params.buffer, name,
180                                 0 /* QuantParam */, false /* is_variable */, 0 /* sparsity */,
181                                 0 /* shape_signature */);
182   }
183
184   flatbuffers::Offset<circle::SubGraph> buildSubGraph()
185   {
186     return circle::CreateSubGraphDirect(_fbb, &_tensors, &_inputs, &_outputs, &_operators, nullptr);
187   }
188
189 private:
190   flatbuffers::FlatBufferBuilder _fbb{1024};
191   std::vector<flatbuffers::Offset<circle::Buffer>> _buffers;
192   std::vector<flatbuffers::Offset<circle::OperatorCode>> _opcodes;
193
194   // per-subgraph
195   std::vector<int> _inputs;
196   std::vector<int> _outputs;
197   std::vector<flatbuffers::Offset<circle::Tensor>> _tensors;
198   std::vector<flatbuffers::Offset<circle::Operator>> _operators;
199 };
200
201 #endif // __NNFW_API_TEST_CIRCLE_GEN_H__