本页目录

  • 概述
  • 安装
  • 推理管线
  • Camera
  • 模型和解析器
  • 队列
  • 结果
  • 示例
  • 故障排除
  • 设置模型 SHAVEs
  • 更改解析器参数
  • 不同图像尺寸用于可视化和模型输入
  • 从 HubAI 下载模型时的存储位置
  • 延伸阅读
  • 在 RVC4 上并行运行模型

推理

概述

RVC 平台 转换的模型可以部署在 OAK 设备 上执行推理。 以下章节指导您为所需的 AI 模型设置简单的 推理管线 我们利用 DepthAI 构建推理管线,由以下节点组成:两种类型的节点可以互换连接。 内置节点稳定、优化,并在 Luxonis 设备上确保高效性能,而主机节点提供更大的灵活性,并可根据特定用例进行定制。 请查看 DepthAI Nodes 库,其中包含我们内部收集的 Python 主机节点。推理管线可以手动逐节点定义。 然而,我们也提供基于相关 NN Archive 的管线创建一定程度的自动化(例如,自动将神经网络与负责解码其输出的特定主机节点连接)。 详细信息请参见下文。

安装

创建推理管线需要 DepthAI (v3) 库。 使用我们的自定义主机节点(例如用于模型输出解码)需要 DepthAI Nodes 库。 您可以使用 pip 安装它们:
Command Line
1pip install depthai --force-reinstall
2pip install depthai-nodes

推理管线

我们在此展示一个简单的推理管线模板。 它由以下四个主要部分组成,我们在下面详细描述:
  • Camera, - 模型和解析器;- 队列;- 结果。
Python
1import depthai as dai
2from depthai_nodes.node import ParsingNeuralNetwork
3
4model = "..." # NN Archive 或 HubAI 模型标识符
5
6# 创建管线
7with dai.Pipeline() as pipeline:
8
9    # Camera
10    camera = pipeline.create(dai.node.Camera).build()
11
12    # 模型和解析器
13    nn_with_parser = pipeline.create(ParsingNeuralNetwork).build(
14        camera, model
15    )
16
17    # 队列
18    parser_output_queue = nn_with_parser.out.createOutputQueue()
19
20    # 启动管线
21    pipeline.start()
22
23    while pipeline.isRunning():
24
25        # 结果
26        ...

Camera

推理管线从 Camera 节点开始。 它是用于推理的图像帧的来源。 该节点可以按如下方式添加到管线中:
Python
1camera_node = pipeline.create(dai.node.Camera).build()

模型和解析器

推理包含两个步骤。 首先,模型对输入数据进行预测。 其次,一个后处理节点,也称为解析器,用于处理模型输出。 此步骤可选,如果跳过,则返回原始模型输出。 您可以在 DepthAI Nodes 库中找到有关可用解析器的更多信息。模型使用 NeuralNetwork 节点设置。 可以建立模型-解析器对:
  • 自动,使用 ParsingNeuralNetwork 节点,或
  • 手动,将它们初始化为独立节点并连接在一起。
前者自动将模型输出与相关 NN Archive 中定义的适当解析器连接。 这抽象掉了所有配置细节,因此是与解析器交互的首选方式。 创建的节点(独立或非独立)可以通过连接到其他节点或定义为管线队列,以与标准 DepthAI 节点相同的方式使用。

自动设置

ParsingNeuralNetwork 节点通过为模型输出添加自动解析功能,扩展了标准 NeuralNetwork 节点。 它可以从 depthai_nodes 包中导入,如下所示:
Python
1from depthai_nodes.node import ParsingNeuralNetwork
并直接从以下任意一种实例化:(1) NN Archive 对象,或
Python
1# 设置 NN Archive
2nn_archive = dai.NNArchive(<path/to/NNArchiveName.tar.xz>)
3
4# 设置模型(带解析器)并将其链接到相机输出
5nn_with_parser = pipeline.create(ParsingNeuralNetwork).build(
6    cameraNode, nn_archive
7)
(2) HubAI,通过指定 模型标识符(HubAI 平台上模型的唯一标识符。 更多信息请参见模型上传/下载章节)。
Python
1# 设置 HubAI 模型标识符
2model = "..."
3
4# 设置模型(带解析器)
5nn_with_parser = pipeline.create(ParsingNeuralNetwork).build(
6    camera_node, model
7)
初始化时,管道会自动检测连接设备的平台,并设置模型以及相关的解析器。 此外,它还会设置相机节点并将其链接到模型输入。

