• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 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 "minddata/dataset/core/device_tensor_ascend910b.h"
17 
18 #include <string>
19 
20 #include "minddata/dataset/core/global_context.h"
21 #include "minddata/dataset/core/type_id.h"
22 #include "minddata/dataset/kernels/image/dvpp/acl_adapter.h"
23 #include "minddata/dataset/kernels/image/dvpp/utils/ErrorCode.h"
24 #include "minddata/dataset/kernels/image/image_utils.h"
25 #include "minddata/dataset/util/status.h"
26 
27 namespace mindspore {
28 namespace dataset {
DeviceTensorAscend910B(const TensorShape & shape,const DataType & type,device::DeviceContext * device_context,const size_t & stream_id,bool is_hwc)29 DeviceTensorAscend910B::DeviceTensorAscend910B(const TensorShape &shape, const DataType &type,
30                                                device::DeviceContext *device_context, const size_t &stream_id,
31                                                bool is_hwc)
32     : device_context_(device_context),
33       stream_id_(stream_id),
34       device_address_(nullptr),
35       tensor_(nullptr),
36       workspace_(nullptr),
37       float_arrays_({}),
38       int_arrays_({}),
39       tensor_shape_(shape),
40       data_type_(type),
41       is_hwc_(is_hwc) {}
42 
~DeviceTensorAscend910B()43 DeviceTensorAscend910B::~DeviceTensorAscend910B() {}
44 
ValidShape(TensorShape * input_shape,bool is_hwc,std::vector<int> channels={1, 3})45 Status ValidShape(TensorShape *input_shape, bool is_hwc, std::vector<int> channels = {1, 3}) {
46   // change the shape from HWC to 1HWC
47   if (input_shape->Rank() == 1) {                                                    // no expand
48     MS_LOG(DEBUG) << "The input is not RGB which is no need convert to 1HWC/1CHW.";  // used by Dvpp Decode
49     return Status::OK();
50   }
51 
52   const auto kChannelIndexHWC = 2;
53   const auto kChannelIndexNHWC = 3;
54   const auto kDefaultImageChannel = 3;
55   if (is_hwc) {
56     std::string delimiter = ", ";
57     std::ostringstream oss;
58     if (!channels.empty()) {
59       oss << channels[0];
60       for (size_t i = 1; i < channels.size(); ++i) {
61         oss << delimiter << channels[i];
62       }
63     }
64     std::string result = oss.str();
65     // change the shape from HWC to 1HWC
66     if (input_shape->Rank() == kMinImageRank) {  // expand HW to 1HW1
67       *input_shape = input_shape->AppendDim(1);
68       *input_shape = input_shape->PrependDim(1);
69     } else if (input_shape->Rank() == kDefaultImageRank) {  // expand HWC to 1HWC
70       if (std::find(channels.begin(), channels.end(), input_shape->AsVector()[kChannelIndexHWC]) == channels.end()) {
71         RETURN_STATUS_UNEXPECTED("The channel of the input tensor of shape [H,W,C] is not " + result +
72                                  ", but got: " + std::to_string(input_shape->AsVector()[kChannelIndexHWC]));
73       }
74       *input_shape = input_shape->PrependDim(1);
75     } else if (input_shape->Rank() == kDefaultImageRank + 1) {  // NHWC
76       if (std::find(channels.begin(), channels.end(), input_shape->AsVector()[kChannelIndexNHWC]) == channels.end()) {
77         RETURN_STATUS_UNEXPECTED("The channel of the input tensor of shape [N,H,W,C] is not " + result +
78                                  ", but got: " + std::to_string(input_shape->AsVector()[kChannelIndexNHWC]));
79       }
80       if (input_shape->AsVector()[0] != 1) {
81         RETURN_STATUS_UNEXPECTED("The input tensor NHWC should be 1HWC or HWC.");
82       }
83     } else {
84       RETURN_STATUS_UNEXPECTED("The input tensor is not of shape [H,W], [H,W,C] or [N,H,W,C].");
85     }
86   } else {
87     // change the shape from CHW to 1CHW
88     if (input_shape->Rank() == kMinImageRank) {  // expand HW to 11HW
89       *input_shape = input_shape->PrependDim(1);
90       *input_shape = input_shape->PrependDim(1);
91     } else if (input_shape->Rank() == kDefaultImageRank) {  // expand CHW to 1CHW
92       if (input_shape->AsVector()[0] != 1 && input_shape->AsVector()[0] != kDefaultImageChannel) {
93         RETURN_STATUS_UNEXPECTED("The channel of the input tensor of shape [C,H,W] is not 1 or 3, but got: " +
94                                  std::to_string(input_shape->AsVector()[0]));
95       }
96       *input_shape = input_shape->PrependDim(1);
97     } else if (input_shape->Rank() == kDefaultImageRank + 1) {  // NCHW
98       if (input_shape->AsVector()[1] != 1 && input_shape->AsVector()[1] != kDefaultImageChannel) {
99         RETURN_STATUS_UNEXPECTED("The channel of the input tensor of shape [N,C,H,W] is not 1 or 3, but got: " +
100                                  std::to_string(input_shape->AsVector()[1]));
101       }
102       if (input_shape->AsVector()[0] != 1) {
103         RETURN_STATUS_UNEXPECTED("The input tensor NCHW should be 1CHW or CHW.");
104       }
105     } else {
106       RETURN_STATUS_UNEXPECTED("The input tensor is not of shape [H,W], [C,H,W] or [N,C,H,W].");
107     }
108   }
109   return Status::OK();
110 }
111 
112 // create device_tensor by empty
CreateDeviceTensor(const TensorShape & shape,const DataType & type,device::DeviceContext * device_context,const size_t & stream_id,std::shared_ptr<DeviceTensorAscend910B> * out,bool is_hwc,std::vector<int> channels)113 Status DeviceTensorAscend910B::CreateDeviceTensor(const TensorShape &shape, const DataType &type,
114                                                   device::DeviceContext *device_context, const size_t &stream_id,
115                                                   std::shared_ptr<DeviceTensorAscend910B> *out, bool is_hwc,
116                                                   std::vector<int> channels) {
117   RETURN_UNEXPECTED_IF_NULL(device_context);
118   RETURN_UNEXPECTED_IF_NULL(out);
119 
120   TensorShape input_shape(shape);
121   RETURN_IF_NOT_OK(ValidShape(&input_shape, is_hwc, channels));
122 
123   *out = std::make_shared<DeviceTensorAscend910B>(input_shape, type, device_context, stream_id, is_hwc);
124 
125   // create new device address for data copy
126   void *device_address = device_context->device_res_manager_->AllocateMemory((*out)->GetShape().NumOfElements() *
127                                                                              (*out)->GetType().SizeInBytes());
128   if (device_address == nullptr) {
129     RETURN_STATUS_UNEXPECTED("Allocate dynamic workspace memory failed");
130   }
131 
132   (*out)->SetDeviceAddress(device_address);
133 
134   // create the stride
135   std::vector<int64_t> strides((*out)->GetShape().Rank(), 1);
136   for (int64_t i = (*out)->GetShape().Rank() - 2; i >= 0; i--) {
137     strides[i] = (*out)->GetShape()[i + 1] * strides[i + 1];
138   }
139 
140   // create aclTensor, here we use void* hold it.
141   void *device_tensor = nullptr;
142   auto ret = AclAdapter::GetInstance().CreateAclTensor((*out)->GetShape().AsVector().data(), (*out)->GetShape().Rank(),
143                                                        DETypeToMSType((*out)->GetType()), strides.data(), 0,
144                                                        (*out)->GetShape().AsVector().data(), (*out)->GetShape().Rank(),
145                                                        (*out)->GetDeviceAddress(), is_hwc, &device_tensor);
146   if (ret != APP_ERR_OK) {
147     std::string error = "Create acl tensor failed.";
148     RETURN_STATUS_UNEXPECTED(error);
149   }
150   CHECK_FAIL_RETURN_UNEXPECTED(device_tensor != nullptr, "Create device tensor failed.");
151 
152   (*out)->SetDeviceTensor(device_tensor);
153 
154   return Status::OK();
155 }
156 
157 // create device_tensor by host tensor
CreateDeviceTensor(std::shared_ptr<Tensor> tensor,device::DeviceContext * device_context,const size_t & stream_id,std::shared_ptr<DeviceTensorAscend910B> * out,bool is_hwc,std::vector<int> channels)158 Status DeviceTensorAscend910B::CreateDeviceTensor(std::shared_ptr<Tensor> tensor, device::DeviceContext *device_context,
159                                                   const size_t &stream_id, std::shared_ptr<DeviceTensorAscend910B> *out,
160                                                   bool is_hwc, std::vector<int> channels) {
161   RETURN_UNEXPECTED_IF_NULL(tensor);
162   RETURN_UNEXPECTED_IF_NULL(device_context);
163   RETURN_UNEXPECTED_IF_NULL(out);
164 
165   RETURN_IF_NOT_OK(DeviceTensorAscend910B::CreateDeviceTensor(tensor->shape(), tensor->type(), device_context,
166                                                               stream_id, out, is_hwc, channels));
167 
168   CHECK_FAIL_RETURN_UNEXPECTED(
169     tensor->SizeInBytes() == (*out)->GetShape().NumOfElements() * (*out)->GetType().SizeInBytes(),
170     "The device SizeInBytes is not equal the input tensor.");
171 
172   // copy the host data to device
173   (void)(*out)->GetDeviceContext()->device_res_manager_->SwapIn(
174     reinterpret_cast<void *>(tensor->GetMutableBuffer()), (*out)->GetDeviceAddress(), tensor->SizeInBytes(), nullptr);
175 
176   return Status::OK();
177 }
178 
ToHostTensor(std::shared_ptr<Tensor> * host_tensor)179 Status DeviceTensorAscend910B::ToHostTensor(std::shared_ptr<Tensor> *host_tensor) {
180   CHECK_FAIL_RETURN_UNEXPECTED(host_tensor != nullptr, "The host tensor is nullptr pointer.");
181   CHECK_FAIL_RETURN_UNEXPECTED(device_address_ != nullptr, "The device tensor is nullptr pointer.");
182 
183   if (!device_context_->device_res_manager_->SyncStream(stream_id_)) {
184     std::string err_msg = "SyncStream stream id: " + std::to_string(stream_id_) + " failed.";
185     RETURN_STATUS_UNEXPECTED(err_msg);
186   }
187 
188   RETURN_IF_NOT_OK(Tensor::CreateEmpty(GetShape(), GetType(), host_tensor));
189 
190   // copy the device data to host
191   (void)device_context_->device_res_manager_->SwapOut(device_address_,
192                                                       reinterpret_cast<void *>((*host_tensor)->GetMutableBuffer()),
193                                                       (*host_tensor)->SizeInBytes(), nullptr);
194 
195   // release the device memory
196   (void)device_context_->device_res_manager_->FreeMemory(device_address_);
197 
198   (*host_tensor)->Squeeze();
199 
200   return Status::OK();
201 }
202 
AddWorkSpace(void * workspace)203 bool DeviceTensorAscend910B::AddWorkSpace(void *workspace) {
204   if (workspace == nullptr) {
205     MS_LOG(ERROR) << "The input workspace is nullptr.";
206     return false;
207   }
208   if (workspace_ != nullptr) {
209     MS_LOG(ERROR) << "The workspace_ is not nullptr, please don't re-add workspace to the current DeviceTensor.";
210     return false;
211   }
212   workspace_ = workspace;
213   return true;
214 }
215 
AddMaintenFloatArrayMemory(void * float_array)216 bool DeviceTensorAscend910B::AddMaintenFloatArrayMemory(void *float_array) {
217   if (float_array == nullptr) {
218     MS_LOG(ERROR) << "The input float_array is nullptr.";
219     return false;
220   }
221   float_arrays_.push_back(float_array);
222   return true;
223 }
224 
AddMaintenIntArrayMemory(void * int_array)225 bool DeviceTensorAscend910B::AddMaintenIntArrayMemory(void *int_array) {
226   if (int_array == nullptr) {
227     MS_LOG(ERROR) << "The input int_array is nullptr.";
228     return false;
229   }
230   int_arrays_.push_back(int_array);
231   return true;
232 }
233 
ReleaseDeviceMemory()234 bool DeviceTensorAscend910B::ReleaseDeviceMemory() {
235   // release the device memory of the data
236   if (device_address_ != nullptr) {
237     device_context_->device_res_manager_->FreeMemory(device_address_);
238     device_address_ = nullptr;
239   }
240 
241   // release the acl_tensor
242   if (tensor_ != nullptr) {
243     auto ret = AclAdapter::GetInstance().DestroyTensor(tensor_);
244     if (ret != APP_ERR_OK) {
245       MS_LOG(ERROR) << "Destroy acl tensor failed.";
246       return false;
247     }
248     tensor_ = nullptr;
249   }
250 
251   // release the device memory of the workspace
252   if (workspace_ != nullptr) {
253     device_context_->device_res_manager_->FreeMemory(workspace_);
254     workspace_ = nullptr;
255   }
256 
257   // release the float arrays
258   for (auto &float_array : float_arrays_) {
259     if (float_array != nullptr) {
260       auto ret = AclAdapter::GetInstance().DestroyFloatArray(float_array);
261       if (ret != APP_ERR_OK) {
262         MS_LOG(ERROR) << "Destroy float array failed.";
263         return false;
264       }
265     }
266     float_array = nullptr;
267   }
268 
269   // release the int arrays
270   for (auto &int_array : int_arrays_) {
271     if (int_array != nullptr) {
272       auto ret = AclAdapter::GetInstance().DestroyIntArray(int_array);
273       if (ret != APP_ERR_OK) {
274         MS_LOG(ERROR) << "Destroy int array failed.";
275         return false;
276       }
277     }
278     int_array = nullptr;
279   }
280 
281   return true;
282 }
283 }  // namespace dataset
284 }  // namespace mindspore
285