当前位置: 首页 > news >正文

deepstream--nvinfer

deepstream SDK地址:NVIDIA DeepStream SDK Developer Guide — DeepStream 6.1.1 Release documentation

nvinfer地址:Gst-nvinfer — DeepStream 6.1.1 Release documentation

 nvinfer插件使用来做推理的插件,输入,输出可以看nvinfer的插件介绍。这个插件是代码开源的,现在分析下源代码。

管道启动后,会进入gst_nvinfer_start,如下:

gst_nvinfer_start{

  status = createNvDsInferContext (&infer_context, *init_params, nvinfer, gst_nvinfer_logger);

//创建推理的上下文,是一个推理的封装,最后传给插件的成员变量m_InferCtx

  nvinfer->output_thread =
      g_thread_new ("nvinfer-output-thread", gst_nvinfer_output_loop, nvinfer);  //做后处理,添加Meta

  if (!nvinfer->input_tensor_from_meta) {
    nvinfer->input_queue_thread =
        g_thread_new ("nvinfer-input-queue-thread", gst_nvinfer_input_queue_loop,
            nvinfer);   //做前处理,推理

 ......

}

线程1:主线程

上游插件传下来的数据会先进入gst_nvinfer_submit_input_buffer函数,

gst_nvinfer_submit_input_buffer{

......

  if (nvinfer->input_tensor_from_meta) {

   flow_ret = gst_nvinfer_process_tensor_input (nvinfer, inbuf, in_surf);

  } else if (nvinfer->process_full_frame) {

   flow_ret = gst_nvinfer_process_full_frame (nvinfer, inbuf, in_surf);

  } else {

    flow_ret = gst_nvinfer_process_objects (nvinfer, inbuf, in_surf);

  }

......

}

可以看到,根据不同的配置,会进入不同的函数。

如果nvinfer->input_tensor_from_meta是1,就会进入gst_nvinfer_process_tensor_input,nvinfer就直接从Meta中获取已经做了前处理的tensor,经过tensors.push_back (tensor)之后, 所有tensor数据都保存到std::vector<NvDsInferLayerInfo> tensors中,再按最大batch-size对tensors进行分批推理,如下:

    if (i == frames.size () - 1 || batch->frames.size () == nvinfer->max_batch_size) {......

NvDsInferContextBatchPreprocessedInput input_batch;

DS_NVINFER_IMPL (nvinfer)->m_InferCtx->queueInputBatchPreprocessed (input_batch);

//在queueInputBatchPreprocessed中,不做前处理,直接去做推理(m_BackendContext->enqueueBuffer,enqueueBuffer不开源)。

}

如果nvinfer->process_full_frame是1,就会进入gst_nvinfer_process_full_frame,这个函数主要是将源图缩放填充到模型需要的尺寸,如下:

gst_nvinfer_process_full_frame{......

     gst_buffer_pool_acquire_buffer (nvinfer->pool, &conv_gst_buf,  nullptr); //分配临时GstBuffer

    batch->conv_buf = conv_gst_buf;

    get_converted_buffer(...  //这个函数只是先计算下缩放填充的参数,并不是实际的转换处理。

      /* Submit batch if the batch size has reached max_batch_size. */

      if (batch->frames.size () == nvinfer->max_batch_size) {

      if (!convert_batch_and_push_to_input_thread (nvinfer, batch.get(), memory)) ......//按最大batch-size分配进行转换,会调用实际转换函数NvBufSurfTransformAsync。

       g_queue_push_tail (nvinfer->input_queue, batch); //转换后的数据会推到队列,gst_nvinfer_input_queue_loop线程会去处理。

}

如果nvinfer->input_tensor_from_meta=0 && nvinfer->process_full_frame=0,就会进入gst_nvinfer_process_objects,这是SGIE对源图的object进行处理,如下:

gst_nvinfer_process_objects{......

        if (nvinfer->classifier_async_mode && object_meta->object_id == UNTRACKED_OBJECT_ID) {

        //这是异常情况,异步分类必须跟traker配合。

        }

        source_info->object_history_map.find (object_meta->object_id); //查找历史记录。

        bool needs_infer = should_infer_object (......  //检查是否要再进行推理,比如不需要此模型进行推理,或者已经做了分类,obeject的大小又没怎么变,就不需要再推理。

        if (!needs_infer) {

           continue;

        }

        if (obj_history && nvinfer->classifier_async_mode) {

              attach_metadata_classifier(......//异步模型又有历史记录,那就直接添加分类的meta。

        }

         batch.reset (new GstNvInferBatch); //为推理做准备,再下面的代码跟gst_nvinfer_process_full_frame中的类似。

线程2:gst_nvinfer_input_queue_loop

如果nvinfer->input_tensor_from_meta=1,就不会启动此线程,这个线程主要做推理,如下:

gst_nvinfer_input_queue_loop{......

        while (nvinfer->stop == FALSE) {

          NvDsInferContextBatchInput input_batch; //推理函数queueInputBatch的参数

           batch = (GstNvInferBatch *) g_queue_pop_head (nvinfer->input_queue); //取出要推理的数据。

          /* Form the vector of input frame pointers. */

          for (i = 0; i < batch->frames.size (); i++) {

             input_frames.push_back (batch->frames[i].converted_frame_ptr);  //添加推理数据

          }

           input_batch.inputFrames = input_frames.data ();

          input_batch.numInputFrames = input_frames.size ();

          input_batch.inputFormat = NvDsInferFormat_RGBA;

          status = nvdsinfer_ctx->queueInputBatch (input_batch); //先做前处理(m_Preprocessor->transform),再做推理(m_BackendContext->enqueueBuffer),再拷贝推理数据(m_Postprocessor->copyBuffersToHostMemory)。

           g_queue_push_tail (nvinfer->process_queue, batch);

        }

}

线程3:gst_nvinfer_output_loop

此函数主要走后处理和添加结果meta, 如下:

gst_nvinfer_output_loop

   while (!nvinfer->stop) {......

       /* Pop a batch from the element's process queue. */

        batch.reset ((GstNvInferBatch *) g_queue_pop_head (nvinfer->process_queue)); 

        /* Need to only push buffer to downstream element. This batch was not

     * actually submitted for inferencing. */

           if (batch->push_buffer) { //需要推到下游。

                 gst_pad_push (GST_BASE_TRANSFORM_SRC_PAD (nvinfer), batch->inbuf);

           }   

           /* Dequeue inferencing output from NvDsInferContext */

          status = nvdsinfer_ctx->dequeueOutputBatch (*batch_output); //取出推理后的数据做后处理,如聚类算法(m_Postprocessor->postProcessHost)。

   }

}

相关文章:

  • python+vue+elementui企业会议管理系统django
  • centos 部署java环境,拷贝jar包并运行
  • 支持在线写SQL的Oracle学习免费网站(个人常使用)
  • ESP8266-Arduino编程实例-SHT20温湿度传感器驱动
  • 【web-代码审计】(14.5)PHP
  • Waline评论服务docker自部署手册 + 无需备案域名配置
  • [202209]mysql8.0 双主集群搭建 亲测可用
  • C++后台开发学习路线(已多人拿下腾讯后台开发)
  • 中值滤波器 median filter
  • 基于ssm的图书(借阅)管理系统
  • linux内核中的I2C
  • 【Java面试】如何系统准备秋招?献上一份超硬核Java学习路线图+学习资源,拿走不谢!!
  • 面试分析:你懂不懂threadlocal?
  • ESP8266-Arduino编程实例-CCS811数字气体传感器驱动
  • 【C++编程语言】之类和对象---对象初始化和清除
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • 2017前端实习生面试总结
  • 78. Subsets
  • android图片蒙层
  • Docker: 容器互访的三种方式
  • ECMAScript6(0):ES6简明参考手册
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • NLPIR语义挖掘平台推动行业大数据应用服务
  • spring-boot List转Page
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 基于HAProxy的高性能缓存服务器nuster
  • 坑!为什么View.startAnimation不起作用?
  • 那些被忽略的 JavaScript 数组方法细节
  • 如何用vue打造一个移动端音乐播放器
  • 探索 JS 中的模块化
  • 一起参Ember.js讨论、问答社区。
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 中文输入法与React文本输入框的问题与解决方案
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • # 飞书APP集成平台-数字化落地
  • #{}和${}的区别?
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (转)可以带来幸福的一本书
  • .axf 转化 .bin文件 的方法
  • .cn根服务器被攻击之后
  • .java 9 找不到符号_java找不到符号
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .net FrameWork简介,数组,枚举
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .net 按比例显示图片的缩略图
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .NET 设计一套高性能的弱事件机制
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .Net6使用WebSocket与前端进行通信
  • .NetCore项目nginx发布