手动设置

模型和解析器也可以实例化为独立的节点。首先,导入感兴趣的 DepthAI Nodes 解析器或实现自己的解析器。
Python
1from depthai_nodes.node import <ParserNode>
2# 或者:
3class ParserNode(dai.node.ThreadedHostNode):
4    def __init__(self) -> None:
5        super().__init__()
6        self.input = self.createInput()
7        self.out = self.createOutput()
8    def build(self) -> "ParserNode":
9        return self
10    def run(self) -> None:
11        nn_out_raw = self.input.get()
12        nn_out_processed = ... # 自定义后处理
13        self.out.send(nn_out_processed)
其次,通过调用管道上的 create() 方法,将模型和解析器初始化为单独的节点:
Python
1model = pipeline.create(dai.node.NeuralNetwork)
2parser = pipeline.create(<ParserNode>)
节点使用默认参数初始化,并且可以根据需要进一步配置,方式如下:
  • 在初始化时,可以通过将参数值作为参数传递给 create() 方法来设置配置: parser = pipeline.create(<ParserNode>, <ParameterName>=<ParameterValue>, ...) 如果配置多个参数,可以将它们组织成一个 dict 并将其作为参数传递给解析器的 build() 方法: parser = pipeline.create(<ParserNode>).build(config_dict);
  • 初始化后,可以通过使用 setter 方法来更改配置: parser.<SetterMethodName>(<ParameterValue>). 您可以在 DepthAI Nodes API 参考 页面上找到特定解析器可用的所有 setter 方法。
第三,设置模型可执行文件(即 RVC2 的 .blob 文件,或 RVC4 的 .dlc 文件):
Python
1model.setModelPath(<path/to/model_executable>)
最后,准备相机流并将独立节点链接以构成管道:
Python
1width, height = ... # 模型输入尺寸
2camera_stream = camera.requestOutput(size=(width, height))
3camera_stream.link(model.input)
4model.out.link(parser.input)

队列

队列用于从管道的特定节点获取数据。 要获取输入模型的图像帧,可以使用直通队列
Python
1frame_queue = nn_with_parser.passthrough.createOutputQueue()
要获取(解析后的)模型输出,可以使用输出队列 其定义取决于模型头的数量:

单头

Python
1parser_output_queue = nn_with_parser.out.createOutputQueue()

多头

Python
1head0_parser_output_queue = nn_with_parser.getOutput(0).createOutputQueue()
2head1_parser_output_queue = nn_with_parser.getOutput(1).createOutputQueue()
3...

结果

在管道通过 pipeline.start() 启动后,可以从定义的队列中获取输出。 您可以像这样获取输入帧和解析后的模型输出:
Python
1while pipeline.isRunning():
2
3    # 获取相机输出
4    frame_queue_output = frame_queue.get()
5    frame = frame_queue_output.getCvFrame()
6    ...
7
8    # 获取解析后的输出
9    parser_output = parser_output_queue.get()
10    ...
已解析的模型输出返回为:请阅读 DepthAI 节点 API 参考,以了解相关格式以及如何为您的用例使用它们。

示例

请查阅 OAK 示例 页面。

故障排除

以下是一些常见问题及其解决方案。

设置模型 SHAVEs

SHAVEs 是 RVC2 VPU 中运行神经网络的计算核心。 有时,模型构建时使用了与目标设备支持的 SHAVE 数量不同的值。如果模型编译时使用的 SHAVE 数量多于设备实际拥有的数量,流水线将失败并出现类似于以下内容的 RuntimeError:
Command Line
1NeuralNetwork: Blob compiled for ... shaves, but only ... are available in current configuration
这种情况通常出现在旧设备(如 OAK-D Lite)上。相反,如果模型编译时使用的 SHAVE 数量少于设备可用数量,它仍会运行,但您可能会看到如下警告:
Command Line
1[14442C103180EECF00] [2.1] [4.736] [NeuralNetwork(2)] [warning] Network compiled for 8 shaves, maximum available 13, compiling for 6 shaves likely will yield in better performance
在这种情况下,模型未充分利用可用计算资源,重新编译模型以更好地匹配设备的 SHAVE 数量可以提高性能。要修复使用的 SHAVE 数量,您可以:
  • 如果模型是使用旧版 Blobconverter 导出的,则可以重新编译模型并匹配 SHAVE 数量,或者
  • 如果模型是在 HubAI 中导出的,则无需重新编译 - 您可以在流水线初始化时设置 SHAVE 数量以匹配设备要求:
