• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/litert/delegate/npu/npu_executor.h"
18 #include <unordered_map>
19 #include <set>
20 #include "include/errorcode.h"
21 #include "src/litert/delegate/npu/npu_manager.h"
22 #include "src/common/log_adapter.h"
23 
24 namespace mindspore::lite {
~NPUExecutor()25 NPUExecutor::~NPUExecutor() {
26   client_.reset();
27   for (auto t : npu_input_tensors_) {
28     t.reset();
29   }
30   npu_input_tensors_.clear();
31   for (auto t : npu_output_tensors_) {
32     t.reset();
33   }
34   npu_output_tensors_.clear();
35 }
36 
Prepare()37 int NPUExecutor::Prepare() {
38   MS_ASSERT(npu_manager_ != nullptr);
39   this->client_ = npu_manager_->GetClient(model_name_);
40   if (this->client_ == nullptr) {
41     MS_LOG(ERROR) << "client is nullptr.";
42     return RET_ERROR;
43   }
44   if (GetIOTensorVec() != RET_OK) {
45     MS_LOG(ERROR) << "NPUExecutor GetIOTensorVec failed.";
46     return RET_ERROR;
47   }
48   return RET_OK;
49 }
50 
GetNpuTensorShape(int dim,std::shared_ptr<hiai::AiTensor> npu_tensor)51 std::vector<int64_t> GetNpuTensorShape(int dim, std::shared_ptr<hiai::AiTensor> npu_tensor) {
52   std::vector<int64_t> npu_shape;
53   if (dim > 0) {
54     npu_shape.push_back(npu_tensor->GetTensorDimension().GetNumber());
55   }
56   if (dim > 1) {
57     npu_shape.push_back(npu_tensor->GetTensorDimension().GetChannel());
58   }
59   if (dim > 2) {
60     npu_shape.push_back(npu_tensor->GetTensorDimension().GetHeight());
61   }
62   if (dim > 3) {
63     npu_shape.push_back(npu_tensor->GetTensorDimension().GetWidth());
64   }
65   return npu_shape;
66 }
67 
IsSameShapeTensor(mindspore::MSTensor tensor,const std::shared_ptr<hiai::AiTensor> & npu_tensor)68 bool IsSameShapeTensor(mindspore::MSTensor tensor, const std::shared_ptr<hiai::AiTensor> &npu_tensor) {
69   if (tensor.Shape().size() > NPU_SHAPE_SIZE) {
70     MS_LOG(ERROR) << "Npu does not support output tensor dims greater than 4";
71     return false;
72   }
73   return GetNpuTensorShape(tensor.Shape().size(), npu_tensor) == tensor.Shape();
74 }
75 
Run(const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & valid_out_tensors,const std::vector<mindspore::MSTensor> & all_out_tensors,const std::vector<NPUOp * > & out_ops)76 int NPUExecutor::Run(const std::vector<mindspore::MSTensor> &in_tensors,
77                      const std::vector<mindspore::MSTensor> &valid_out_tensors,
78                      const std::vector<mindspore::MSTensor> &all_out_tensors, const std::vector<NPUOp *> &out_ops) {
79   hiai::AiContext context;
80   for (size_t i = 0; i < npu_input_tensors_.size(); ++i) {
81     MS_CHECK_TRUE_RET(i < input_relationship_.size() && input_relationship_.at(i) < in_tensors.size(), RET_ERROR);
82     auto inx = input_relationship_.at(i);
83     auto data = in_tensors[inx].Data();
84     if (data == nullptr) {
85       MS_LOG(ERROR) << "For " << model_name_ << ", the input tensor " << in_tensors[inx].Name() << " data is nullptr";
86       return RET_ERROR;
87     }
88     memcpy(npu_input_tensors_[i]->GetBuffer(), data.get(), in_tensors[inx].DataSize());
89   }
90   context.AddPara("model_name", model_name_);
91   if (this->client_ == nullptr) {
92     MS_LOG(ERROR) << "NPU client is nullptr";
93     return RET_ERROR;
94   }
95   int stamp;
96   int ret = this->client_->Process(context, this->npu_input_tensors_, this->npu_output_tensors_, 1000, stamp);
97   if (ret != hiai::AI_SUCCESS) {
98     MS_LOG(ERROR) << "NPU Process failed. code is " << ret;
99     return RET_ERROR;
100   }
101 
102   // if the multi-output op is the graph out op, all of its output tensor will be treat as graph output for om model.
103   std::set<schema::PrimitiveType> multi_output_list = {schema::PrimitiveType_Split};
104   bool has_multi_output_op = false;
105   for (auto out_op : out_ops) {
106     if (std::find(multi_output_list.begin(), multi_output_list.end(), out_op->type()) != multi_output_list.end()) {
107       has_multi_output_op = true;
108       break;
109     }
110   }
111 
112   if (npu_output_tensors_.size() != all_out_tensors.size() ||
113       (!has_multi_output_op && npu_output_tensors_.size() != valid_out_tensors.size())) {
114     MS_LOG(ERROR) << "The output count (" << npu_output_tensors_.size() << ") is not equal to ms tensor ("
115                   << all_out_tensors.size() << ").";
116     return RET_ERROR;
117   }
118   for (size_t i = 0; i < npu_output_tensors_.size(); ++i) {
119     mindspore::MSTensor out_tensor = all_out_tensors[i];
120     if (std::find(valid_out_tensors.begin(), valid_out_tensors.end(), out_tensor) != valid_out_tensors.end()) {
121       auto data = out_tensor.MutableData();
122       if (data == nullptr) {
123         MS_LOG(ERROR) << "For " << model_name_ << ", the output tensor " << out_tensor.Name() << " data is nullptr";
124         return RET_ERROR;
125       }
126       memcpy(data, npu_output_tensors_[i]->GetBuffer(), npu_output_tensors_[i]->GetSize());
127     }
128   }
129   return RET_OK;
130 }
131 
GetIOTensorVec()132 int NPUExecutor::GetIOTensorVec() {
133   std::vector<hiai::TensorDimension> input_dimension;
134   std::vector<hiai::TensorDimension> output_dimension;
135   input_dimension.clear();
136   output_dimension.clear();
137   if (this->client_ == nullptr) {
138     MS_LOG(ERROR) << "client is nullptr.";
139     return RET_ERROR;
140   }
141   auto ret = this->client_->GetModelIOTensorDim(model_name_, input_dimension, output_dimension);
142   if (ret != hiai::AI_SUCCESS) {
143     MS_LOG(ERROR) << "Get model input and output tensor dims failed." << ret;
144     return RET_ERROR;
145   }
146   ret = UpdateInputTensorVec(input_dimension);
147   if (ret != RET_OK) {
148     MS_LOG(ERROR) << "Update input tensor vector failed. " << ret;
149     return RET_ERROR;
150   }
151   ret = UpdateOutputTensorVec(output_dimension);
152   if (ret != RET_OK) {
153     MS_LOG(ERROR) << "Update output tensor vector failed. " << ret;
154     return RET_ERROR;
155   }
156   return RET_OK;
157 }
158 
UpdateInputTensorVec(const std::vector<hiai::TensorDimension> & input_dimension)159 int NPUExecutor::UpdateInputTensorVec(const std::vector<hiai::TensorDimension> &input_dimension) {
160   if (input_dimension.empty()) {
161     MS_LOG(ERROR) << "npu input tensor dimension is empty.";
162     return RET_ERROR;
163   }
164   npu_input_tensors_.resize(input_dimension.size());
165   npu_input_tensors_.clear();
166   for (const auto &inDim : input_dimension) {
167     std::shared_ptr<hiai::AiTensor> input = std::make_shared<hiai::AiTensor>();
168     if (input->Init(&inDim) != hiai::AI_SUCCESS) {
169       MS_LOG(ERROR) << "Input AiTensor init failed.";
170       return RET_ERROR;
171     }
172     npu_input_tensors_.push_back(input);
173   }
174   if (npu_input_tensors_.empty()) {
175     MS_LOG(ERROR) << "NPU input tensor is empty.";
176     return RET_ERROR;
177   }
178   return RET_OK;
179 }
180 
UpdateOutputTensorVec(const std::vector<hiai::TensorDimension> & output_dimension)181 int NPUExecutor::UpdateOutputTensorVec(const std::vector<hiai::TensorDimension> &output_dimension) {
182   if (output_dimension.empty()) {
183     MS_LOG(ERROR) << "output_dimension_ is empty.";
184     return RET_ERROR;
185   }
186   npu_output_tensors_.resize(output_dimension.size());
187   npu_output_tensors_.clear();
188   for (const auto &outDim : output_dimension) {
189     std::shared_ptr<hiai::AiTensor> output = std::make_shared<hiai::AiTensor>();
190     int ret = output->Init(&outDim);
191     if (ret != hiai::AI_SUCCESS) {
192       return RET_ERROR;
193     }
194     npu_output_tensors_.push_back(output);
195   }
196   if (npu_output_tensors_.empty()) {
197     MS_LOG(ERROR) << "NPU output tensor is empty.";
198     return RET_ERROR;
199   }
200   return RET_OK;
201 }
202 }  // namespace mindspore::lite
203