深度学习实战:ResNet原理与昇腾C++实践
本文提供了ResNet在昇腾平台上C++推理的完整实现方案,涵盖从原理到代码的各个环节,为深度学习模型部署提供实用参考。025年昇腾CANN训练营第二季,基于CANN开源开放全场景,推出0基础入门系列、码力全开特辑、开发者案例等专题课程,助力不同阶段开发者快速提升算子开发技能。获得Ascend C算子中级认证,即可领取精美证书,完成社区任务更有机会赢取华为手机,平板、开发板等大奖。报名链接:htt
本文简要介绍ResNet核心原理,并展示在昇腾平台上使用C++实现模型推理的完整流程。
ResNet核心原理
ResNet(残差网络)通过引入残差块和跳跃连接,解决了深度网络训练中的梯度消失问题。
残差学习思想:让网络学习目标映射与输入之间的残差F(x) = H(x) - x,而不是直接学习目标映射H(x)。
昇腾平台C++推理实现
环境准备
bash
export DDK_PATH=/usr/local/Ascend/ascend-toolkit/latest
export NPU_HOST_LIB=$DDK_PATH/runtime/lib64/stub
完整代码实现
cpp
#include "acl/acl.h"
#include <iostream>
#include <fstream>
#include <map>
using namespace std;
// 全局变量
int32_t deviceId = 0;
uint32_t modelId;
size_t pictureDataSize = 0;
void* pictureHostData = nullptr;
void* pictureDeviceData = nullptr;
// 初始化资源
void InitResource()
{
aclError ret = aclInit(nullptr);
if (ret != ACL_SUCCESS) {
std::cerr << "Failed to init ACL" << std::endl;
return;
}
ret = aclrtSetDevice(deviceId);
if (ret != ACL_SUCCESS) {
std::cerr << "Failed to set device" << std::endl;
return;
}
}
// 加载模型
void LoadModel(const char* modelPath)
{
aclError ret = aclmdlLoadFromFile(modelPath, &modelId);
if (ret != ACL_SUCCESS) {
std::cerr << "Failed to load model" << std::endl;
return;
}
}
// 加载图片数据
void LoadPicture(const char* picturePath)
{
// 读取图片到Host内存
ifstream binFile(picturePath, ifstream::binary);
if (!binFile.is_open()) {
std::cerr << "Failed to open picture file" << std::endl;
return;
}
binFile.seekg(0, binFile.end);
pictureDataSize = binFile.tellg();
binFile.seekg(0, binFile.beg);
aclError ret = aclrtMallocHost(&pictureHostData, pictureDataSize);
if (ret != ACL_SUCCESS) {
std::cerr << "Failed to malloc host memory" << std::endl;
return;
}
binFile.read(static_cast<char*>(pictureHostData), pictureDataSize);
binFile.close();
// 复制到Device内存
ret = aclrtMalloc(&pictureDeviceData, pictureDataSize, ACL_MEM_MALLOC_HUGE_FIRST);
if (ret != ACL_SUCCESS) {
std::cerr << "Failed to malloc device memory" << std::endl;
return;
}
ret = aclrtMemcpy(pictureDeviceData, pictureDataSize,
pictureHostData, pictureDataSize,
ACL_MEMCPY_HOST_TO_DEVICE);
if (ret != ACL_SUCCESS) {
std::cerr << "Failed to copy data to device" << std::endl;
}
}
// 执行推理
void Inference()
{
aclmdlDesc* modelDesc = aclmdlCreateDesc();
aclError ret = aclmdlGetDesc(modelDesc, modelId);
if (ret != ACL_SUCCESS) {
std::cerr << "Failed to get model description" << std::endl;
return;
}
// 准备输入
aclmdlDataset* inputDataset = aclmdlCreateDataset();
aclDataBuffer* inputData = aclCreateDataBuffer(pictureDeviceData, pictureDataSize);
aclmdlAddDatasetBuffer(inputDataset, inputData);
// 准备输出
aclmdlDataset* outputDataset = aclmdlCreateDataset();
size_t outputSize = aclmdlGetOutputSizeByIndex(modelDesc, 0);
void* outputDeviceBuffer = nullptr;
aclrtMalloc(&outputDeviceBuffer, outputSize, ACL_MEM_MALLOC_HUGE_FIRST);
aclDataBuffer* outputData = aclCreateDataBuffer(outputDeviceBuffer, outputSize);
aclmdlAddDatasetBuffer(outputDataset, outputData);
// 执行推理
ret = aclmdlExecute(modelId, inputDataset, outputDataset);
if (ret != ACL_SUCCESS) {
std::cerr << "Failed to execute model" << std::endl;
}
// 处理输出结果
void* outputHostBuffer = nullptr;
aclrtMallocHost(&outputHostBuffer, outputSize);
// 这里简化处理,实际需要从Device复制结果到Host
// 并解析分类结果
// 释放资源
aclmdlDestroyDataset(inputDataset);
aclmdlDestroyDataset(outputDataset);
aclmdlDestroyDesc(modelDesc);
}
// 资源清理
void DestroyResource()
{
if (pictureDeviceData != nullptr) {
aclrtFree(pictureDeviceData);
}
if (pictureHostData != nullptr) {
aclrtFreeHost(pictureHostData);
}
aclmdlUnload(modelId);
aclrtResetDevice(deviceId);
aclFinalize();
}
int main()
{
// 完整推理流程
InitResource();
LoadModel("../model/resnet50.om");
LoadPicture("../data/test_image.bin");
Inference();
DestroyResource();
return 0;
}
CMakeLists.txt
cmake
make_minimum_required(VERSION 3.10)
project(ResNetInference)
set(CMAKE_CXX_STANDARD 11)
include_directories(/usr/local/Ascend/ascend-toolkit/latest/include)
link_directories(/usr/local/Ascend/ascend-toolkit/latest/runtime/lib64/stub)
add_executable(main main.cpp)
target_link_libraries(main ascendcl stdc++)
关键要点
-
初始化流程:ACL初始化 → 设置设备 → 加载模型
-
数据处理:Host内存申请 → 数据读取 → Device内存复制
-
推理执行:准备输入输出 → 执行模型 → 处理结果
-
资源清理:内存释放 → 模型卸载 → ACL去初始化
总结
本文提供了ResNet在昇腾平台上C++推理的完整实现方案,涵盖从原理到代码的各个环节,为深度学习模型部署提供实用参考。
025年昇腾CANN训练营第二季,基于CANN开源开放全场景,推出0基础入门系列、码力全开特辑、开发者案例等专题课程,助力不同阶段开发者快速提升算子开发技能。获得Ascend C算子中级认证,即可领取精美证书,完成社区任务更有机会赢取华为手机,平板、开发板等大奖。
报名链接:https://www.hiascend.com/developer/activities/cann20252
注:实际使用时请根据具体模型调整数据预处理和后处理逻辑。
更多推荐


所有评论(0)