1 /**
2 * Copyright 2021-2023 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 #include "src/litert/infer_manager.h"
17 #include <algorithm>
18 #include <set>
19 #include <string>
20 #include <memory>
21 #include "src/common/prim_util.h"
22 #include "src/common/tensor_util.h"
23 #include "src/litert/cxx_api/tensor/tensor_impl.h"
24 #include "schema/model_generated.h"
25 #include "include/errorcode.h"
26 #include "nnacl/errorcode.h"
27 #include "src/tensorlist.h"
28 #include "include/registry/register_kernel_interface.h"
29 #include "src/litert/kernel_registry.h"
30
31 namespace mindspore {
32 namespace lite {
33 namespace {
34 static const size_t kNumMaxMallocSize = GetMaxMallocSize();
35 } // namespace
36
InferCheckerAll(const std::vector<Tensor * > & inputs,const std::vector<Tensor * > & outputs)37 bool InferCheckerAll(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) {
38 if (outputs.empty()) {
39 return false;
40 }
41 auto out = outputs.front();
42 if (out == nullptr) {
43 return false;
44 }
45 if (!out->get_shape_changed() && std::any_of(inputs.begin(), inputs.end(), [](const lite::Tensor *input) {
46 if (input == nullptr) {
47 return false;
48 }
49 return input->get_shape_changed();
50 })) {
51 return false;
52 }
53 auto shape = out->shape();
54 return !std::any_of(shape.begin(), shape.end(), [](const int dim) { return dim < 0; });
55 }
56
InferCheckerInput(const std::vector<Tensor * > & inputs,const std::vector<Tensor * > & outputs)57 bool InferCheckerInput(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) {
58 if (outputs.empty()) {
59 return false;
60 }
61 if (outputs.front() == nullptr) {
62 return false;
63 }
64 return std::all_of(outputs.begin(), outputs.end(),
65 [](const lite::Tensor *output) {
66 if (output == nullptr) {
67 return false;
68 }
69 return output->get_shape_changed();
70 }) ||
71 std::all_of(inputs.begin(), inputs.end(), [](const lite::Tensor *input) {
72 if (input == nullptr) {
73 return false;
74 }
75 return !input->get_shape_changed();
76 });
77 }
78
InferCheckerOutput(const std::vector<Tensor * > & inputs,const std::vector<Tensor * > & outputs)79 bool InferCheckerOutput(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) {
80 if (outputs.empty()) {
81 return false;
82 }
83 if (outputs.front() == nullptr) {
84 return false;
85 }
86 auto shape = outputs.front()->shape();
87 return !std::any_of(shape.begin(), shape.end(), [](const int dim) { return dim < 0; });
88 }
89
KernelInferShape(const std::vector<lite::Tensor * > & inputs,const std::vector<lite::Tensor * > & outputs,const void * primitive,std::set<std::string> && providers,int schema_version,const kernel::Kernel * kernel)90 int KernelInferShape(const std::vector<lite::Tensor *> &inputs, const std::vector<lite::Tensor *> &outputs,
91 const void *primitive, std::set<std::string> &&providers, int schema_version,
92 const kernel::Kernel *kernel) {
93 #ifndef CUSTOM_KERNEL_REGISTRY_CLIP
94 if (primitive == nullptr && kernel == nullptr) {
95 return RET_NOT_SUPPORT;
96 }
97 std::shared_ptr<kernel::KernelInterface> kernel_interface = nullptr;
98 bool is_custom_node = false;
99 if (kernel == nullptr) {
100 if (IsCustomNode(primitive, schema_version)) {
101 is_custom_node = true;
102 }
103 } else if (kernel->type() == schema::PrimitiveType_Custom) {
104 is_custom_node = true;
105 }
106 if (is_custom_node) {
107 kernel_interface = registry::RegisterKernelInterface::GetKernelInterface(
108 "", static_cast<const schema::Primitive *>(primitive), kernel);
109 } else {
110 for (auto &&provider : providers) {
111 kernel_interface = registry::RegisterKernelInterface::GetKernelInterface(
112 provider, static_cast<const schema::Primitive *>(primitive), kernel);
113 if (kernel_interface != nullptr) {
114 break;
115 }
116 }
117 }
118
119 if (kernel_interface == nullptr) {
120 return RET_NOT_SUPPORT;
121 }
122 std::vector<mindspore::MSTensor> in_tensors;
123 (void)std::transform(inputs.begin(), inputs.end(), std::back_inserter(in_tensors), [](lite::Tensor *tensor) {
124 return mindspore::MSTensor(std::make_shared<LiteTensorImpl>(tensor));
125 });
126 std::vector<mindspore::MSTensor> out_tensors;
127 (void)std::transform(outputs.begin(), outputs.end(), std::back_inserter(out_tensors), [](lite::Tensor *tensor) {
128 return mindspore::MSTensor(std::make_shared<LiteTensorImpl>(tensor));
129 });
130 auto ret =
131 kernel_interface->Infer(&in_tensors, &out_tensors, static_cast<const schema::Primitive *>(primitive), kernel);
132 if (ret == kLiteInferInvalid) {
133 for (auto output : outputs) {
134 output->set_shape({-1});
135 }
136 return RET_INFER_INVALID;
137 }
138 if (ret != kSuccess) {
139 MS_LOG(ERROR) << "op_type: " << GetPrimitiveTypeName(primitive, schema_version) << " infer fail!ret: " << ret;
140 return RET_ERROR;
141 }
142 return RET_OK;
143 #endif
144 return lite::RET_NOT_SUPPORT;
145 }
146
CheckInfershapeResult(int result,const std::vector<lite::Tensor * > & inputs,const std::vector<lite::Tensor * > & outputs,OpParameter * parameter)147 int CheckInfershapeResult(int result, const std::vector<lite::Tensor *> &inputs,
148 const std::vector<lite::Tensor *> &outputs, OpParameter *parameter) {
149 if (result == NNACL_INFER_INVALID) {
150 return RET_INFER_INVALID;
151 } else if (result != NNACL_OK) {
152 if (result == NNACL_FORMAT_ERROR) {
153 MS_LOG(WARNING) << "Unexpected input format " << inputs[0]->format();
154 }
155 return RET_INFER_ERR;
156 }
157
158 for (auto output : outputs) {
159 auto element_num = output->ElementsNum();
160 if (element_num < 0) {
161 continue;
162 }
163 if (static_cast<size_t>(element_num) >= kNumMaxMallocSize / sizeof(int64_t)) {
164 MS_LOG(ERROR) << "The size of output tensor is too big, output size: " << output->ElementsNum();
165 return RET_INFER_ERR;
166 }
167 }
168
169 parameter->is_zero_shape_ = true;
170 size_t zero_shape_num = 0;
171 for (auto tensor : outputs) {
172 for (size_t i = 0; i < tensor->shape().size(); i++) {
173 if (tensor->shape()[i] == 0) {
174 zero_shape_num++;
175 break;
176 }
177 }
178 }
179 if (zero_shape_num != outputs.size()) {
180 parameter->is_zero_shape_ = false;
181 }
182 return RET_OK;
183 }
184
KernelInferShape(const std::vector<lite::Tensor * > & inputs,const std::vector<lite::Tensor * > & outputs,OpParameter * parameter,std::shared_ptr<Allocator> allocator)185 int KernelInferShape(const std::vector<lite::Tensor *> &inputs, const std::vector<lite::Tensor *> &outputs,
186 OpParameter *parameter, std::shared_ptr<Allocator> allocator) {
187 MS_CHECK_TRUE_MSG(parameter != nullptr, RET_ERROR, "parameter is nullptr.");
188 if (inputs.empty()) {
189 MS_LOG(ERROR) << "No input!";
190 return RET_ERROR;
191 }
192 if (parameter->type_ == static_cast<int>(PrimType_Inner_ThirdPartyModel)) {
193 MS_LOG(INFO) << "no need infer shape.";
194 return RET_OK;
195 }
196 std::vector<TensorC *> in_tensors;
197 std::vector<TensorC *> out_tensors;
198 int ret = GenerateInTensorC(inputs, &in_tensors, allocator);
199 if (ret != RET_OK) {
200 FreeInTensorC(&in_tensors, allocator);
201 return RET_ERROR;
202 }
203 ret = GenerateOutTensorC(parameter, outputs, &out_tensors);
204 if (ret != RET_OK) {
205 FreeInTensorC(&in_tensors, allocator);
206 FreeOutTensorC(&out_tensors, allocator);
207 return RET_ERROR;
208 }
209 auto infer_shape_func = GetInferFunc(parameter->type_);
210 if (infer_shape_func == nullptr) {
211 MS_LOG(ERROR) << "Get infershape func failed! type:" << PrimitiveCurVersionTypeName(parameter->type_);
212 FreeInTensorC(&in_tensors, allocator);
213 FreeOutTensorC(&out_tensors, allocator);
214 return RET_ERROR;
215 }
216 ret = infer_shape_func(static_cast<TensorC **>(in_tensors.data()), in_tensors.size(), out_tensors.data(),
217 out_tensors.size(), parameter);
218 FreeInTensorC(&in_tensors, allocator);
219 for (size_t i = 0; i < out_tensors.size(); i++) {
220 if (out_tensors.at(i) == nullptr) {
221 continue;
222 }
223 if (reinterpret_cast<TensorListC *>(out_tensors.at(i))->data_type_ == TypeIdC::kObjectTypeTensorType) {
224 auto *tensor_list_c = reinterpret_cast<TensorListC *>(out_tensors.at(i));
225 auto tensor_list = MallocTensorListDataAccordingToTensorListC(outputs.at(i), tensor_list_c);
226 if (tensor_list == nullptr) {
227 MS_LOG(ERROR) << "get as tensorlist failed";
228 FreeOutTensorC(&out_tensors, allocator);
229 return RET_ERROR;
230 }
231 auto tensor_ret = TensorListC2TensorList(tensor_list_c, tensor_list);
232 if (tensor_ret != RET_OK) {
233 MS_LOG(ERROR) << "TensorCList2TensorList failed";
234 FreeOutTensorC(&out_tensors, allocator);
235 return tensor_ret;
236 }
237 } else {
238 // During the online phase of shape operator fusion, the output data is computed in advance during the infer shape
239 // stage. Therefore, the output data is not nullptr and is constant.
240 if (parameter->type_ == static_cast<int>(PrimType::PrimType_Inner_ShapeFusion) &&
241 out_tensors.at(i)->data_ != nullptr) {
242 outputs.at(i)->set_own_data(true);
243 outputs.at(i)->set_category(CONST_TENSOR);
244 }
245 }
246
247 if (ret == NNACL_INFER_INVALID) {
248 outputs.at(i)->set_shape({-1});
249 }
250 outputs.at(i)->set_shape_changed(true);
251 }
252 FreeOutTensorC(&out_tensors, allocator);
253
254 return CheckInfershapeResult(ret, inputs, outputs, parameter);
255 }
256 } // namespace lite
257 } // namespace mindspore
258