OpenVINO 2021r2 - Remote Blob API of GPU Plugin 示例复现(一) OpenCL Kernel Execution on a Shared Buffer

本文主要是介绍OpenVINO 2021r2 - Remote Blob API of GPU Plugin 示例复现(一) OpenCL Kernel Execution on a Shared Buffer,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前一阵尝试了一下OpenVINO纯GPU推理的代码实现, 主要复现了OpenVINO官方文档Remote Blob API of GPU Plugin 中的 OpenCL Kernel Execution on a Shared Buffer例子

官方示例的完整实现可以具体参考这篇文章 OpenVINO 2020r3 体验GPU Remote Blob API

 

在代码里,把OpenVINO clDNN的cl::context提取出来,再基于这个context创建了cl::device和cl::queue.

然后基于这个cl::context创建了一个cl::Buffer (就是cl_mem对象), 再将这个cl::Buffer 用gpu::make_shared_blob把Buffer转换成了Inference Engine能识别的内存Blob,

最后通过 InferRequest::SetBlob将这个Blob和推理网络的输入层连在一起,这个在inf_req_shared.Infer()的时候就会在读取输入层数据的时候从这个Blob的cl::Buffer里读取数据,这样就完成了从GPU显存(OpenCL cl_mem对象)里读取输入数据

 

上次的这段代码主要参考自OV源码库的openvino-master\inference-engine\tests\functional\plugin\gpu\remote_blob_tests\cldnn_remote_blob_tests.cpp里面。这次基于OpenVINO 2021r2把这段代码补全一下,将上图中的“OpenVINO GPU推理”的输出部分的数据也存放到cl_mem对象里,这样推理结束后就可以基于这个cl_mem对象用自己的OpenCL代码来实现基于GPU的数据后处理,避免使用CPU将数据读取到系统内存中再拷回显存的开销。 这个例子叫 OpenCL Kernel Execution on a Shared Buffer and Output to a Shared Buffer :)

 

GPU RemoteBlob API推理代码的实现

// inference using remote blobauto inf_req_shared = executable_network.CreateInferRequest();// obtain the RemoteContext pointer from the executable network object//从ExecutableNetwork中获取cldnn的cl_contextauto cldnn_context = executable_network.GetContext();cl_context ctx = std::dynamic_pointer_cast<gpu::ClContext>(cldnn_context)->get();cl::Context _context;cl::Device _device;cl::CommandQueue _queue;// user-supplied context handle// 基于这个cl_context创建cl::Context/Device/Queue_context = cl::Context(ctx, true);_device = cl::Device(_context.getInfo<CL_CONTEXT_DEVICES>()[0].get(), true);cl_command_queue_properties props = CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE;_queue = cl::CommandQueue(_context, _device, props);auto dims = network.getInputsInfo().begin()->second->getTensorDesc().getDims();size_t imSize = dims[1] * dims[2] * dims[3];cout << "imSize = " << imSize << " dims[1]=" << dims[1] << " dims[2]=" << dims[2] << " dims[3]=" << dims[3] << endl << endl;size_t num_channels = dims[1];size_t image_size = dims[3] * dims[2];//prepare input image data/** Iterate over all pixel in image (b,g,r) **///将输入图像的RGB数据放到ImageBuffer里unsigned char *ImageBuffer;ImageBuffer = (unsigned char *)malloc(imSize);unsigned char* pixels = (unsigned char*)(jpg.data);for (size_t pid = 0; pid < image_size; pid++) {/** Iterate over all channels **/for (size_t ch = 0; ch < num_channels; ++ch) {/**          [images stride + channels stride + pixel id ] all in bytes            **/ImageBuffer[ch * image_size + pid] = pixels[pid*num_channels + ch];//set input data to 0//ImageBuffer[ch * image_size + pid] = 0;}}//创建cl::Buffer shared_buffer作为输入Buffer,并将ImageBuffer的数据放入shared_buffer内cl_int err;cl::Buffer shared_buffer(_context, CL_MEM_READ_WRITE, imSize, NULL, &err);{void *buffer = ImageBuffer;_queue.enqueueWriteBuffer(shared_buffer, true, 0, imSize, buffer);}//将cl::Buffer封装进InferenceEngine::BlobBlob::Ptr shared_blob = gpu::make_shared_blob(network.getInputsInfo().begin()->second->getTensorDesc(), cldnn_context,shared_buffer);//将网络输入层的数据指针指向存有输入图像RGB值的Blobinf_req_shared.SetBlob(network.getInputsInfo().begin()->first, shared_blob);//这里创建2个内存块, 块大小和推理网络输出层的数据块大小一致//SqueezeNet输出是1000个FP32的值,所以每个块的大小为4KB//块的大小可以通过getOutputsInfo()来获取,这里偷懒,手工写成4KB//C[]全填0,用来将推理输出层的Blob全清0; D[]用来存放从推理输出的cl::Buffer中读取的数据size_t outputSize = 1000 * 4;float *C = new float[1000];float *D = new float[1000];for (int i = 0; i < 1000; i++){C[i] = 0;D[i] = 0;}//创建cl::Buffer shared_output_buffer作为输出Buffer,并将输出Buffer清0cl::Buffer shared_output_buffer(_context, CL_MEM_READ_WRITE, outputSize, NULL, &err);{void *buffer = ImageBuffer;_queue.enqueueWriteBuffer(shared_output_buffer, true, 0, sizeof(float)*1000, C);}//将cl::Buffer封装进InferenceEngine::Blob shared_output_blobBlob::Ptr shared_output_blob = gpu::make_shared_blob(network.getOutputsInfo().begin()->second->getTensorDesc(), cldnn_context,shared_output_buffer);//将网络输出层的数据指针指向shared_output_blobinf_req_shared.SetBlob(network.getOutputsInfo().begin()->first, shared_output_blob);inf_req_shared.Infer();// Copy the output data back to the host//将shared_output_buffer内的数据读到D[]中_queue.enqueueReadBuffer(shared_output_buffer, CL_TRUE, 0, sizeof(float) * 1000, D);//这里只打印每个class的confidence大于0.0001的class的信息for (int i = 0; i < 1000; i++){if (D[i] > 0.0001){cout << "C[" << i << "] = " << C[i] << " - D[" << i << "] = " << D[i] << endl;}}//输出数据在调用Infer()的时候已经放到shared_output_blob里了, 所以不需要通过调用GetBlob获得输出数据//auto outputBlob_shared = inf_req_shared.GetBlob(network.getOutputsInfo().begin()->first);free(ImageBuffer);if (C != NULL){delete C;}if (D != NULL){delete D;}//cout << "Processing output shared blobs" << endl;//ClassificationResult classificationResult_shared(outputBlob_shared, validImageNames,//	batchSize, FLAGS_nt,//	labels);//classificationResult_shared.print();

 

