此页面由 AI 自动翻译。查看英文原版

本页目录

  • 概述
  • 安装
  • 推理管道
  • 相机
  • 模型和解析器
  • 队列(Queue)
  • 结果
  • 示例
  • 故障排除
  • 设置模型 SHAVEs
  • 更改解析器参数
  • 不同的可视化和模型输入尺寸
  • 从 HubAI 下载的模型位置
  • 扩展阅读
  • 在 RVC4 上并发执行模型

推理

概述

RVC平台转换的模型可以部署在OAK设备上执行推理。 以下部分将指导您为所需的 AI 模型设置一个简单的推理管道 我们使用 DepthAI 将推理管道构建为一系列:这两种节点都可以互相连接。 内置节点稳定、优化,并确保 Luxonis 设备上的高效性能, 而主机节点则提供更大的灵活性,并可根据特定用例进行定制。 请查看我们的内部 Python 主机节点集合的 DepthAI 节点 库。推理管道可以手动定义,逐个节点地进行。 但是,我们也提供了一定程度的管道创建自动化,该自动化基于相关的 NN Archive (例如,自动将神经网络与负责解码其输出的特定主机节点连接起来)。 有关更多信息,请参阅下文。

安装

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

推理管道

此处我们提供一个简单的推理管道模板。 它包含四个主要部分,我们将在下面进行更详细的描述:
  • 相机,
  • 模型和解析器;
  • 队列;
  • 结果。
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    # 相机
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 节点开始。 它是要进行推理的图像帧的来源。 可以如下将该节点添加到管道中:
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 并将其作为参数传递给 parserbuild() 方法: 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)

队列(Queue)

队列用于从管道的特定节点获取数据。 要获取输入到模型的图像帧,您可以使用直通队列
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 Nodes 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# 创建并配置用于模型输入的 resize 节点
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 Tensor Processor (HTP) 上执行的更多信息和见解。

在 RVC4 上并发执行模型

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

HTP 上的资源分配

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

控制旋钮

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

实践指南

  1. 假设在新的/并发会话启动或停止时,延迟和吞吐量会发生波动。
  2. 使用 SNPE 定时日志(例如逐层分析)来测量端到端延迟,而不是猜测资源共享。