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