OpenVINO 2021r2 - Remote Blob API of GPU Plugin 示例复现(二) Inference within User-Supplied Shared Contex

今天再试试官方文档Remote Blob API of GPU Plugin里面的另一个例子Running GPU Plugin Inference within User-Supplied Shared Context,大概的意思就是由用户提供自己的OpenCL context,OpenVINO的clDNN利用用户共享的context来跑inference (对应的场景应该是用户已经有了自己的OpenCL实现的应用,然后要把OpenVINO GPU推理功能集成进自己应用的场景)。

官网的例子只给出了一部分代码片段,看的云山雾罩的,但是有了前一次的经验,感觉实现起来并不难,大致就是利用用户OCL对象的context来转换成remote context,创建ExecuableNetwork的时候把remote context传进去,这样clDNN里面所有OCL的操作都会基于用户提供这个context, 而不会创建自己独立的context. 另外输入输出的数据共享可以通过shared blob把OV推理网络的输入和输出层的数据指向用户自己创建的cl_mem内存对象即可。

 

GPU RemoteBlob API推理代码的实现

        /********************* Init OpenCL Device ***************************************/
        //模拟3个用户从外面传进来的OpenCL对象(user_context,user_device,user_queue) 后面的
        //OpenVINO的IE clDNN都基于这个用户提供的OpenCL context来创建
        cl::Context user_context;
        cl::Device user_device;
        cl::CommandQueue user_queue;
 
        // get Intel iGPU OCL device, create context and queue
        {
            const unsigned int refVendorID = 0x8086;
            cl_uint n = 0;
            cl_int err = clGetPlatformIDs(0, NULL, &n);
 
            // Get platform list
            std::vector<cl_platform_id> platform_ids(n);
            err = clGetPlatformIDs(n, platform_ids.data(), NULL);
 
            for (auto& id : platform_ids) {
                cl::Platform platform = cl::Platform(id);
                std::vector<cl::Device> devices;
                platform.getDevices(CL_DEVICE_TYPE_GPU, &devices);
                for (auto& d : devices) {
                    if (refVendorID == d.getInfo<CL_DEVICE_VENDOR_ID>()) {
                        user_device = d;
                        user_context = cl::Context(user_device);
                        break;
                    }
                }
            }
            cl_command_queue_properties props = CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE;
            user_queue = cl::CommandQueue(user_context, user_device, props);
        }
 
 
...
 
        /*********** 开始演示OpenVINO Shared GPU context的用法 *******************/
        /* 使用这种方法 IE/clDNN初始化时不会自己创建新的OpenCL ctx, 而是基于用户提供的OCL ctx来创建 */
        //create remote context, 先基于用户的OCL ctx创建remote context
        auto remote_context = gpu::make_shared_context(ie, FLAGS_d, user_context.get());
 
        //创建shared execute network时, clDNN基于remote OCL context来初始化
        auto exec_net_shared = ie.LoadNetwork(network, remote_context);
 
        // inference using remote blob
        auto inf_req_shared = exec_net_shared.CreateInferRequest();
 
        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) **/
        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;
            }
        }
 
        //这里模拟用户自己的OCL ctx创建的一个cl::Buffer, 用来放推理的输入数据
        cl_int err;
        cl::Buffer shared_buffer(user_context, CL_MEM_READ_WRITE, imSize, NULL, &err);
        {
            void *buffer = ImageBuffer;
            user_queue.enqueueWriteBuffer(shared_buffer, true, 0, imSize, buffer);
        }
 
        //将这个cl::Buffer转成shared blob
        Blob::Ptr shared_blob = gpu::make_shared_blob(network.getInputsInfo().begin()->second->getTensorDesc(), remote_context,
            shared_buffer);
 
        //将推理网络的输入部分指向这个shared blob, 推理时会从这个blob里读数据
        inf_req_shared.SetBlob(network.getInputsInfo().begin()->first, shared_blob);
 
        //这里是已知用的是squeezenet, 输出是1000个FP32的数据,所以创建2个FP32 [1000]的数组
        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;
        }
 
        //这里模拟用户自己的OCL ctx创建的一个cl::Buffer, 用来放推理输出的数据
        cl::Buffer shared_output_buffer(user_context, CL_MEM_READ_WRITE, outputSize, NULL, &err);
        {
            void *buffer = ImageBuffer;
            //将输出Buffer清零
            user_queue.enqueueWriteBuffer(shared_output_buffer, true, 0, sizeof(float)*1000, C);
        }
 
        //将输出的cl::Buffer转成shared blob
        Blob::Ptr shared_output_blob = gpu::make_shared_blob(network.getOutputsInfo().begin()->second->getTensorDesc(), remote_context,
            shared_output_buffer);
        //将推理网络输出数据层替换成这个shared blob, 这样推理输出的数据就会放到shared_output_buffer里
        inf_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里
        user_queue.enqueueReadBuffer(shared_output_buffer, CL_TRUE, 0, sizeof(float) * 1000, D);
 
        for (int i = 0; i < 1000; i++)
        {
            //如果D数组的值大于0.0001, 则输出D数组的数据,数组的index对应1000组分类的index
            if (D[i] > 0.0001)
            {
                cout << "C[" << i << "] = " << C[i] << " - D[" << i << "] = " << D[i] << endl;
            }
            //可以看到输出分类信息和普通infernece输出结果一致,但是输出数据放在用户的cl::Buffer里
        }
 

编译运行程序,得到结果

和上一篇OpenCL Kernel Execution on a Shared Buffer例子的输出一致,收工 :)

 

个人感受:

OV的2个例子shared buffer和shared context的思路基本是一致的。因为GPU里运行的不同程序也和CPU这边的多进程程序一样,不同进程之间的数据是相互隔离的。所以要想共享GPU多个程序之间的数据,最简单的方法就是多个程序共享同一个OCL的context来创建, 也就是互相认干爹,有了同一个context爸爸,数据自然也就能互相访问了 :)

 

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

https://gitee.com/tisandman/cl_ov_sharing_ctx
————————————————
版权声明:本文为CSDN博主「sandmangu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sandmangu/article/details/115298117

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值