1 /**
2 * Copyright 2021 Huawei Technologies Co., Ltd
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 "coder/generator/component/common_component.h"
18 #include <memory>
19 #include "coder/generator/component/const_blocks/license.h"
20 #include "coder/generator/component/component.h"
21 #include "coder/utils/type_cast.h"
22 #include "coder/utils/coder_utils.h"
23 #include "coder/log.h"
24 #include "include/errorcode.h"
25 #include "nnacl/op_base.h"
26
27 namespace mindspore::lite::micro {
CodeSessionCompileGraph(std::ofstream & ofs,const std::unique_ptr<CoderContext> & ctx,const Configurator * config)28 void CodeSessionCompileGraph(std::ofstream &ofs, const std::unique_ptr<CoderContext> &ctx, const Configurator *config) {
29 auto array_tostring = [&ofs](const std::vector<int> &array, const std::string &name) {
30 size_t num = array.size();
31 ofs << " Vector<int32_t> " << name << ";\n";
32 ofs << " " << name << ".resize(" << num << ");\n";
33 for (size_t i = 0; i < num; ++i) {
34 ofs << " " << name << "[" << i << "] = " << array[i] << ";\n";
35 }
36 };
37 std::vector<Tensor *> inputs = ctx->graph_inputs();
38 std::vector<Tensor *> outputs = ctx->graph_outputs();
39 size_t inputs_size = inputs.size();
40 size_t outputs_size = outputs.size();
41 ofs << kNameSpaceMindSpore << " {\n";
42 ofs << kNameSpaceLite << " {\n";
43 ofs << "int LiteSession::CompileGraph(lite::Model *model) {\n";
44 ofs << " inputs_.resize(" << inputs_size << ");\n";
45 for (size_t i = 0; i < inputs_size; ++i) {
46 Tensor *input = inputs[i];
47 std::string shape_i = "in_shape_" + std::to_string(i);
48 array_tostring(input->shape(), shape_i);
49 ofs << " inputs_[" << i << "] = new (std::nothrow) MTensor(String(\"" << input->tensor_name() << "\"), "
50 << EnumNameDataType(input->data_type()) << ", " << shape_i << ");\n";
51 ofs << " MS_ERROR_IF_NULL(inputs_[" << i << "]);\n";
52 }
53 ofs << " outputs_.resize(" << outputs_size << ");\n";
54 for (size_t i = 0; i < outputs_size; ++i) {
55 Tensor *output = outputs[i];
56 std::string shape_i = "out_shape_" + std::to_string(i);
57 array_tostring(output->shape(), shape_i);
58 ofs << " outputs_[" << i << "] = new (std::nothrow) MTensor(String(\"" << output->tensor_name() << "\"), "
59 << EnumNameDataType(output->data_type()) << ", " << shape_i << ");\n";
60 ofs << " MS_ERROR_IF_NULL(outputs_[" << i << "]);\n";
61 }
62 if (config->target() != kARM32M) {
63 ofs << " int ret = Init(model->buf, static_cast<MModel *>(model)->buf_size());\n"
64 " return ret;\n"
65 "}\n\n";
66 return;
67 }
68 ofs << " return RET_OK;\n";
69 ofs << "}\n\n";
70 }
71
CodeCreateSessionImplement(std::ofstream & ofs,const Configurator * config)72 void CodeCreateSessionImplement(std::ofstream &ofs, const Configurator *config) {
73 ofs << "session::LiteSession *session::LiteSession::CreateSession(const lite::Context *context) {\n"
74 " auto *session = new (std::nothrow) lite::LiteSession();\n"
75 " MS_NULLPTR_IF_NULL(session);\n"
76 " int ret = session->InitRuntimeBuffer();\n"
77 " MS_NULLPTR_IF_ERROR(ret);\n";
78 if (config->support_parallel()) {
79 ofs << " MS_NULLPTR_IF_NULL(context);\n"
80 " ret = CreateThreadPool(context->thread_num_);\n"
81 " MS_NULLPTR_IF_ERROR(ret);\n"
82 " SetCoreAffinity(context->device_list_[0].device_info_.cpu_device_info_.cpu_bind_mode_);\n";
83 }
84 ofs << " return session;\n"
85 "}\n\n";
86 ofs << "session::LiteSession *session::LiteSession::CreateSession(const char *model_buf, size_t size,\n"
87 " const lite::Context *context) {\n"
88 " session::LiteSession *session = CreateSession(context);\n"
89 " MS_NULLPTR_IF_NULL(session);\n"
90 " lite::Model *model = lite::Model::Import(model_buf, size);\n"
91 " int ret = session->CompileGraph(model);\n"
92 " MS_NULLPTR_IF_ERROR(ret);\n"
93 " delete model;\n"
94 " return session;\n"
95 "}\n"
96 "} // namespace mindspore\n\n";
97 }
98
CodeCreateSessionDestructor(std::ofstream & ofs,const Configurator * config)99 void CodeCreateSessionDestructor(std::ofstream &ofs, const Configurator *config) {
100 ofs << "LiteSession::~LiteSession() {\n"
101 " FreeResource();\n"
102 " if (runtime_buffer_ != nullptr) {\n"
103 " free(runtime_buffer_);\n"
104 " runtime_buffer_ = nullptr;\n"
105 " }\n"
106 " for (auto &input : inputs_) {\n"
107 " if (input == nullptr) {\n"
108 " continue;\n"
109 " }\n"
110 " delete input;\n"
111 " input = nullptr;\n"
112 " }\n"
113 " for (auto &output : outputs_) {\n"
114 " if (output == nullptr) {\n"
115 " continue;\n"
116 " }\n"
117 " delete output;\n"
118 " output = nullptr;\n"
119 " }\n";
120 if (config->support_parallel()) {
121 ofs << " ClearThreadPool();\n";
122 }
123 ofs << "}\n";
124 }
125
CodeCopyOutputsState(std::ofstream & ofs)126 void CodeCopyOutputsState(std::ofstream &ofs) { ofs << "int CopyOutputsData(void **outputs, int num);\n\n"; }
127
CodeCopyOutputsImplement(std::ofstream & ofs,const std::unique_ptr<CoderContext> & ctx)128 void CodeCopyOutputsImplement(std::ofstream &ofs, const std::unique_ptr<CoderContext> &ctx) {
129 auto tensor_map = ctx->tensors_map();
130 std::vector<Tensor *> outputs = ctx->graph_outputs();
131 size_t outputs_size = outputs.size();
132
133 ofs << "int CopyOutputsData(void **outputs, int num) {\n"
134 " if (outputs == NULL) {\n"
135 " return RET_ERROR;\n"
136 " }\n"
137 << " if (num != " << outputs_size << ") {\n"
138 << " return RET_ERROR;\n"
139 " }\n";
140 for (size_t i = 0; i < outputs_size; ++i) {
141 Tensor *output = outputs[i];
142 MS_CHECK_PTR_IF_NULL(output);
143 ofs << " memcpy(outputs[" << i << "], " << tensor_map[output] << ", " << output->Size() << ");\n";
144 }
145 ofs << " return RET_OK;\n"
146 "}\n\n";
147 }
148
CodeInputState(std::ofstream & ofs)149 void CodeInputState(std::ofstream &ofs) {
150 ofs << "/**\n"
151 << " * set input tensors\n"
152 << " * @param inputs, the input data ptr's array of the model, the tensors' count of input may be greater than "
153 "one.\n"
154 << " * @param num, the input data's number of the model.\n"
155 << " **/\n"
156 << "int "
157 << "SetInputs(const void **inputs, int num);\n\n";
158 }
159
CodeInputImplement(std::ofstream & ofs,const std::unique_ptr<CoderContext> & ctx)160 void CodeInputImplement(std::ofstream &ofs, const std::unique_ptr<CoderContext> &ctx) {
161 // input tensors
162 std::vector<Tensor *> inputs = ctx->graph_inputs();
163 for (size_t i = 0; i < inputs.size(); ++i) {
164 ofs << "static const unsigned char *" << ctx->input_name() + std::to_string(i) << " = 0;\n";
165 }
166 size_t size = inputs.size();
167 ofs << "int "
168 << "SetInputs(const void **inputs, int num) {\n"
169 << " if (inputs == NULL) {\n"
170 " return RET_ERROR;\n"
171 " }\n"
172 << " if (num !=" << size << ") {\n"
173 << " return RET_ERROR;\n"
174 " }\n";
175 for (size_t i = 0; i < size; ++i) {
176 ofs << "\t" << ctx->input_name() << i << " = inputs[" << i << "];\n";
177 }
178 ofs << " return RET_OK;\n}\n";
179 }
180
CodeGraphQuantArgsState(std::ofstream & ofs)181 void CodeGraphQuantArgsState(std::ofstream &ofs) {
182 ofs << "/**\n"
183 << " * get input and output QuantArgs of the model \n"
184 << " **/\n"
185 << "GraphQuantArgs "
186 << "GetInOutQuantArgs();\n\n";
187 }
188
CodeGraphQuantArgsImplement(std::ofstream & ofs,const std::unique_ptr<CoderContext> & ctx)189 void CodeGraphQuantArgsImplement(std::ofstream &ofs, const std::unique_ptr<CoderContext> &ctx) {
190 std::vector<Tensor *> graph_inputs = ctx->graph_inputs();
191 if (graph_inputs.empty()) {
192 MS_LOG(ERROR) << "graph input tensors' number is 0";
193 return;
194 }
195 Tensor *in_tensor = graph_inputs.at(kInputIndex);
196 MS_CHECK_PTR_IF_NULL(in_tensor);
197 std::vector<Tensor *> graph_outputs = ctx->graph_outputs();
198 if (graph_outputs.empty()) {
199 MS_LOG(ERROR) << "graph output tensors' number is 0";
200 return;
201 }
202 Tensor *out_tensor = graph_outputs.at(kOutputIndex);
203 MS_CHECK_PTR_IF_NULL(out_tensor);
204 std::vector<LiteQuantParam> in_quant_args = in_tensor->quant_params();
205 std::vector<LiteQuantParam> out_quant_args = out_tensor->quant_params();
206 if (in_quant_args.empty() || out_quant_args.empty()) {
207 MS_LOG(ERROR) << "code model quant args failed";
208 return;
209 }
210 ofs << "GraphQuantArgs "
211 << "GetInOutQuantArgs() {\n"
212 << "\t\tGraphQuantArgs quan_args = { " << in_quant_args.at(0).scale << ", " << out_quant_args.at(0).scale << ", "
213 << in_quant_args.at(0).zeroPoint << ", " << out_quant_args.at(0).zeroPoint << "};\n"
214 << "\t\treturn quan_args;\n"
215 << "}\n";
216 }
217
CodeManageResourceState(std::ofstream & ofs)218 void CodeManageResourceState(std::ofstream &ofs) {
219 ofs << "/**\n"
220 << " * get the memory space size of the inference.\n"
221 << " **/\n"
222 << "int "
223 << "GetBufferSize();\n";
224
225 ofs << "/**\n"
226 << " * set the memory space for the inference\n"
227 << " **/\n"
228 << "int "
229 << "SetBuffer(void *buffer);\n\n";
230
231 ofs << "/**\n"
232 << " * free the memory of packed weights, and set the membuf buffer and input address to NULL\n"
233 << " **/\n"
234 << "void "
235 << "FreeResource();\n";
236 }
237
CodeInitResourceImplement(std::ofstream & ofs,const std::unique_ptr<CoderContext> & ctx)238 void CodeInitResourceImplement(std::ofstream &ofs, const std::unique_ptr<CoderContext> &ctx) {
239 ofs << "int "
240 << "GetBufferSize() {\n"
241 << " return " << ctx->total_buffer_size() << ";\n"
242 << "}\n";
243 ofs << "int "
244 << "SetBuffer( void *buffer) {\n";
245 ofs << " if (buffer == NULL) {\n"
246 " return RET_ERROR;\n"
247 " }\n";
248 ofs << " " << ctx->buffer_name() << " = buffer;\n"
249 << " return RET_OK;\n"
250 "}\n";
251 }
252
CodeFreeResourceImplement(std::ofstream & ofs,const std::unique_ptr<CoderContext> & ctx)253 void CodeFreeResourceImplement(std::ofstream &ofs, const std::unique_ptr<CoderContext> &ctx) {
254 ofs << "void "
255 << "FreeResource() {\n";
256 ofs << " " << ctx->buffer_name() << "= NULL;\n";
257 std::vector<Tensor *> inputs = ctx->graph_inputs();
258 size_t size = inputs.size();
259 for (size_t i = 0; i < size; ++i) {
260 ofs << " " << ctx->input_name() + std::to_string(i) << " = NULL;\n";
261 }
262 ofs << " void *allocated[] = {";
263 size_t num = 0;
264 for (const auto &item : ctx->tensors_map()) {
265 Tensor *tensor = item.first;
266 std::string name = item.second;
267 if (tensor->data() != nullptr && !(CheckConstantTensor(tensor))) {
268 ofs << name << ", ";
269 num++;
270 }
271 }
272 ofs << " };\n";
273 ofs << " for (int i = 0; i < " << num << "; ++i) {\n"
274 << " free(allocated[i]);\n"
275 << " allocated[i] = NULL;\n"
276 << " }\n";
277 ofs << "}\n";
278 }
279
CodeInferenceState(std::ofstream & ofs)280 void CodeInferenceState(std::ofstream &ofs) {
281 ofs << "/**\n"
282 << " * net inference function\n"
283 << " **/\n"
284 << "void "
285 << "Inference();\n\n";
286 }
287 } // namespace mindspore::lite::micro
288