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中yield的用法和实际应用示例

《Python中yield的用法和实际应用示例》在Python中,yield关键字主要用于生成器函数(generatorfunctions)中,其目的是使函数能够像迭代器一样工作,即可以被遍历,但不会... 目录python中yield的用法详解一、引言二、yield的基本用法1、yield与生成器2、yi

MyBatis-Plus 与 Spring Boot 集成原理实战示例

《MyBatis-Plus与SpringBoot集成原理实战示例》MyBatis-Plus通过自动配置与核心组件集成SpringBoot实现零配置,提供分页、逻辑删除等插件化功能,增强MyBa... 目录 一、MyBATis-Plus 简介 二、集成方式(Spring Boot)1. 引入依赖 三、核心机制

MySQL设置密码复杂度策略的完整步骤(附代码示例)

《MySQL设置密码复杂度策略的完整步骤(附代码示例)》MySQL密码策略还可能包括密码复杂度的检查,如是否要求密码包含大写字母、小写字母、数字和特殊字符等,:本文主要介绍MySQL设置密码复杂度... 目录前言1. 使用 validate_password 插件1.1 启用 validate_passwo

springboot整合mqtt的步骤示例详解

《springboot整合mqtt的步骤示例详解》MQTT(MessageQueuingTelemetryTransport)是一种轻量级的消息传输协议,适用于物联网设备之间的通信,本文介绍Sprin... 目录1、引入依赖包2、yml配置3、创建配置4、自定义注解6、使用示例使用场景:mqtt可用于消息发

Go中select多路复用的实现示例

《Go中select多路复用的实现示例》Go的select用于多通道通信,实现多路复用,支持随机选择、超时控制及非阻塞操作,建议合理使用以避免协程泄漏和死循环,感兴趣的可以了解一下... 目录一、什么是select基本语法:二、select 使用示例示例1:监听多个通道输入三、select的特性四、使用se

MySQL实现多源复制的示例代码

《MySQL实现多源复制的示例代码》MySQL的多源复制允许一个从服务器从多个主服务器复制数据,这在需要将多个数据源汇聚到一个数据库实例时非常有用,下面就来详细的介绍一下,感兴趣的可以了解一下... 目录一、多源复制原理二、多源复制配置步骤2.1 主服务器配置Master1配置Master2配置2.2 从服

Python中的sort()和sorted()用法示例解析

《Python中的sort()和sorted()用法示例解析》本文给大家介绍Python中list.sort()和sorted()的使用区别,详细介绍其参数功能及Timsort排序算法特性,涵盖自适应... 目录一、list.sort()参数说明常用内置函数基本用法示例自定义函数示例lambda表达式示例o

SpringBoot集成P6Spy的实现示例

《SpringBoot集成P6Spy的实现示例》本文主要介绍了SpringBoot集成P6Spy的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录本节目标P6Spy简介抛出问题集成P6Spy1. SpringBoot三板斧之加入依赖2. 修改

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

Python开发简易网络服务器的示例详解(新手入门)

《Python开发简易网络服务器的示例详解(新手入门)》网络服务器是互联网基础设施的核心组件,它本质上是一个持续运行的程序,负责监听特定端口,本文将使用Python开发一个简单的网络服务器,感兴趣的小... 目录网络服务器基础概念python内置服务器模块1. HTTP服务器模块2. Socket服务器模块