华为CANN训练营笔记——应用开发全流程 [4](with 代码版)

10 篇文章 5 订阅
6. main.cpp
# include <iostream>
# 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;
}
7. sample_process.cpp
# include <iostream>
# 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");
}


8. model_process.cpp

手动管理内存

# include <iostream>
# include "model_process.h"
# include <map>
# include <sstream>
# include <algorithm>
# 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");
}
9. utils.cpp
#include "utils.h"
#include <iostream>
#include <fstream>
#include <cstring>
#include "acl/acl.h"
#include <sys/stat.h>

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;
    }
}

1.5.5 编译&运行

下载模型文件.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

  • result
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值