【MindStudio训练营第一季】MindStudio AscendCL开发应用篇
本文使用YOLOV3进行目标检测,同时使用DVPP进行JPEG解码和缩放,使用AIPP进行色域转换和归一化。
操作过程
下载模型并同步文件
首先根据README中的链接下载模型文件和权重文件,放置在model
文件夹下,同时配置远程服务器ssh链接,同步工程文件。
模型转换
利用ATC转为om
模型。
编译文件
在编译之前,需要配置环境,可参考昇腾AI设备安装开发环境修改.bashrc
和安装opencv等。
添加构建配置,进行构建:
执行
配置并执行
实验结果
输入 | 输出 |
---|---|
代码分析
文件目录
1 | . |
main
1 | int main() |
sampleProcess
sampleProcess.InitResource()
准备运行环境
1 | // 创建ACL并初始化 |
sampleProcess.Process()
整个过程的大概处理流程如下:
初始化DVPP -> 加载模型 -> 输入图片 -> 预处理 -> 推理 -> 获取输出 -> 后处理
modelProcess
主要负责与模型相关的操作,如加载、创建输入输出、推理等
dvppProcess
是与DVPP处理相关,如图像解码、缩放等。
1 | // DVPP |
sampleProcess.Postprocess()
1 | uint32_t dataSize = 0; |
ModelProcess
modelProcess.LoadModel()
1 | // 获取模型尺寸 |
modelProcess.Execute()
在执行之前还有一系列准备工作
获取模型描述 -> 创建输出并分配内存 -> 获取模型输入宽高 -> 将图片信息移动到Device上 -> 读取图片并经过DVPP处理 -> 创建模型输入 -> 执行
-
modelProcess.CreateDesc()
1
2
3
4
5
6Result ModelProcess::CreateDesc()
{
g_modelDesc_= aclmdlCreateDesc();
aclError ret = aclmdlGetDesc(g_modelDesc_, g_modelId_);
return SUCCESS;
} -
modelProcess.CreateOutput()
1
2
3
4
5
6
7
8
9
10
11
12
13Result ModelProcess::CreateOutput()
{
g_output_ = aclmdlCreateDataset();
size_t outputSize = aclmdlGetNumOutputs(g_modelDesc_);
for (size_t i = 0; i < outputSize; ++i) {
size_t modelOutputSize = aclmdlGetOutputSizeByIndex(g_modelDesc_, i);
void *outputBuffer = nullptr;
aclError ret = aclrtMalloc(&outputBuffer, modelOutputSize, ACL_MEM_MALLOC_NORMAL_ONLY);
aclDataBuffer *outputData = aclCreateDataBuffer(outputBuffer, modelOutputSize);
ret = aclmdlAddDatasetBuffer(g_output_, outputData);
}
return SUCCESS;
} -
modelProcess.GetModelInputWH()
1
2
3
4
5
6
7
8
9Result ModelProcess::GetModelInputWH(int &width, int &height)
{
aclmdlIODims dims; // NHWC
aclError ret = aclmdlGetInputDims(g_modelDesc_, 0, &dims);
width = dims.dims[2];
height = dims.dims[1];
INFO_LOG("model input width %d, input height %d", width, height);
return SUCCESS;
} -
CopyDataHostToDevice
1
2
3
4void* Utils::CopyDataHostToDevice(void* deviceData, uint32_t dataSize)
{
return CopyDataToDevice(deviceData, dataSize, ACL_MEMCPY_HOST_TO_DEVICE);
} -
dvppProcess
-
modelProcess.CreateInput()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19Result ModelProcess::CreateInput(void *input1, size_t input1Size, void *input2, size_t input2Size)
{
vector<DataInfo> inputData = {{input1, input1Size}, {input2, input2Size}};
uint32_t dataNum = aclmdlGetNumInputs(g_modelDesc_);
if (dataNum == 0) {
ERROR_LOG("Create input failed for no input data");
return FAILED;
}
g_input_ = aclmdlCreateDataset();
for (uint32_t i = 0; i < inputData.size(); i++) {
size_t modelInputSize = aclmdlGetInputSizeByIndex(g_modelDesc_, i);
aclDataBuffer *dataBuf = aclCreateDataBuffer(inputData[i].data, inputData[i].size);
aclError ret = aclmdlAddDatasetBuffer(g_input_, dataBuf);
}
INFO_LOG("create model input success");
return SUCCESS;
} -
modelProcess.Execute()
1
2
3
4
5Result ModelProcess::Execute()
{
aclError ret = aclmdlExecute(g_modelId_, g_input_, g_output_);
return SUCCESS;
}
DVPP
DVPP 在dvpp上执行的图像处理,主要流程为 初始化 -> 设置输入 -> 初始化输出参数 -> 执行 -> 获取输出
dvppProcess.InitResource()
创建通道描述信息 -> 创建通道 -> 缩放配置
1 | Result DvppProcess::InitResource() |
dvppProcess.SetInput()
1 | void DvppProcess::SetInput(void *inDevBuffer, uint32_t inDevBufferSize, const PicDesc &picDesc) |
dvppProcess.InitDvppOutputPara()
1 | Result DvppProcess::InitDvppOutputPara(int modelInputWidth, int modelInputHeight) |
dvppProcess.Process()
DVPP执行流程:初始化图片解码描述信息 -> JPEG图片解码 -> 初始化缩放输入与输出描述信息 -> 图片缩放 -> 销毁资源
1 | Result DvppProcess::Process() |
-
InitDecodeOutputDesc()
1
2
3
4
5
6
7
8
9Result DvppProcess::InitDecodeOutputDesc()
{
aclError ret = acldvppMalloc(&g_decodeOutDevBuffer_, g_jpegDecodeOutputSize_);
g_decodeOutputDesc_ = acldvppCreatePicDesc();
(void)acldvppSetPicDescData(g_decodeOutputDesc_, g_decodeOutDevBuffer_);
(void)acldvppSetPicDescFormat(g_decodeOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
(void)acldvppSetPicDescSize(g_decodeOutputDesc_, g_jpegDecodeOutputSize_);
return SUCCESS;
} -
ProcessDecode()
JPEG异步解码1
2
3
4
5
6
7
8
9
10
11Result DvppProcess::ProcessDecode()
{
aclError ret = acldvppJpegDecodeAsync(g_dvppChannelDesc_, g_inDevBuffer_, g_inDevBufferSize_, g_decodeOutputDesc_, g_stream_);
ret = aclrtSynchronizeStream(g_stream_);
g_decodeOutputWidth_ = acldvppGetPicDescWidth(g_decodeOutputDesc_);
g_decodeOutputHeight_ = acldvppGetPicDescHeight(g_decodeOutputDesc_);
g_decodeOutputWidthStride_ = acldvppGetPicDescWidthStride(g_decodeOutputDesc_);
return SUCCESS;
} -
InitResizeInputDesc()
创建输入图片描述并设置相应的值1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20Result DvppProcess::InitResizeInputDesc()
{
uint32_t jpegOutWidthStride = g_decodeOutputWidthStride_;
uint32_t jpegOutHeightStride = AlignSize(g_decodeOutputHeight_, 16);
uint32_t jpegOutBufferSize = jpegOutWidthStride * jpegOutHeightStride * 3 / 2;
g_resizeInputDesc_ = acldvppCreatePicDesc();
if (g_resizeInputDesc_ == nullptr) {
ERROR_LOG("InitResizeInputDesc failed");
return FAILED;
}
(void)acldvppSetPicDescData(g_resizeInputDesc_, g_decodeOutDevBuffer_);
(void)acldvppSetPicDescFormat(g_resizeInputDesc_, PIXEL_FORMAT_YVU_SEMIPLANAR_420);
(void)acldvppSetPicDescWidth(g_resizeInputDesc_, g_decodeOutputWidth_);
(void)acldvppSetPicDescHeight(g_resizeInputDesc_, g_decodeOutputHeight_);
(void)acldvppSetPicDescWidthStride(g_resizeInputDesc_, jpegOutWidthStride);
(void)acldvppSetPicDescHeightStride(g_resizeInputDesc_, jpegOutHeightStride);
(void)acldvppSetPicDescSize(g_resizeInputDesc_, jpegOutBufferSize);
return SUCCESS;
} -
InitResizeOutputDesc()
创建输出图片描述并设置相应的值1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17Result DvppProcess::InitResizeOutputDesc()
{
g_resizeOutputDesc_ = acldvppCreatePicDesc();
if (g_resizeOutputDesc_ == nullptr) {
ERROR_LOG("acldvppCreatePicDesc failed");
return FAILED;
}
(void)acldvppSetPicDescData(g_resizeOutputDesc_, g_resizeOutBufferDev_);
(void)acldvppSetPicDescFormat(g_resizeOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
(void)acldvppSetPicDescWidth(g_resizeOutputDesc_, g_modelInputWidth_);
(void)acldvppSetPicDescHeight(g_resizeOutputDesc_, g_modelInputHeight_);
(void)acldvppSetPicDescWidthStride(g_resizeOutputDesc_, g_resizeOutWidthStride_);
(void)acldvppSetPicDescHeightStride(g_resizeOutputDesc_, g_resizeOutHeightStride_);
(void)acldvppSetPicDescSize(g_resizeOutputDesc_, g_resizeOutBufferSize_);
return SUCCESS;
} -
ProcessResize()
异步缩放1
2
3
4
5
6
7
8Result DvppProcess::ProcessResize()
{
aclError ret = acldvppSetResizeConfigInterpolation(g_resizeConfig_, 0);
ret = acldvppVpcResizeAsync(g_dvppChannelDesc_, g_resizeInputDesc_,
g_resizeOutputDesc_, g_resizeConfig_, g_stream_);
ret = aclrtSynchronizeStream(g_stream_);
return SUCCESS;
}
dvppProcess.GetDvppOutput()
1 | void DvppProcess::GetDvppOutput(void **outputBuffer, int &outputSize) |
AIPP
运行在AICore上的图像处理,主要有色域转换(YUV->BGR
)和归一化
1 | aipp_op{ |
总结
本次复现了使用DVPP+AIPP的YOLOV3目标检测网络,对代码执行流程和AscendCL调用流程进行了分析,了解了使用MindStudio进行AscendCL开发的过程,相较于直接使用VSCode连接ECS开发ACL程序而言,MindStudio提供了可视化的模型转换界面,以及deployment、ssh等功能。