Initial commit

This commit is contained in:
Heiko J Schick
2020-11-23 16:10:05 +01:00
commit ded30f2e42
16 changed files with 1361 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
# Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved.
# CMake lowest version requirement
cmake_minimum_required(VERSION 3.5.1)
# project information
project(sample-colorization)
# Compile options
add_compile_options(-std=c++11)
add_definitions(-DENABLE_DVPP_INTERFACE)
# Specify target generation path
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "../../../out")
set(OPENCV_PATH "/usr/local")
set(INC_PATH $ENV{DDK_PATH})
if (NOT DEFINED ENV{DDK_PATH})
set(INC_PATH "/home/c72/Ascend/")
message(STATUS "set default INC_PATH: ${INC_PATH}")
else ()
message(STATUS "env INC_PATH: ${INC_PATH}")
endif()
set(LIB_PATH $ENV{NPU_HOST_LIB})
if (NOT DEFINED ENV{NPU_HOST_LIB})
set(LIB_PATH "/usr/local/Ascend/acllib/lib64/stub/")
message(STATUS "set default LIB_PATH: ${LIB_PATH}")
else ()
message(STATUS "env LIB_PATH: ${LIB_PATH}")
endif()
# Header path
include_directories(
../inc/
${INC_PATH}/acllib/include/
${OPENCV_PATH}/include/opencv4
)
# add host lib path
link_directories(
${LIB_PATH}
$ENV{HOME}/ascend_ddk/host/lib/
${OPENCV_PATH}/lib
${INC_PATH}/atc/lib64
)
add_executable(main
utils.cpp
colorize_process.cpp
model_process.cpp
main.cpp)
target_link_libraries(main
ascendcl acl_dvpp stdc++ opencv_highgui opencv_core opencv_imgproc opencv_imgcodecs opencv_calib3d opencv_features2d opencv_videoio)
install(TARGETS main DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
+1
View File
@@ -0,0 +1 @@
{}
+292
View File
@@ -0,0 +1,292 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* File sample_process.cpp
* Description: handle acl resource
*/
#include "colorize_process.h"
#include <iostream>
#include "acl/acl.h"
#include "model_process.h"
#include "utils.h"
using namespace std;
namespace {
uint32_t kTopNConfidenceLevels = 5;
}
ColorizeProcess::ColorizeProcess(const char* modelPath,
uint32_t modelWidth, uint32_t modelHeight)
:deviceId_(0), inputBuf_(nullptr),
modelWidth_(modelWidth), modelHeight_(modelHeight), isInited_(false){
modelPath_ = modelPath;
inputDataSize_ = RGBF32_CHAN_SIZE(modelWidth_, modelHeight_);
}
ColorizeProcess::~ColorizeProcess() {
DestroyResource();
}
Result ColorizeProcess::InitResource() {
// ACL init
const char *aclConfigPath = "../src/acl.json";
aclError ret = aclInit(aclConfigPath);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("Acl init failed");
return FAILED;
}
INFO_LOG("Acl init success");
// open device
ret = aclrtSetDevice(deviceId_);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("Acl open device %d failed", deviceId_);
return FAILED;
}
INFO_LOG("Open device %d success", deviceId_);
ret = aclrtGetRunMode(&runMode_);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("acl get run mode failed");
return FAILED;
}
return SUCCESS;
}
Result ColorizeProcess::InitModel(const char* omModelPath) {
Result ret = model_.LoadModelFromFileWithMem(omModelPath);
if (ret != SUCCESS) {
ERROR_LOG("execute LoadModelFromFileWithMem failed");
return FAILED;
}
ret = model_.CreateDesc();
if (ret != SUCCESS) {
ERROR_LOG("execute CreateDesc failed");
return FAILED;
}
ret = model_.CreateOutput();
if (ret != SUCCESS) {
ERROR_LOG("execute CreateOutput failed");
return FAILED;
}
aclrtMalloc(&inputBuf_, (size_t)(inputDataSize_), ACL_MEM_MALLOC_HUGE_FIRST);
if (inputBuf_ == nullptr) {
ERROR_LOG("Acl malloc image buffer failed.");
return FAILED;
}
ret = model_.CreateInput(inputBuf_, inputDataSize_);
if (ret != SUCCESS) {
ERROR_LOG("Create mode input dataset failed");
return FAILED;
}
return SUCCESS;
}
Result ColorizeProcess::Init() {
if (isInited_) {
INFO_LOG("Classify instance is initied already!");
return SUCCESS;
}
Result ret = InitResource();
if (ret != SUCCESS) {
ERROR_LOG("Init acl resource failed");
return FAILED;
}
ret = InitModel(modelPath_);
if (ret != SUCCESS) {
ERROR_LOG("Init model failed");
return FAILED;
}
isInited_ = true;
return SUCCESS;
}
Result ColorizeProcess::Preprocess(const string& imageFile) {
// read image using OPENCV
cv::Mat mat = cv::imread(imageFile, CV_LOAD_IMAGE_COLOR);
//resize
cv::Mat reiszeMat;
cv::resize(mat, reiszeMat, cv::Size(224, 224));
// deal image
reiszeMat.convertTo(reiszeMat, CV_32FC3);
reiszeMat = 1.0 * reiszeMat / 255;
cv::cvtColor(reiszeMat, reiszeMat, CV_BGR2Lab);
// pull out L channel and subtract 50 for mean-centering
std::vector<cv::Mat> channels;
cv::split(reiszeMat, channels);
cv::Mat reiszeMatL = channels[0] - 50;
if (mat.empty()) {
return FAILED;
}
if (runMode_ == ACL_HOST) {
//AI1上运行时,需要将图片数据拷贝到device侧
aclError ret = aclrtMemcpy(inputBuf_, inputDataSize_,
reiszeMatL.ptr<uint8_t>(), inputDataSize_,
ACL_MEMCPY_HOST_TO_DEVICE);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("Copy resized image data to device failed.");
return FAILED;
}
} else {
//Atals200DK上运行时,数据拷贝到本地即可.
//reiszeMat是局部变量,数据无法传出函数,需要拷贝一份
memcpy(inputBuf_, reiszeMatL.ptr<uint8_t>(), inputDataSize_);
}
return SUCCESS;
}
Result ColorizeProcess::Inference(aclmdlDataset*& inferenceOutput) {
Result ret = model_.Execute();
if (ret != SUCCESS) {
ERROR_LOG("Execute model inference failed");
return FAILED;
}
inferenceOutput = model_.GetModelOutputData();
return SUCCESS;
}
Result ColorizeProcess::Postprocess(const string& imageFile, aclmdlDataset* modelOutput)
{
uint32_t dataSize = 0;
void* data = GetInferenceOutputItem(dataSize, modelOutput);
if (data == nullptr) return FAILED;
uint32_t size = static_cast<uint32_t>(dataSize) / sizeof(float);
// get a channel and b channel result data
cv::Mat mat_a(56, 56, CV_32FC1, const_cast<float*>((float*)data));
cv::Mat mat_b(56, 56, CV_32FC1, const_cast<float*>((float*)data + size / 2));
// pull out L channel in original image
cv::Mat mat = cv::imread(imageFile, CV_LOAD_IMAGE_COLOR);
mat.convertTo(mat, CV_32FC3);
mat = 1.0 * mat / 255;
cv::cvtColor(mat, mat, CV_BGR2Lab);
std::vector<cv::Mat> channels;
cv::split(mat, channels);
// resize to match size of original image L
int r = mat.rows;
int c = mat.cols;
cv::Mat mat_a_up(r, c, CV_32FC1);
cv::Mat mat_b_up(r, c, CV_32FC1);
cv::resize(mat_a, mat_a_up, cv::Size(c, r));
cv::resize(mat_b, mat_b_up, cv::Size(c, r));
// result Lab image
cv::Mat newChannels[3] = { channels[0], mat_a_up, mat_b_up };
cv::Mat resultImage;
cv::merge(newChannels, 3, resultImage);
//convert back to rgb
cv::cvtColor(resultImage, resultImage, CV_Lab2BGR);
resultImage = resultImage * 255;
SaveImage(imageFile, resultImage);
return SUCCESS;
}
void ColorizeProcess::SaveImage(const string& origImageFile, cv::Mat& image) {
int pos = origImageFile.find_last_of("/");
string filename(origImageFile.substr(pos + 1));
stringstream sstream;
sstream.str("");
sstream << "./output/out_" << filename;
string outputPath = sstream.str();
cv::imwrite(outputPath, image);
}
void* ColorizeProcess::GetInferenceOutputItem(uint32_t& itemDataSize,
aclmdlDataset* inferenceOutput) {
aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(inferenceOutput, 0);
if (dataBuffer == nullptr) {
ERROR_LOG("Get the dataset buffer from model "
"inference output failed");
return nullptr;
}
void* dataBufferDev = aclGetDataBufferAddr(dataBuffer);
if (dataBufferDev == nullptr) {
ERROR_LOG("Get the dataset buffer address "
"from model inference output failed");
return nullptr;
}
size_t bufferSize = aclGetDataBufferSize(dataBuffer);
if (bufferSize == 0) {
ERROR_LOG("The dataset buffer size of "
"model inference output is 0 ");
return nullptr;
}
void* data = nullptr;
if (runMode_ == ACL_HOST) {
data = Utils::CopyDataDeviceToHost(dataBufferDev, bufferSize);
if (data == nullptr) {
ERROR_LOG("Copy inference output to host failed");
return nullptr;
}
} else {
data = dataBufferDev;
}
itemDataSize = bufferSize;
return data;
}
void ColorizeProcess::DestroyResource()
{
model_.Unload();
model_.DestroyDesc();
model_.DestroyInput();
model_.DestroyOutput();
aclError ret;
ret = aclrtResetDevice(deviceId_);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("reset device failed");
}
INFO_LOG("end to reset device is %d", deviceId_);
ret = aclFinalize();
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("finalize acl failed");
}
INFO_LOG("end to finalize acl");
aclrtFree(inputBuf_);
inputBuf_ = nullptr;
}
+82
View File
@@ -0,0 +1,82 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* File main.cpp
* Description: dvpp sample main func
*/
#include <iostream>
#include <stdlib.h>
#include <dirent.h>
#include "colorize_process.h"
#include "utils.h"
using namespace std;
namespace {
uint32_t kModelWidth = 224;
uint32_t kModelHeight = 224;
const char* kModelPath = "../model/colorization.om";
}
int main(int argc, char *argv[]) {
//检查应用程序执行时的输入,程序执行要求输入图片目录参数
if((argc < 2) || (argv[1] == nullptr)){
ERROR_LOG("Please input: ./main <image_dir>");
return FAILED;
}
//实例化分类推理对象,参数为分类模型路径,模型输入要求的宽和高
ColorizeProcess colorize(kModelPath, kModelWidth, kModelHeight);
//初始化分类推理的acl资源, 模型和内存
Result ret = colorize.Init();
if (ret != SUCCESS) {
ERROR_LOG("Classification Init resource failed");
return FAILED;
}
//获取图片目录下所有的图片文件名
string inputImageDir = string(argv[1]);
vector<string> fileVec;
Utils::GetAllFiles(inputImageDir, fileVec);
if (fileVec.empty()) {
ERROR_LOG("Failed to deal all empty path=%s.", inputImageDir.c_str());
return FAILED;
}
//逐张图片推理
for (string imageFile : fileVec) {
//预处理图片:读取图片,讲图片缩放到模型输入要求的尺寸
Result ret = colorize.Preprocess(imageFile);
if (ret != SUCCESS) {
ERROR_LOG("Read file %s failed, continue to read next",
imageFile.c_str());
continue;
}
//将预处理的图片送入模型推理,并获取推理结果
aclmdlDataset* inferenceOutput = nullptr;
ret = colorize.Inference(inferenceOutput);
if ((ret != SUCCESS) || (inferenceOutput == nullptr)) {
ERROR_LOG("Inference model inference output data failed");
return FAILED;
}
//解析推理输出,并将推理得到的物体类别标记到图片上
ret = colorize.Postprocess(imageFile, inferenceOutput);
if (ret != SUCCESS) {
ERROR_LOG("Process model inference output data failed");
return FAILED;
}
}
INFO_LOG("Execute sample success");
return SUCCESS;
}
+238
View File
@@ -0,0 +1,238 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* File model_process.cpp
* Description: handle model process
*/
#include "model_process.h"
#include <iostream>
#include "utils.h"
using namespace std;
ModelProcess::ModelProcess():loadFlag_(false), modelId_(0), modelMemPtr_(nullptr), modelMemSize_(0),
modelWeightPtr_(nullptr),modelWeightSize_(0), modelDesc_(nullptr), input_(nullptr), output_(nullptr) {
}
ModelProcess::~ModelProcess() {
Unload();
DestroyDesc();
DestroyInput();
DestroyOutput();
}
Result ModelProcess::LoadModelFromFileWithMem(const char *modelPath) {
if (loadFlag_) {
ERROR_LOG("has already loaded a model");
return FAILED;
}
aclError ret = aclmdlQuerySize(modelPath, &modelMemSize_, &modelWeightSize_);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("query model failed, model file is %s", modelPath);
return FAILED;
}
ret = aclrtMalloc(&modelMemPtr_, modelMemSize_, ACL_MEM_MALLOC_HUGE_FIRST);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("malloc buffer for mem failed, require size is %zu", modelMemSize_);
return FAILED;
}
ret = aclrtMalloc(&modelWeightPtr_, modelWeightSize_, ACL_MEM_MALLOC_HUGE_FIRST);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("malloc buffer for weight failed, require size is %zu", modelWeightSize_);
return FAILED;
}
ret = aclmdlLoadFromFileWithMem(modelPath, &modelId_, modelMemPtr_,
modelMemSize_, modelWeightPtr_, modelWeightSize_);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("load model from file failed, model file is %s", modelPath);
return FAILED;
}
loadFlag_ = true;
INFO_LOG("load model %s success", modelPath);
return SUCCESS;
}
Result ModelProcess::CreateDesc() {
modelDesc_ = aclmdlCreateDesc();
if (modelDesc_ == nullptr) {
ERROR_LOG("create model description failed");
return FAILED;
}
aclError ret = aclmdlGetDesc(modelDesc_, modelId_);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("get model description failed");
return FAILED;
}
INFO_LOG("create model description success");
return SUCCESS;
}
void ModelProcess::DestroyDesc() {
if (modelDesc_ != nullptr) {
(void)aclmdlDestroyDesc(modelDesc_);
modelDesc_ = nullptr;
}
}
Result ModelProcess::CreateInput(void *inputDataBuffer, size_t bufferSize) {
input_ = aclmdlCreateDataset();
if (input_ == nullptr) {
ERROR_LOG("can't create dataset, create input failed");
return FAILED;
}
aclDataBuffer* inputData = aclCreateDataBuffer(inputDataBuffer, bufferSize);
if (inputData == nullptr) {
ERROR_LOG("can't create data buffer, create input failed");
return FAILED;
}
aclError ret = aclmdlAddDatasetBuffer(input_, inputData);
if (inputData == nullptr) {
ERROR_LOG("can't add data buffer, create input failed");
aclDestroyDataBuffer(inputData);
inputData = nullptr;
return FAILED;
}
return SUCCESS;
}
void ModelProcess::DestroyInput() {
if (input_ == nullptr) {
return;
}
for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(input_); ++i) {
aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(input_, i);
aclDestroyDataBuffer(dataBuffer);
}
aclmdlDestroyDataset(input_);
input_ = nullptr;
}
Result ModelProcess::CreateOutput() {
if (modelDesc_ == nullptr) {
ERROR_LOG("no model description, create ouput failed");
return FAILED;
}
output_ = aclmdlCreateDataset();
if (output_ == nullptr) {
ERROR_LOG("can't create dataset, create output failed");
return FAILED;
}
size_t outputSize = aclmdlGetNumOutputs(modelDesc_);
for (size_t i = 0; i < outputSize; ++i) {
size_t buffer_size = aclmdlGetOutputSizeByIndex(modelDesc_, i);
void *outputBuffer = nullptr;
aclError ret = aclrtMalloc(&outputBuffer, buffer_size, ACL_MEM_MALLOC_NORMAL_ONLY);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("can't malloc buffer, size is %zu, create output failed", buffer_size);
return FAILED;
}
aclDataBuffer* outputData = aclCreateDataBuffer(outputBuffer, buffer_size);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("can't create data buffer, create output failed");
aclrtFree(outputBuffer);
return FAILED;
}
ret = aclmdlAddDatasetBuffer(output_, outputData);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("can't add data buffer, create output failed");
aclrtFree(outputBuffer);
aclDestroyDataBuffer(outputData);
return FAILED;
}
}
INFO_LOG("create model output success");
return SUCCESS;
}
void ModelProcess::DestroyOutput() {
if (output_ == nullptr) {
return;
}
for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(output_); ++i) {
aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(output_, i);
void* data = aclGetDataBufferAddr(dataBuffer);
(void)aclrtFree(data);
(void)aclDestroyDataBuffer(dataBuffer);
}
(void)aclmdlDestroyDataset(output_);
output_ = nullptr;
}
Result ModelProcess::Execute() {
aclError ret = aclmdlExecute(modelId_, input_, output_);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("execute model failed, modelId is %u", modelId_);
return FAILED;
}
INFO_LOG("model execute success");
return SUCCESS;
}
void ModelProcess::Unload() {
if (!loadFlag_) {
return;
}
aclError ret = aclmdlUnload(modelId_);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("unload model failed, modelId is %u", modelId_);
}
if (modelDesc_ != nullptr) {
(void)aclmdlDestroyDesc(modelDesc_);
modelDesc_ = nullptr;
}
if (modelMemPtr_ != nullptr) {
aclrtFree(modelMemPtr_);
modelMemPtr_ = nullptr;
modelMemSize_ = 0;
}
if (modelWeightPtr_ != nullptr) {
aclrtFree(modelWeightPtr_);
modelWeightPtr_ = nullptr;
modelWeightSize_ = 0;
}
loadFlag_ = false;
INFO_LOG("unload model success, modelId is %u", modelId_);
}
aclmdlDataset *ModelProcess::GetModelOutputData() {
return output_;
}
+136
View File
@@ -0,0 +1,136 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* File utils.cpp
* Description: handle file operations
*/
#include "utils.h"
#include <map>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <cstring>
#include <dirent.h>
#include <vector>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "acl/acl.h"
using namespace std;
namespace {
const std::string kImagePathSeparator = ",";
const int kStatSuccess = 0;
const std::string kFileSperator = "/";
const std::string kPathSeparator = "/";
// output image prefix
const std::string kOutputFilePrefix = "out_";
}
bool Utils::IsDirectory(const string &path) {
// get path stat
struct stat buf;
if (stat(path.c_str(), &buf) != kStatSuccess) {
return false;
}
// check
if (S_ISDIR(buf.st_mode)) {
return true;
} else {
return false;
}
}
bool Utils::IsPathExist(const string &path) {
ifstream file(path);
if (!file) {
return false;
}
return true;
}
void Utils::SplitPath(const string &path, vector<string> &path_vec) {
char *char_path = const_cast<char*>(path.c_str());
const char *char_split = kImagePathSeparator.c_str();
char *tmp_path = strtok(char_path, char_split);
while (tmp_path) {
path_vec.emplace_back(tmp_path);
tmp_path = strtok(nullptr, char_split);
}
}
void Utils::GetAllFiles(const string &path, vector<string> &file_vec) {
// split file path
vector<string> path_vector;
SplitPath(path, path_vector);
for (string every_path : path_vector) {
// check path exist or not
if (!IsPathExist(path)) {
ERROR_LOG("Failed to deal path=%s. Reason: not exist or can not access.",
every_path.c_str());
continue;
}
// get files in path and sub-path
GetPathFiles(every_path, file_vec);
}
}
void Utils::GetPathFiles(const string &path, vector<string> &file_vec) {
struct dirent *dirent_ptr = nullptr;
DIR *dir = nullptr;
if (IsDirectory(path)) {
dir = opendir(path.c_str());
while ((dirent_ptr = readdir(dir)) != nullptr) {
// skip . and ..
if (dirent_ptr->d_name[0] == '.') {
continue;
}
// file path
string full_path = path + kPathSeparator + dirent_ptr->d_name;
// directory need recursion
if (IsDirectory(full_path)) {
GetPathFiles(full_path, file_vec);
} else {
// put file
file_vec.emplace_back(full_path);
}
}
}
else {
file_vec.emplace_back(path);
}
}
void* Utils::CopyDataDeviceToHost(void* deviceData, uint32_t dataSize) {
void* hostPtr = nullptr;
aclError aclRet = aclrtMalloc(&hostPtr, dataSize, ACL_MEM_MALLOC_HUGE_FIRST);
if (aclRet != ACL_ERROR_NONE) {
ERROR_LOG("malloc host data buffer failed, aclRet is %d", aclRet);
return nullptr;
}
aclRet = aclrtMemcpy(hostPtr, dataSize, deviceData, dataSize, ACL_MEMCPY_DEVICE_TO_DEVICE);
if (aclRet != ACL_ERROR_NONE) {
ERROR_LOG("aclrtMemcpy device to host failed, aclRet is %d", aclRet);
(void)aclrtFree(hostPtr);
return nullptr;
}
return hostPtr;
}