运行程序,可以得到结果

输出数据放在cl::Buffer shared_output_blob->shared_output_buffer中,这里偷懒了, 没有做输出数据的排序,而是输出了每个class分类confidence>0.0001的所有类的index和confidence

可以看到

top 1是 D[817] = 0.6386719

top 2是 D[479] = 0.2141113

top 3是 D[511] = 0.1010742

和前半部分的GPU标准推理流程的输出一致。

classid probability label
------- ----------- -----
817     0.6386719   sports car, sport car
479     0.2141113   car wheel
511     0.1010742   convertible
436     0.0251923   beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon
751     0.0065804   racer, race car, racing car
656     0.0047264   minivan
717     0.0031071   pickup, pickup truck
581     0.0026569   grille, radiator grille
468     0.0014210   cab, hack, taxi, taxicab
661     0.0010548   Model T

 

整个流程的实现顺序如图

个人感受:

Remote Blob API主要用在OpenVINO GPU推理与其他GPU加速代码的集成这种场景。在OpenCL Kernel Execution on a Shared Buffer的例子里,OCL的context是从OpenVINO的ExecutableNetwork里获取的,所以必须要先创建OV的对象,再在这个基础上添加运行自己的OCL的处理代码,个人感觉比较适合从零开始开发自己的AI推理项目,或者只用OCL做推理前后数据的预处理和后处理的评估预研这种场景。如果要是把OpenVINO集成到自己已经有的OpenCL项目里,可能就需要官网文档里提到的另一种方法(Running GPU Plugin Inference within User-Supplied Shared Context)了。

PS: 因为我不是很懂OCL的开发, 所以以上为纯个人感受,欢迎拍砖 :P

 

最后完整项目奉上,仅供参考

https://gitee.com/tisandman/cl_ov_sharing

 

 

 

这篇关于OpenVINO 2021r2 - Remote Blob API of GPU Plugin 示例复现(一) OpenCL Kernel Execution on a Shared Buffer的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/301005

相关文章

Python如何去除图片干扰代码示例

《Python如何去除图片干扰代码示例》图片降噪是一个广泛应用于图像处理的技术,可以提高图像质量和相关应用的效果,:本文主要介绍Python如何去除图片干扰的相关资料,文中通过代码介绍的非常详细,... 目录一、噪声去除1. 高斯噪声(像素值正态分布扰动)2. 椒盐噪声(随机黑白像素点)3. 复杂噪声(如伪

Java Spring ApplicationEvent 代码示例解析

《JavaSpringApplicationEvent代码示例解析》本文解析了Spring事件机制,涵盖核心概念(发布-订阅/观察者模式)、代码实现(事件定义、发布、监听)及高级应用(异步处理、... 目录一、Spring 事件机制核心概念1. 事件驱动架构模型2. 核心组件二、代码示例解析1. 事件定义

python使用库爬取m3u8文件的示例

《python使用库爬取m3u8文件的示例》本文主要介绍了python使用库爬取m3u8文件的示例,可以使用requests、m3u8、ffmpeg等库,实现获取、解析、下载视频片段并合并等步骤,具有... 目录一、准备工作二、获取m3u8文件内容三、解析m3u8文件四、下载视频片段五、合并视频片段六、错误

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

mysql中insert into的基本用法和一些示例

《mysql中insertinto的基本用法和一些示例》INSERTINTO用于向MySQL表插入新行,支持单行/多行及部分列插入,下面给大家介绍mysql中insertinto的基本用法和一些示例... 目录基本语法插入单行数据插入多行数据插入部分列的数据插入默认值注意事项在mysql中,INSERT I

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

LiteFlow轻量级工作流引擎使用示例详解

《LiteFlow轻量级工作流引擎使用示例详解》:本文主要介绍LiteFlow是一个灵活、简洁且轻量的工作流引擎,适合用于中小型项目和微服务架构中的流程编排,本文给大家介绍LiteFlow轻量级工... 目录1. LiteFlow 主要特点2. 工作流定义方式3. LiteFlow 流程示例4. LiteF

MyBatis ResultMap 的基本用法示例详解

《MyBatisResultMap的基本用法示例详解》在MyBatis中,resultMap用于定义数据库查询结果到Java对象属性的映射关系,本文给大家介绍MyBatisResultMap的基本... 目录MyBATis 中的 resultMap1. resultMap 的基本语法2. 简单的 resul