Skip to main content
本指南描述了如何在 Qualcomm IM SDK 管线中添加模型后处理支持。 当 Qualcomm IM SDK 插件不支持某个模型的后处理时, 这是必要的。
有关后处理在管线中的作用背景,请参阅 IM SDK 概述。有关完整的 qtimlpostprocess 参考和自定义插件构建详细信息,请参阅 Discover SDKs → IM SDKs。
本节涵盖以下主题。
  1. AI IM SDK 管线概述。
  2. qtimlpostprocess 插件简介。
  3. 如何编写后处理模块。
  4. 如何编译后处理模块。
  5. 如何部署和测试后处理模块。
本示例说明了向 qtimlpostprocess 插件添加自定义 YOLOv8 模型后处理的步骤。 下图显示了添加自己的后处理模型的流程, 从开发和集成模型到运行参考应用程序。 向 Qualcomm IM SDK 添加自定义模型后处理的流程

AI IM SDK 管线概述

Qualcomm Intelligent Multimedia SDK (IM SDK) 包含构建 AI、多媒体和 计算机视觉管线所需的构建模块, 用于构建应用程序。 使用 IM SDK 构建 AI 工作流涉及三个关键的 GStreamer 插件。
  1. 预处理元素: 将传入的数据流转换为适合 AI 推理的 张量格式。
  2. 推理元素: 使用 AI 模型执行推理,并对输出张量应用 反量化。除反量化之外,此元素不执行任何 预处理或后处理。
  3. 后处理元素: 解析输出张量并生成包含机器学习元数据的 缓冲区。此元素以以下方式之一输出 元数据。
  • 使用 qtimetamuxer 将其附加到源流
  • 将其直接流式传输到 RTSP、RTMP 或 Redis 等端点。
  • 作为图像掩码,使用 qtivcomposer 叠加到源视频帧上。
包含预处理、推理和后处理元素的 Qualcomm IM SDK AI 管线

示例: 直接使用 ML 元数据

在以下示例中,源流在推理插件之后不再传播。 IM SDK 管线示例: 直接使用 ML 元数据,不传播源流

示例: 将 ML 元数据附加到源视频

在以下示例中,ML 元数据附加到源视频。 叠加层使用附加的 ML 元数据绘制边界框、文本 和其他可视元素。结果显示在屏幕上, 或通过网络流式传输。 IM SDK 管线示例: ML 元数据附加到源视频流

示例: 将 ML 元数据转换为图像掩码

在以下示例中,ML 元数据被转换为图像掩码,然后 叠加 (blit) 到源流之上。 IM SDK 管线示例: ML 元数据转换为叠加在源流上的图像掩码

IM SDK 中的 AI 后处理插件简介

qtimlpostprocess 是一个可自定义的插件,为推理插件的张量输出后处理 提供库接口。后处理库 负责张量解析,并输出预测结果列表。 后处理 (PP) 模块处理一种类型的机器学习 (ML) 模型。 每个 PP 模块处理特定类型的模型及其变体,例如 所有 YOLOv8 检测模型变体。该插件负责管理模块的执行、 输出生成 (ML 元数据或图像掩码)、批处理、ML 暂存以及其他相关任务。 下图显示了输入、输出、后处理 模块和后处理插件之间的关系。 显示后处理模块输入和输出的图片。 后处理插件支持以下模型类型:
  • 目标检测
  • 图像分类
  • 图像分割
  • 超分辨率
  • 姿态估计
  • 音频分类
后处理插件接收张量列表作为输入。 这些张量封装在 GST Buffer 中。机器学习元数据附加到 每个缓冲区,指定诸如张量数量、张量形状、模型输入 张量形状、每个输入张量中有多少被流数据填充、 时间戳和批处理索引等详细信息。 后处理插件可以生成以下格式之一:
  • 文本: 后处理插件将机器学习元数据序列化为文本。此 元数据可被其他插件直接使用,或使用 qtimetamuxer 附加到源流。
  • 图像掩码: 后处理插件可以生成带有叠加文本、 边界框、点、线和其他可视元素的图像掩码。这是一个仅包含 机器学习结果的透明帧。 例如,如果后处理类型是目标检测,插件会绘制带标签的 边界框。然后,qtivcomposer 插件可以将图像掩码叠加到 源视频流上。
  • 张量: 后处理插件可以生成张量。当下一个推理 阶段需要当前推理阶段的输出张量,但张量形状 不完全匹配时使用此格式。 例如,第一阶段产生四个输出张量,而下一阶段 需要其中三个。
