【临时方案】Model Zoo YOLO FP32 模型 TROS 高效使用指南

Model Zoo YOLO FP32 模型 TROS 高效使用指南

最新方案:add ultralytics_yolo_output_parser to support YOLOv5-26 FP32 output models by Machao615 · Pull Request #42 · D-Robotics/hobot_dnn · GitHub

背景信息

社区开发者经常遇到一个棘手的问题:从开发者社区(Model Zoo)获取的 YOLO 系列模型(例如:RDK X5 YOLO参考这里,RDK S100 YOLO参考这里),无法直接在 TROS(TogetherROS)中使用。这主要是因为模型的输出格式与TROS中hobot_dnn节点的解析代码不兼容。

截至 2026年2月2日,我们已经充分意识到这一问题,并已启动一项旨在提升开发者体验的对Model Zoo 全面重构工作,其内容包括:

  • 代码规范:统一代码风格与标准。
  • 版本管理: 执行严格的版本管理标准。
  • 目录结构:优化和统一项目结构。
  • 文档规范:提供清晰、一致的中英文文档。
  • 资源整合:逐步统一 TROS 和 Model Zoo 中的模型资源,包括/app目录下的应用案例,最终实现无缝集成。

TROS预计在下一版本尽快完成统一工作。在此之前,您可以参考以下临时解决方案来适配当前最新的YOLO模型。

1. 问题描述

hobot_dnn 项目的后处理解析器(parser)当前期望其处理的YOLO模型输出是量化后(例如 int32_t 类型)的张量,因此代码中包含了反量化处理步骤。然而,当前 Model Zoo 中最新的 YOLO 模型已更新,其输出层直接输出未经量化的 float (FP32) 浮点型张量。

这种变化导致了数据格式的不兼容:原有的解析器会错误地将 FP32 数据当作 int32_t 处理,导致解析失败和错误的检测结果。

2. 解决方案概述

核心解决方案是修改与您使用的YOLO模型相对应的 C++ 输出解析器,使其能够正确处理 FP32 数据。这主要涉及两个关键点:

  1. 更改用于读取模型输出张量的数据类型。
  2. 移除不再需要的反量化(Dequantization)处理步骤。

本指南以 YOLOv8 模型为例,对应的文件是 ptq_yolo8_output_parser.cpp。同样的方法也适用于其他遇到类似问题的 YOLO 模型解析器,目前Model Zoo中的YOLO方案后处理通用。

3. 分步修改指南

以下步骤将指导您如何修改 src/hobot_dnn/dnn_node/src/output_parser/detection/ptq_yolo8_output_parser.cpp 文件。

步骤 3.1: 更改包围框(Bounding Box)的数据类型

ParseTensor 函数中,找到获取包围框张量数据的代码行。您需要将指针类型从 int32_t* 修改为 float*

找到此行:

int32_t *box_data = boxes->GetTensorData<int32_t>();

并将其修改为:

float *box_data = boxes->GetTensorData<float>();

步骤 3.2: 移除反量化相关的代码

由于模型直接输出浮点数,反量化函数 DequantiScale 和相关的 box_scale_data 变量都不再需要。

找到并删除这一行:

auto *box_scale_data = reinterpret_cast<float *>(boxes->properties.scale.scaleData);

步骤 3.3: 修改核心解析逻辑

这是最关键的一步。我们需要修改解析包围框分布的代码,直接使用从 cur_box_data 中读取的浮点数,而不是先进行反量化。

找到此代码块:

int32_t *cur_box_data = box_data;

// ... (中间省略几行) ...

for (size_t i = 0; i < 4; ++i) {
  sum = 0.;
  for (int reg = 0; reg < reg_max; ++reg) {
    if (is_performance_) {
      distribute_score = fastExp(DequantiScale(cur_box_data[box_id], false, box_scale_data[box_id]));
    } else {
      distribute_score = std::exp(DequantiScale(cur_box_data[box_id], false, box_scale_data[box_id]));
    }
    sum += distribute_score;
    decoded_boxes[i] += distribute_score * reg;
    ++box_id;
  }
  decoded_boxes[i] /= sum;
}

将其替换为以下简化版本:

float *cur_box_data = box_data;

// ... (中间省略几行) ...

for (size_t i = 0; i < 4; ++i) {
  sum = 0.;
  for (int reg = 0; reg < reg_max; ++reg) {
    if (is_performance_) {
      distribute_score = fastExp(cur_box_data[box_id]);
    } else {
      distribute_score = std::exp(cur_box_data[box_id]);
    }
    sum += distribute_score;
    decoded_boxes[i] += distribute_score * reg;
    ++box_id;
  }
  decoded_boxes[i] /= sum;
}

步骤 3.4: 移除不再使用的 DequantiScale 函数

为了保持代码整洁,请移除已经不再使用的 DequantiScale 函数的声明和定义。

从文件中删除以下两个部分:

  1. 函数前向声明 (通常在文件靠前的位置):

    float DequantiScale(int32_t data,
                        bool big_endian,
                        float &scale_value);
    
  2. 函数定义 (通常在文件的末尾):

    float DequantiScale(int32_t data,
                        bool big_endian,
                        float &scale_value) {
      return static_cast<float>(r_int32(data, big_endian)) * scale_value;
    }
    

4. 编译与部署指南

完成代码修改后,您需要重新编译功能包,并让TROS环境加载您本地修改后的版本。以下是详细步骤。

步骤 4.1: 编译功能包并指定目标平台

hobot_dnn 的编译需要明确指定目标硬件平台。您需要通过CMake参数来完成。

  1. 回到您的ROS2工作空间根目录,例如 /root/tros_ws
  2. 执行 colcon build 命令,并使用 --cmake-args 来传递平台参数。

编译命令示例:

  • 为 S100 平台编译:

    colcon build --packages-select dnn_node --cmake-args -DPLATFORM_S100=ON
    
  • 为 X5 平台编译:

    colcon build --packages-select dnn_node --cmake-args -DPLATFORM_X5=ON
    

编译成功后,dnn_node 的新版本库文件将生成在您工作空间的 install/dnn_node/ 目录下。

步骤 4.2: 部署与覆盖TROS环境

为了让系统使用您刚刚编译的版本,而不是TROS系统自带的版本,您需要利用ROS2的 工作空间覆盖(Overlay) 机制。原理是,ROS2会优先使用您最后 source 的工作空间中的功能包。

  1. 打开一个新的终端。这是一个干净的环境,确保不会被旧的环境变量干扰。

  2. 首先,source TROS 的主环境。这会加载TROS系统的所有基础功能包。

    source /opt/tros/humble/setup.bash
    
  3. 然后,source 您本地的工作空间。这个工作空间包含了您刚刚修改并编译的 dnn_node

    # 注意:请确保路径是您自己的工作空间路径
    source /root/tros_ws/install/setup.bash
    

    这个顺序至关重要!后 source 的会覆盖先 source 的。

  4. (可选)验证覆盖是否成功。您可以运行以下命令来检查当前环境中 dnn_node 功能包的路径:

    ros2 pkg prefix dnn_node
    

    如果覆盖成功,输出的路径应该指向您本地的工作空间,例如:

    /root/tros_ws/install/dnn_node
    

    如果输出的是 /opt/tros/humble/share/dnn_node 或类似路径,则说明覆盖未成功,请检查您的 source 顺序和路径是否正确。

完成以上步骤后,您在该终端中启动的任何ROS2节点(例如通过 ros2 launch)都将自动使用您本地修改过的 dnn_node 版本,从而能够正确处理FP32模型输出。