Python
1nn_archive = dai.NNArchive(...)
2nn_with_parser = pipeline.create(ParsingNeuralNetwork).build(
3    ..., nn_archive
4)
5# 设置 SHAVE 数量
6nn_with_parser.setNNArchive(
7    nn_archive, numShaves=<Number>
8)

更改解析器参数

要修改解析器参数,您首先需要访问解析器对象。
  • 具有独立解析器节点的流水线: 直接访问解析器节点即可。
  • 具有 ParsingNeuralNetwork 节点的流水线: 在这种情况下,解析器与 AI 模型集成在一起。 通过调用 ParsingNeuralNetwork 节点上的 .getParser() 方法来获取它。
获得解析器后,使用相关的 set 方法更新其参数。 示例:
Python
1parser.setConfThreshold(0.5)

不同图像尺寸用于可视化和模型输入

您可以为模型输入和可视化使用不同的图像尺寸。 使用 ImageManip 节点将图像在发送到模型之前调整大小,同时保留原始分辨率用于显示。示例:
Python
1cam = pipeline.create(dai.node.Camera).build()
2
3# 请求特定图像尺寸用于捕获
4cam_out = cam.requestOutput(size=(<width1>, <height1>))
5
6# 创建并配置用于模型输入的调整大小节点
7resize_node = pipeline.create(dai.node.ImageManip)
8resize_node.initialConfig.setOutputSize(<width2>, <height2>)
9cam_out.link(resize_node.inputImage)
10
11# 使用调整大小后的输入定义模型
12nn_with_parser: ParsingNeuralNetwork = pipeline.create(ParsingNeuralNetwork).build(
13    resize_node.out, ...
14)
15
16# 使用原始分辨率进行可视化
17video_queue = cam_out.out.createOutputQueue() # 高分辨率流
18detection_queue = nn_with_parser.out.createOutputQueue() # 低分辨率流上的检测结果
19...

从 HubAI 下载模型时的存储位置

当您从 HubAI 下载模型时,它会被存储在项目根目录的 .depthai_cached_models 文件夹中。 此缓存包含之前运行的所有模型。 如果模型已缓存,则会从本地加载,而不是重新下载。 要强制重新下载,可以在下载模型时使用 useCached=False 参数。 示例:
Python
1nn_archive = dai.NNArchive(dai.getModelFromZoo(model_description, useCached=False))
2nn_with_parser = pipeline.create(ParsingNeuralNetwork).build(
3    ..., nn_archive
4)
或者,您可以删除 .depthai_cached_models 文件夹并重新运行流水线。

延伸阅读

以下部分提供了关于 RVC4 平台上推理过程的额外信息和见解,以及如何在 Qualcomm 的 Hexagon 张量处理器(HTP) 上执行 NN 模型。

在 RVC4 上并行运行模型

在 Qualcomm SoC 的 Hexagon Tensor Processor (HTP) 上同时运行多个模型时,需要注意资源分配和调度方面的一些重要事项。HTP 会动态共享计算和片上内存资源。根据 Qualcomm 的说法,没有直接的方法可以在 HTP 上优先处理一个模型,并且这是用户不可调优的。您应将 HTP 视为一个黑盒调度器,并选择经实证效果最佳的线程策略。

HTP 上的资源分配

  • HTP 计算核心和 V-TCM 内存在所有并发的 SNPE 会话之间是 弹性 共享的。
  • 内部调度器采用轮询策略;多个模型之间的资源分配 不是固定的,并且可能在帧之间变化。

控制手段

  • 不支持资源导向。没有 按模型的优先级、核心亲和性或配额 API。唯一的全局杠杆是 --perf_profile 标志,它影响 SoC 级别的功耗/性能权衡。

实践指导

  1. 假设在新增/停止并发会话时,延迟和吞吐量会波动。
  2. 使用 SNPE 时序日志(例如分层分析)来衡量端到端延迟,而不是猜测资源份额。