本文来源公众号“码科智能”,仅用于学术分享,侵权删,干货满满。
原文链接:加速实时视觉检测应用,在边缘设备部署上实现2.4倍的加速!
想象一个场景:高速公路上遇到200km/h超速车辆,这时30帧摄像头抓拍成“幻影”,AI违法事件监控功能直接失效。反之另一个场景:暴雨夜大货车侧翻,AI 监控毫秒内预警,救援响应大幅提速!
上述就是实现实时视觉应用的重要性,尤其是在算力低下或者边缘部署的情况下,模型运行效率更是评价系统的一个重要指标。
YOLOv8 在高速公路摄像头上进行物体检测
在智能监控、工业检测等实时视觉应用中,端侧计算通过将处理保持在数据源附近,具备低延迟:本地处理避免网络传输延迟;低成本:节省带宽和云服务费用;隐私安全:敏感数据无需上传云端的优势。然而,边缘设备的计算能力往往成为瓶颈。
在本文中,将探索加速的三大关键技术,以YOLOv8为例实现在边缘设备上的极致加速:
-
多线程异步处理:吞吐量提升11%,告别卡顿!
-
TensorRT极致优化:推理速度暴涨43%!
-
Deepstream全流程加速:最终实现48.2FPS,性能提升2.4倍!
一、视觉应用常见的推理Pipline
首先从一个基础的目标检测推理应用场景开始,推理流程通常包含如下几个部分:
GPU AI推理业务流程
-
数据输入是摄像头获取的视频数据流,一般以H.264格式为主。
-
然后通过FFmpeg软件,将连续的视频流进行拆帧和解码。
-
下一阶段是对解码后的图像进行预处理,通常使用OpenCV对图像进行缩放,得到模型需要的图像规格。
-
模型推理环节,用户可以选择的方式比较多,比较典型的是使用TensorRT进行推理应用开发。
-
目标检测后处理需要进行NMS计算,进行图片画框等操作。
-
数据输出阶段,用户根据需要实现一个结果呈现形式。
二、异步化你的处理流程
推理流程的各个步骤可以同时执行,多线程是实现这一目标的关键。在 Python 中,多线程通过上下文切换实现,当一个线程空闲时,处理器可以切换到其他线程,从而提高效率。对于包含 I/O 操作的推理管道,多线程尤为重要,因为它能让 CPU 在等待 I/O 操作完成时继续处理其他任务。
Roboflow 推理管道正是基于这一原理,将视频解码、推理和后处理分离到不同的线程中,实现并行处理。这种异步处理方式能有效提高处理速度,尤其是在处理批量帧时,CPU 可以在等待一批帧进行推理时继续处理其他任务。
多线程
三、OpenCV与Roboflow Inference加速效果对比
使用 OpenCV 中的 YOLOv8-nano 对象检测模型实现同步推理流程:
import cv2
from inference import get_model
import supervision as sv
model = get_model("yolov8n-640")
cap = cv2.VideoCapture('/path/to/video')
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
predictions = model.infer(frame)
detections = sv.Detections.from_inference(predictions[0])
annotated_image = sv.BoxAnnotator().annotate(scene=frame, detections=detections)
annotated_image = sv.LabelAnnotator().annotate(scene=annotated_image, detections=detections)
在上述代码中,从视频流中读取一帧、调用检测模型以及渲染结果这三个步骤是按照顺序依次执行的。也就是说,只有在前一个步骤完成之后,下一个步骤才会开始。
接下来,我们将其与使用 Roboflow 推理实现的相同流程进行对比。
from inference importInferencePipeline
from inference.core.interfaces.camera.entitiesimportVideoFrame
import supervision as sv
import cv2
def on_prediction(
predictions: dict,
video_frame: VideoFrame,
) -> None:
detections = sv.Detections.from_inference(predictions)
annotated_image = sv.BoxAnnotator().annotate(scene=frame, detections=detections)
annotated_image = sv.LabelAnnotator().annotate(scene=annotated_image, detections=detections)
cv2.imshow("output", annotated_image)
cv2.waitKey(1)
# create an inference pipeline object
pipeline = InferencePipeline.init(
model_id="yolov8n-640",
video_reference='/path/to/video'
)
# start the pipeline
pipeline.start()
# wait for the pipeline to finish
pipeline.join()
在 Nvidia Jetson AGX Xavier 设备上运行这两种程序后,我们得到了以下吞吐量的测量结果:
-
OpenCV(同步):20.1 FPS
-
Roboflow(异步):22.3 FPS
由此可见,多线程的应用带来了 11% 的性能提升,这已经是一个相当不错的成绩了。
四、选择正确的推理引擎再对比加速效果
通常情况下,机器学习(ML)模型是在 PyTorch 或 Tensorflow 等框架中进行训练的。这些框架主要目的是便于模型的训练。训练完成后,这些模型可以转换为以部署为中心的格式,从而利用加速后端实现更快的推理。推理引擎通常是针对特定芯片组进行优化的。常见的推理引擎包括:
-
TensorRT(适用于 Nvidia GPU)
-
OpenVINO(适用于英特尔 x86 CPU)
-
Tensorflow Lite / Lite Micro(适用于嵌入式设备)
-
ONNX(适用于多平台)
回到前面的例子,Roboflow Inference 默认使用 ONNX 运行时引擎。为了充分发挥 Jetson 设备上 Nvidia GPU 的性能,我们可以通过设置相应的环境变量来启用 TensorRT。这样会从 YOLOv8 权重文件编译出 TensorRT 模型引擎。再次运行上述两种推理流程后,我们得到了以下结果:
-
OpenCV(同步):26.7 FPS
-
Roboflow(异步):31.9 FPS
TensorRT 引擎为这两条管道都带来了显著的性能提升。有趣的是,两条管道之间的吞吐量差距从 11% 扩大到了 19%,这表明异步管道从加速引擎中获得了更多的好处。
五、加速其余流程
在加速了推理步骤之后,我们还可以继续提升其余管道组件的性能。为此,我们使用了 Nvidia 的 Deepstream SDK。该 SDK 将推理管道拆分为一组基于 GStreamer 媒体框架构建的硬件优化插件。
我们使用以下 Deepstream 插件构建了相同的推理管道:
-
UriDecodeBin:自动解码一系列视频源,包括已保存的文件、USB 摄像头和 RTSP 流
-
Nvstreammux:批处理帧并实例化 NvDsBatchMeta 以保存推理结果和帧元数据
-
Nvinfer:TensorRT 推理引擎
-
Nvvideoconvert:将帧转换为可显示的格式
-
Nvosd:屏幕显示容器
-
Sink:在桌面上显示或保存到文件
-
队列:实现管道元素之间的异步
这相当于使用 Deepstream Python 绑定的以下 Python 应用程序。
import gi
gi.require_version('Gst', '1.0')
from gi.repositoryimportGLib, Gst
import sys
# append the dir containing helper functions from deepstream-python-apps
sys.path.append('/opt/nvidia/deepstream/deepstream-6.3/sources/deepstream_python_apps/apps')
from common.bus_callimport bus_call
import pyds
# DeepStream configuration for the application
# InitializeGST
Gst.init(None)
# Create the pipeline
pipeline = Gst.Pipeline()
# Create the video source
uri_name = 'file:///path/to/video'
source_bin=create_source_bin(0, uri_name)
pipeline.add(source_bin)
# Streammux
streammux = Gst.ElementFactory.make('nvstreammux', 'streammux')
pipeline.add(streammux)
# Set streammux properties
streammux.set_property('batch-size', 1)
streammux.set_property('width', 852)
streammux.set_property('height', 480)
sinkpad= streammux.get_request_pad("sink_0")
srcpad=source_bin.get_static_pad("src")
srcpad.link(sinkpad)
# Create the primary inference element (GIE)
primary_gie = Gst.ElementFactory.make('nvinfer', 'primary-gie')
primary_gie.set_property('config-file-path', '/path/to/yolov8/config/file')
# Createnvvidconv (video converter)
nvvidconv = Gst.ElementFactory.make('nvvideoconvert', 'nvvidconv')
# Create the OSD (On-ScreenDisplay)
osd = Gst.ElementFactory.make('nvdsosd', 'osd')
# Create the sink (display output)
sink = Gst.ElementFactory.make('nv3dsink', 'sink')
sink.set_property('sync', 0)
# Add elements to pipeline
pipeline.add(primary_gie)
pipeline.add(nvvidconv)
pipeline.add(osd)
pipeline.add(sink)
# Create queue elements for asynchronous pipeline
queue1=Gst.ElementFactory.make("queue","queue1")
queue2=Gst.ElementFactory.make("queue","queue2")
queue3=Gst.ElementFactory.make("queue","queue3")
pipeline.add(queue1)
pipeline.add(queue2)
pipeline.add(queue3)
# Link elements
streammux.link(queue1)
queue1.link(primary_gie)
primary_gie.link(queue2)
queue2.link(nvvidconv)
nvvidconv.link(queue3)
queue3.link(osd)
osd.link(sink)
# Initialize loop
loop = GLib.MainLoop()
bus = pipeline.get_bus()
bus.add_signal_watch()
bus.connect ("message", bus_call, loop)
# Start playing the pipeline
pipeline.set_state(Gst.State.PLAYING)
# Start the main loop
try:
loop.run()
except Exceptionase:
print("Error during pipeline execution:", e)
pass
pipeline.set_state(Gst.State.NULL)
运行该应用程序后,我们获得以下吞吐量测量值:
- Deepstream— 异步:48.2 FPS
与前两种实现方式相比,性能又有了显著的提升。
总的来说,本教程展示了如何使用 Roboflow Inference Pipeline 和 Deepstream SDK 构建异步和加速推理管道,从而使吞吐量提高了 2 倍以上。
对于那些性能受到严重限制的设备,还可以通过其他技术进一步降低推理延迟,例如帧批处理、模型量化和修剪以及使用更简单的模型。希望本指南能够对你开发实时视觉应用程序有所帮助。
THE END !
文章结束,感谢阅读。您的点赞,收藏,评论是我继续更新的动力。大家有推荐的公众号可以评论区留言,共同学习,一起进步。