GStreamer 管线的 caps 协商决定输出格式。系统会自动协商 最合适的格式,但您可以使用 GStreamer caps 过滤器手动指定。 该插件仅支持一个源 pad。如果管线需要同时使用两种或更多 支持的格式,请在管线中添加并运行后处理插件 两次。 后处理插件配置由以下内容组成 (GStreamer 属性):
  • Module: (必需) 后处理模块名称。此 GStreamer 属性指定如何 解析张量。它不定义插件输出类型。输出类型在 管线 caps 协商期间确定。
  • Settings: (可选) JSON 字符串或 JSON 文件的路径。此配置仅适用 于模块而非插件。它向后处理模块传递任意配置, 因为每个模块都有特定需求。 例如,使用它传递置信度阈值 (confidence-threshold)、关键点、NMS 阈值和 token。
  • Labels: (可选) 标签文件的路径。您可以将标签文件的路径直接传递 给模块,使用换行分隔的标签列表、JSON 格式的标签 或自定义格式。前两种格式的解析器已在头文件中提供, 对于自定义格式,您可以在后处理模块中实现自己的解析器。
  • Results: (可选) 例如,如果模型检测到 7 个结果但最多允许 4 个,则 会丢弃置信度得分最低的 3 个结果。此功能由插件实现,因此 模块开发者无需自行处理。

为自定义模型编写后处理模块

后处理模块是一个共享库,用于解析推理插件的张量输出。 后处理 GST 插件 (qtimlpostprocess) 加载并运行该模块。IM SDK 提供了种类丰富的开箱即用后处理模块:
  • image-detection (yolov5、yolov8、yolonas、ssd-mobilenet、qfd、qpd、east-textdt)
  • classification (mobilnet、resnet、ocr、qfr)
  • pose-estimation (hrnet、lite-3dmm、posenet)
  • segmentation (deeplab、midas-v2、yolov8)
  • super-resolution (snet)
使用 gst-inspect-1.0 qtimlpostprocess 可查看设备上支持的模块的完整列表。 以下日志显示了示例输出。
如果找不到适合您的模型的后处理模块,您可以自行实现。 您可以独立于 IM SDK 构建后处理模块。 要在没有 IM SDK 的情况下构建后处理模块,您需要接口 头文件和工具链。构建模块后,将其部署到 设备上的 /usr/lib/imsdk/qtimlpostprocess/modules/。 后处理插件会自动检测到它,用户即可在 GStreamer 管线中选择它。

模块和库命名

为避免后处理模块名称重复,后处理模块共享库 必须遵循 libml-postprocess-<module-name>.so 命名约定。 例如,YoloV8 模块的共享库必须命名为 libml-postprocess-yolov8.so。 配置后处理插件时使用相同的 <module-name>。例如,module=yolov8。

AI 后处理模块推理

AI 后处理模块提供 C++ API。由于 C++ API 无法直接从共享库加载, 类的实例化被封装在一个 C 函数中。此机制已在头文件中实现, 因此您无需手动处理 C++ 类的实例化。您只需在派生自 IModule 接口的 模块类中实现以下 API。
  • 构造函数/析构函数: 构造函数不接受任何参数,是开发者的 通用入口点。
  • Caps(): 以 JSON 格式返回模块类型和支持的张量维度。
  • Configure(): 接受标签文件的路径和包含模块特定设置的 JSON 字符串。 用户通过后处理 GStreamer 插件的 settings 属性提供这些设置。
  • Process(): 解析输入张量,并根据模型输出生成预测结果。

std::string Caps()

