• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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