# include
# include "sample_process.h"
# include "utils.h"
using namespace std;
bool g_isDevice = false; // 全局变量赋初值
int main(){
SampleProcess processSample;
Result ret = processSample.InitResource(); // 运行资源初始化
if (ret != SUCCESS){
ERROR_LOG("sample init resource failed");
return FAILED;
}
ret = processSample.Process();
if (ret != SUCCESS){
ERROR_LOG("sample process failed");
return FAILED;
}
INFO_LOG("execute sample success");
return SUCCESS;
}
# include
# include "sample_process.h"
# include "utils.h"
# include "model_process.h"
# include "acl/acl.h"
using namespace std;
extern bool g_isDevice;
// 构造方法,为三个成员变量赋初值
SampleProcess::SampleProcess() :deviceId_(0), context_(nullptr), stream_(nullptr)
{
}
// 析构
SampleProcess::~SampleProcess(){
DestroyResource();
}
// 初始化函数
Result SampleProcess::InitResource(){
// ACL初始化
const char *aclConfigPath = "../src/acl.json";
aclError ret = aclInit(aclConfigPath);
if (ret != ACL_ERROR_NONE){ // 判断初始化成功
ERROR_LOG("acl init 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("acl open device %d success", deviceId_);
// create context
ret = aclrtCreateContext(&context_, deviceId_);
if (ret != ACL_ERROR_NONE){
ERROR_LOG("acl create context failed");
return FAILED;
}
INFO_LOG("acl create contxt success");
// create stream
ret = aclrtCreateStream(&stream_);
if (ret != ACL_ERROR_NONE){
ERROR_LOG("acl create stream failed");
return FAILED;
}
INFO_LOG("acl create stream success");
// get run mode
aclrtRunMode runMode;
ret = aclrtGetRunMode(&runMode);
if (ret != ACL_ERROR_NONE){
ERROR_LOG("acl get run mode failed");
return FAILED;
}
g_isDevice = (runMode == ACL_DEVICE);
INFO_LOG("get run mode success");
return SUCCESS;
}
Result SampleProcess::Process(){
// 创建一个modelProcess对象, 这个类构造于model_process.cpp
ModelProcess processModel;
const char* omModelPath = "../model/resnet50.om"; // 模型文件路径
// 手动管理内存, 从文件加载模型
Result ret = processModel.LoadModelFromFileWithMem(omModelPath);
if (ret != SUCCESS){
ERROR_LOG("excute LoadModelFromFileWithMem failed");
return FAILED;
}
// 创建模型描述信息
ret = processModel.CreateDesc();
if (ret != SUCCESS) {
ERROR_LOG("execute CreateModelDesc failed");
return FAILED;
}
// 对于一个模型, 他的输出应该是固定的
ret = processModel.CreateOutput();
if (ret != SUCCESS) {
ERROR_LOG("execute CreateOutput failed");
return FAILED;
}
// =================
// 图片数据
// =================
string testFile[] = {
"../data/dog1_1024_683.bin",
"../data/dog2_1024_683.bin"
};
for (size_t index = 0; index < sizeof(testFile) / sizeof(testFile[0]); ++index) {
INFO_LOG("start to process file:%s", testFile[index].c_str());
// 处理模型
// 不同于resnet50_imageclassification工程; 这里将获取输入放在了循环里
uint32_t devBufferSize;
// 申请这个文件在device上的内存 并返回内存地址
void *picDevBuffer = Utils::GetDeviceBufferOfFile(testFile[index], devBufferSize);
if (picDevBuffer == nullptr){
ERROR_LOG("get pic device buffer failed, index is %zu", index);
return FAILED;
}
// 图片数据内存地址放入input
ret = processModel.CreateInput(picDevBuffer, devBufferSize);
if (ret != SUCCESS){
ERROR_LOG("get pic device buffer failed, index is %zu", index);
aclrtFree(picDevBuffer); // 失败及时销毁
return FAILED;
}
// 推理;结果保存在processModel的成员变量中
ret = processModel.Execute();
if (ret != SUCCESS){
ERROR_LOG("execute inference failed");
aclrtFree(picDevBuffer);
return FAILED;
}
processModel.OutputModelResult();
aclrtFree(picDevBuffer);
processModel.DestroyInput();
}
return SUCCESS;
}
void SampleProcess::DestroyResource()
{
// 销毁顺序:stream -> context -> device -> finalize
aclError ret;
if (stream_ != nullptr) {
ret = aclrtDestroyStream(stream_);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("destroy stream failed");
}
stream_ = nullptr;
}
INFO_LOG("end to destroy stream");
if (context_ != nullptr) {
ret = aclrtDestroyContext(context_);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("destroy context failed");
}
context_ = nullptr;
}
INFO_LOG("end to destroy context");
ret = aclrtResetDevice(deviceId_);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("reset device failed");
}
INFO_LOG("end to reset device %d", deviceId_);
ret = aclFinalize();
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("finalize acl failed");
}
INFO_LOG("end to finalize acl");
}
手动管理内存
# include
# include "model_process.h"
# include
# include
# include
# include "utils.h"
using namespace std;
extern bool g_isDevice;
// 构造函数 loadFlag_ 1表示模型已加载
ModelProcess::ModelProcess() :modelId_(0), modelMemSize_(0), modelWeightSize_(0), modelMemPtr_(nullptr), modelWeightPtr_(nullptr), loadFlag_(false), 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 mem of model file %s failed", modelPath);
return FAILED;
}
// 根据查询的模型内存大小分配空间
ret = aclrtMalloc(&modelMemPtr_, modelMemSize_, ACL_MEM_MALLOC_HUGE_FIRST);
if (ret != ACL_ERROR_NONE){
ERROR_LOG("malloc buffer for mem failed, required 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, required size is %zu", modelMemSize_);
return FAILED;
}
// 调用acl接口,从文件加载模型
ret = aclmdlLoadFromFileWithMem(modelPath, &modelId_, modelMemPtr_, modelMemSize_, modelWeightPtr_, modelWeightSize_);
if (ret != ACL_ERROR_NONE){
ERROR_LOG("load model from file %s failed", 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_SUCCESS) {
ERROR_LOG("get model description failed, modelId is %u", modelId_);
return FAILED;
}
INFO_LOG("create model description success");
return SUCCESS;
}
// 有了模型描述, 然后才可以创建输出
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) {
// 获取第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;
}
// 创建databuffer
aclDataBuffer *outputData = aclCreateDataBuffer(outputBuffer, buffer_size);
if (outputData == nullptr) {
ERROR_LOG("can't create data buffer, create output failed");
(void)aclrtFree(outputBuffer);
return FAILED;
}
// 将databuffer放入output dataset
ret = aclmdlAddDatasetBuffer(output_, outputData);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("can't add data buffer, create output failed");
// 如果失败,释放内存
(void)aclrtFree(outputBuffer);
(void)aclDestroyDataBuffer(outputData);
return FAILED;
}
}
INFO_LOG("create model output success");
return SUCCESS;
}
Result ModelProcess::CreateInput(void *inputDataBuffer, size_t bufferSize)
{
input_ = aclmdlCreateDataset();
if (input_ == nullptr) {
ERROR_LOG("can't create dataset, create input failed");
return FAILED;
}
// 创建databuffer
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 (ret != ACL_SUCCESS) {
ERROR_LOG("add input dataset buffer failed");
(void)aclDestroyDataBuffer(inputData);
inputData = nullptr;
return FAILED;
}
INFO_LOG("create model input success");
return SUCCESS;
}
Result ModelProcess::Execute()
{
// 推理,结果放入output中
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::OutputModelResult()
{
for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(output_); ++i) {
// 遍历output dataset里的data buffer
aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(output_, i);
void* data = aclGetDataBufferAddr(dataBuffer);
// uint32_t len = aclGetDataBufferSizeV2(dataBuffer);
uint32_t len = aclGetDataBufferSizeV2(dataBuffer);
void *outHostData = nullptr;
aclError ret = ACL_ERROR_NONE;
float *outData = nullptr;
if (!g_isDevice) { // 如果正在运行在HOST上,就需要把数据从Device上取回到HOST
aclError ret = aclrtMallocHost(&outHostData, len);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("aclrtMallocHost failed, ret[%d]", ret);
return;
}
// Device -> HOST
ret = aclrtMemcpy(outHostData, len, data, len, ACL_MEMCPY_DEVICE_TO_HOST);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("aclrtMemcpy failed, ret[%d]", ret);
(void)aclrtFreeHost(outHostData);
return;
}
outData = reinterpret_cast<float*>(outHostData);
} else {
outData = reinterpret_cast<float*>(data);
}
// 打印
map<float, unsigned int, greater<float> > resultMap;
for (unsigned int j = 0; j < len / sizeof(float); ++j) {
resultMap[*outData] = j;
outData++;
}
int cnt = 0;
for (auto it = resultMap.begin(); it != resultMap.end(); ++it) {
// print top 5
if (++cnt > 5) {
break;
}
INFO_LOG("top %d: index[%d] value[%lf]", cnt, it->second, it->first);
}
if (!g_isDevice) {
ret = aclrtFreeHost(outHostData);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("aclrtFreeHost failed, ret[%d]", ret);
return;
}
}
}
INFO_LOG("output data success");
return;
}
void ModelProcess::DestroyInput()
{
if (input_ == nullptr) {
return;
}
for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(input_); ++i) {
// 销毁所有的buffer
aclDataBuffer *dataBuffer = aclmdlGetDatasetBuffer(input_, i);
(void)aclDestroyDataBuffer(dataBuffer);
}
(void)aclmdlDestroyDataset(input_);
input_ = nullptr;
INFO_LOG("destroy model input success");
}
void ModelProcess::Unload()
{
if (!loadFlag_) {
WARN_LOG("no model had been loaded, unload failed");
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) {
(void)aclrtFree(modelMemPtr_);
modelMemPtr_ = nullptr;
modelMemSize_ = 0;
}
if (modelWeightPtr_ != nullptr) {
(void)aclrtFree(modelWeightPtr_);
modelWeightPtr_ = nullptr;
modelWeightSize_ = 0;
}
loadFlag_ = false;
INFO_LOG("unload model success, modelId is %u", modelId_);
}
void ModelProcess::DestroyDesc()
{
if (modelDesc_ != nullptr) {
(void)aclmdlDestroyDesc(modelDesc_);
modelDesc_ = nullptr;
}
INFO_LOG("destroy model description 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;
INFO_LOG("destroy model output success");
}
#include "utils.h"
#include
#include
#include
#include "acl/acl.h"
#include
extern bool g_isDevice;
void* Utils::ReadBinFile(std::string fileName, uint32_t &fileSize)
{
struct stat sBuf;
int fileStatus = stat(fileName.data(), &sBuf);
if (fileStatus == -1) {
ERROR_LOG("failed to get file");
return nullptr;
}
if (S_ISREG(sBuf.st_mode) == 0) {
ERROR_LOG("%s is not a file, please enter a file", fileName.c_str());
return nullptr;
}
std::ifstream binFile(fileName, std::ifstream::binary);
if (binFile.is_open() == false) {
ERROR_LOG("open file %s failed", fileName.c_str());
return nullptr;
}
binFile.seekg(0, binFile.end);
uint32_t binFileBufferLen = binFile.tellg();
if (binFileBufferLen == 0) {
ERROR_LOG("binfile is empty, filename is %s", fileName.c_str());
binFile.close();
return nullptr;
}
binFile.seekg(0, binFile.beg);
void* binFileBufferData = nullptr;
aclError ret = ACL_ERROR_NONE;
if (!g_isDevice) {
ret = aclrtMallocHost(&binFileBufferData, binFileBufferLen);
if (binFileBufferData == nullptr) {
ERROR_LOG("malloc binFileBufferData failed");
binFile.close();
return nullptr;
}
} else {
ret = aclrtMalloc(&binFileBufferData, binFileBufferLen, ACL_MEM_MALLOC_NORMAL_ONLY);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("malloc device buffer failed. size is %u", binFileBufferLen);
binFile.close();
return nullptr;
}
}
binFile.read(static_cast<char *>(binFileBufferData), binFileBufferLen);
binFile.close();
fileSize = binFileBufferLen;
return binFileBufferData;
}
void* Utils::GetDeviceBufferOfFile(std::string fileName, uint32_t &fileSize)
{
// 根据文件名及文件大小 返回模型内存地址
uint32_t inputHostBuffSize = 0;
void* inputHostBuff = Utils::ReadBinFile(fileName, inputHostBuffSize);
if (inputHostBuff == nullptr) {
return nullptr;
}
if (!g_isDevice) {
void *inBufferDev = nullptr;
uint32_t inBufferSize = inputHostBuffSize;
aclError ret = aclrtMalloc(&inBufferDev, inBufferSize, ACL_MEM_MALLOC_NORMAL_ONLY);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("malloc device buffer failed. size is %u", inBufferSize);
aclrtFreeHost(inputHostBuff);
return nullptr;
}
ret = aclrtMemcpy(inBufferDev, inBufferSize, inputHostBuff, inputHostBuffSize, ACL_MEMCPY_HOST_TO_DEVICE);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("memcpy failed. device buffer size is %u, input host buffer size is %u",
inBufferSize, inputHostBuffSize);
aclrtFree(inBufferDev);
aclrtFreeHost(inputHostBuff);
return nullptr;
}
aclrtFreeHost(inputHostBuff);
fileSize = inBufferSize;
return inBufferDev;
} else {
fileSize = inputHostBuffSize;
return inputHostBuff;
}
}
下载模型文件.prototxt
和.caffemodel
设置环境. /usr/local/Ascend/ascend-toolkit/set_env.sh
转换模型atc --model caffe_model/resnet50.prototxt --weight caffe_model/resnet50.caffemodel --framework 0 --output model/resnet50 --soc_version Ascend310 --input_format NCHW --input_fp16_nodes data --output_type FP32 --out_nodes prob:0
转换图片格式python3 ../scripts/transferPic.py
转到根目录下mkdir -p build/intermediates/host
编译cmake ../../../src/ -DCMAKE_CXX_COMPILER=g++ -DCMAKE_SKIP_RPATH=TRUE
make
转到生成的out目录下 ./main