以 JSON 字符串形式返回模块类型和支持的张量形状。张量形状不是固定的, 而是定义在一个范围内,用方括号表示。 例如,[1, [21, 42840], 4] 表示第二个维度可以在 21 和 42840 之间变化。 以下代码片段是后处理模块能力的示例定义。该示例实现了 目标检测后处理,张量格式为 FLOAT32,并支持一个、两个或三个张量输出。
支持的后处理模块类型
  • object-detection
  • image-classification
  • image-segmentation
  • super-resolution
  • pose-estimation
  • audio-classification
  • tensor
支持的张量类型
  • FLOAT32
  • FLOAT16
  • INT8
  • UINT8
  • INT16
  • UINT16
  • INT32
  • UINT32
  • INT64
  • UINT64
您可以同时指定多种格式。例如:

bool Configure(const std::string& labels_file, const std::string& json_settings)

参数

bool Process(const Tensors& tensors, Dictionary& mlparams, std::any& output)

参数
张量输出是一种特殊情况,此时后处理插件和模块生成 张量而不是预测结果。当两个机器学习模型链接在一起, 且第一个模型的输出张量需要在传递给下一个模型之前进行修改时, 使用此方式。如果输出张量不需要修改,则两个推理插件可以 直接前后相连,无需后处理插件。

理解后处理模块输入

后处理模块输入分为两个字段:
  • tensor: 此字段保存推理输出张量并描述其结构。向量 将每个输出张量表示为一个条目。例如,对于产生 三个输出张量 (边界框、得分、类别索引) 的 YOLOv8,该向量包含四个条目。
    • Type: float、uint8 等。
    • Name: 张量名称,当两个或多个输出张量具有相同形状时用于识别。 张量名称是唯一的,可保证选中确切的张量。
    • Dimensions: 描述张量形状。 例如,具有三个输出张量的 YoloV8: [1,8400,4], [1,8400], [1,8400]
    • Data: 指向张量的指针。
  • mlparams: 用于张量处理的附加参数,可能不适用于所有子模块。 此字段提供有关管线如何处理输入流的信息,以帮助处理 流的分辨率和宽高比与输入张量形状不匹配的情况。 此字段是使用 std::any 实现的字典。您必须知道预期的键及其 对应的返回类型。使用 std::any 可确保返回值与给定键 关联的类型匹配。用法示例:
    支持的键
    • 键: “input-tensor-region” 类型: video::Region 说明: 此参数指示输入张量的哪一部分被流中的实际数据填充。 其余区域被视为填充 (padding)。
    • 键: “input-tensor-dimensions” 类型: video::Resolution 说明: 指定输入张量的大小。当后处理算法以绝对坐标产生输出时, 需要用它将绝对坐标转换为相对坐标, 因为后处理模块必须输出相对坐标。

生成后处理模块输出

输出是由结果数组组成的数组。 数组嵌套是为了支持批处理用例。 如果没有批处理,则只填充内层数组。内层数组的大小与找到的结果数量一致。 结果始终采用相对维度,结果类型取决于模块类型。
  • 图像/音频分类
    • Name: 类别标签;图像/音频所属的预测类别或类。
    • Confidence: 类别概率或置信度得分。
    • Color: 用于在叠加插件中可视化的 RGBA8888 颜色。
    • Xtraparams: (可选) 字典形式的额外参数 (键/值对),用于从模块导出任意额外结果并向下游传递。
  • 目标检测
    • Left、top、right、bottom: 边界框坐标。
    • Name: 类别标签;图像/音频所属的预测类别或类。
    • Landmarks: (可选) 关键点列表;例如,人脸检测模型可以随边界框输出人脸关键点。
    • Confidence: 类别概率或置信度得分。
    • Color: 用于在叠加插件中可视化的 RGBA8888 颜色。
    • Xtraparams: (可选) 字典形式的额外参数 (键/值对),用于从模块导出任意额外结果并向下游传递。
  • 姿态估计
    • Name: 类别标签;图像/音频所属的预测类别或类。
    • Confidence: 类别概率或置信度得分。
    • Keypoints: 关键点向量。
    • Links: (可选) 关键点之间连接的向量。
    • Color: 用于在叠加插件中可视化的 RGBA8888 颜色。
    • Xtraparams: (可选) 字典形式的额外参数 (键/值对),用于从模块导出任意额外结果并向下游传递。
  • 图像分割和超分辨率
    • 输出是图像帧/掩码。
  • 张量
    • 张量列表。

批处理

后处理插件会自动将张量批次拆分为单个张量。 插件层负责处理批处理,您无需处理批处理用例。 例如,如果批处理大小为四,则模块会针对每个批次自动被调用 4 次。

模块辅助工具

接口头文件中包含标签解析器和 JSON 解析器。 您不必使用它们,但提供它们是为了方便。 您可以使用任何标签或 JSON 解析器,但模块必须与它们静态链接。
  • 标签解析器: 此解析器支持两种格式,接受标签文件的路径,并自动检测格式。
    • 换行分隔格式: 行号即为类别 ID。
    • JSON 格式: 您应在此格式中设置类别索引、标签和可视化颜色。 此格式更灵活,因为您可以只传入部分类别,其余类别会被自动过滤掉。
  • JSON 解析器: 设置以 JSON 字符串传递。此实用工具用于解析设置,并且在 JSON 格式的情况下, Qualcomm 提供的标签解析器也使用了此实现。

日志记录

后处理模块可以将日志输出到 GStreamer 日志系统,而无需直接依赖 GStreamer。 构造函数向模块传递一个日志对象。 该对象与 LOG 宏一起,可用于将日志直接输出到 GStreamer 日志。 支持的日志级别包括: Error、Warning、Info、Debug、Trace 和 Log。 LOG 宏:
日志用法示例:

在主机上编译后处理模块

前提条件
  • Ubuntu 22.04 或 Ubuntu 24.04 主机。
  1. 安装所需的工具。
  2. 从 CodeLinaro 下载所需的 .h 和 .cc 文件。
  3. 将 IM SDK 头文件和模块源文件放在同一个文件夹中。
  4. 创建 CMakeLists.txt 文件。例如:
    后处理模块共享库必须遵循 libml-postprocess-<module-name>.so 命名约定。例如,YoloV8 模块的共享库应命名为 libml-postprocess-yolov8.so。
  5. 创建工具链文件,例如 aarch64-toolchain.cmake。例如:
  6. 配置并构建模块。

部署并测试后处理模块

  1. 在主机上,设置用户环境变量:
  2. 下载所需的脚本和构件。
  3. 将模块部署到目标设备。
    1. 在主机终端中运行以下命令, 将模块传输到目标设备。
    2. 在主机终端中运行以下命令, 通过 SSH 连接到目标设备。
    3. 出现提示时,输入密码: oelinux123。
    4. 在 QLI 目标设备上 (SSH 登录后) 运行以下命令, 以写权限重新挂载 /:
    5. 在目标设备上 (SSH 登录后) 运行以下命令, 将模块复制到 GStreamer 插件目录:
  4. 在目标设备上运行 GST inspect,确认您的模块出现在 支持的模块列表中。 您应该能在支持的模块列表中看到您的后处理模块及其支持的张量形状。
  5. 下载运行 GStreamer 管线所需的模型、标签和媒体文件。
    1. 下载 yolox.json。
    2. 将 yolox.json 文件复制到目标设备。
    3. 下载 video1.mp4。
    4. 将 video1.mp4 文件复制到目标设备。
    5. 下载 yolox_quantized.tflite。
    6. 将 yolox_quantized.tflite 文件复制到目标设备。
  6. 有了后处理模块后,构建一个 GStreamer 管线。 使用 qtimlpostprocess 插件的 module 属性选择您的后处理模块。
如果您的模块需要标签文件或配置,请使用 label 和 settings 属性传递它们。 以下示例管线用于运行 YOLO-X 模型:
  • 管线使用离线视频作为源。
  • 管线使用 v4l2h264dec 解码器将视频解码为 YUV 格式。
  • qtimlvconverter 插件对 YUV 帧进行预处理。
  • qtimltflite 插件使用 LiteRT YOLO-X 模型运行推理。
  • 后处理插件加载 YOLO-X 模块,并传入 JSON 格式的标签文件。
  • 管线在 Wayland 上显示结果。