专栏硬件技术DSP的量化/反量化算子调用

DSP的量化/反量化算子调用

芯链情报局2023-08-31
123
0

1 前言

DSP是J5上专用于视觉/图像处理的数字信号处理器。在OE包的ddk/samples/vdsp_rpc_sample路径下,提供了DSP使用示例,包括nn和cv两部分。nn示例涵盖了深度学习模型的相关算子,包括量化、反量化、Softmax和雷达点云预处理。cv示例展示了如何调用地平线基于DSP封装的图像处理算子,目前已支持20多个,并且仍在持续扩充当中。
在正式阅读前,希望您已经对DSP的软硬件特点、编程思路和板端运行方法有基本的了解,关于这方面的内容可以查看社区文章《DSP开发快速上手》。

2 功能说明

量化、反量化因为涉及浮点计算,无法使用只支持整型计算的BPU,因此通常交由ARM计算。一般来说有两种使用方法,第一种是量化、反量化算子保留在模型内部,模型推理的时候调度ARM计算,另一种是删除模型内部的量化、反量化算子,将相关计算融合进前后处理中。通常更推荐第二种方式,因为能减少数据遍历的次数,提高推理性能。
J5的DSP能替代ARM计算量化、反量化,且同样支持以两种方式进行。

方式1

删去模型内部的量化、反量化算子,将量化、反量化移到前后处理中由DSP计算。
关于如何删除模型内部的量化、反量化算子,以及将相关操作融合进前后处理的大致思路,可以查看社区文章《反量化节点的融合实现》。
注意:由于删去量化、反量化算子后,会让模型的BPU算子直接暴露在模型最外侧,此时板端推理库便不会在模型推理时自动做对齐和删除对齐的操作(模型最外侧是CPU算子时,有方法可以让板端自动做对齐和去除对齐),因此当用户使用方式1时,需要编写代码为输入数据做对齐,并且在使用输出数据前需要编写代码跳用于过对齐的无效数据。关于数据对齐的更多介绍,可以查看社区文章《数据排布与跨距对齐》《模型输入输出对齐规则解析》《在部署时为输入数据做padding》。

方式2

保留模型内部的量化、反量化算子,将原本派发到ARM上的计算调度到DSP执行。
可使用如下环境变量控制ARM是否将计算调度到DSP上执行:

需要注意的是,如果模型输入、输出数据的尺寸过小,那么ARM的量化、反量化性能是会高于DSP的,具体规则如下:

  • quantize输入数据尺寸需要大于等于1x2^18,否则DSP性能会低于ARM

  • dequantize输入数据尺寸需要大于等于1x2^20,否则DSP性能会低于ARM

当板端推理库判断量化、反量化算子的DSP计算性能低于ARM时,会将相关计算还原到ARM侧进行。但如果您十分确定要将所有尺寸的量化、反量化全部交给DSP计算,以节约CPU资源,那么就可以使用下方环境变量:

3 示例文件介绍

OE包的ddk/samples/vdsp_rpc_sample目录提供了量化、反量化示例,文件结构如下:

  • arm:arm侧示例,封装了常用api,主要负责发起RPC调用,接收dsp处理结果。

    • cv:cv示例,包含了图片处理的cv算子示例。

    • nn:nn示例,包含quantize和dequantize api,自定义算子softmax以及pointpillar前处理。

  • dsp:dsp侧示例,实现了dsp算子功能,主要负责接收arm侧发来的任务,完成softmax等算子的计算,将结果发送给arm。

    • src:包含quantize和dequantize api,以及自定义算子softmax以及pointpillar前处理的dsp侧实现。

  • script:示例的生成文件及脚本目录。

    • cv:包含cv示例的可执行文件、输入数据及执行脚本。

    • nn:包含nn示例的可执行文件、输入数据、模型及执行脚本。

    • image: DSP镜像目录。

    • lib: 可执行程序的依赖库目录。

  • deps:所有示例的依赖文件目录。

    • aarch64:arm侧的依赖目录。

    • vdsp:dsp侧的依赖目录。

在arm/nn/src文件夹内,提供了在ARM侧调用DSP计算量化、反量化的示例。
test_quantize.cc和test_dequantize.cc是以方式1计算量化、反量化的示例代码,代码中设定了一组输入数据,以RPC的方式调用DSP做计算,同时将DSP计算结果和ARM的计算结果做了对比,以表明DSP和ARM在计算量化、反量化的精度一致性。
test_nn_plugin.cc是以方式2计算量化、反量化的示例代码,该示例推理了一个实际的模型,并将模型内部的量化和反量化算子交由DSP运行。
common.cc和common.h包含了示例运行的必备组件,其余代码属于Softmax示例,在此不做赘述。
nn文件夹的main.cc集成了调用量化反量化算子的完整功能,CMakeLists.txt是编译必备的配置文件,执行build_arm.sh后,即可编译出可上板运行的可执行文件即相关依赖,这些生成的文件会自动存放进script目录中。我们已提供了编译好的上述文件,无需用户重复编译。

量化与反量化计算的DSP实现源码是开源的,位于dsp/src路径,用户可参考学习,或者基于此代码做二次开发。main.cc主要用于注册编写的DSP算子,量化与反量化算子已经注册,CMakeLists.txt是编译必备的配置文件,执行build_dsp.sh后,即可编译出可以在板端配置的vdsp0和vdsp1镜像,这两个镜像文件还会自动存放进script/image目录中。我们提供了已经编译好的镜像文件,无需用户重复编译。

4 ARM调用代码解读

方式1

删去模型内部的量化、反量化算子,将量化、反量化移到前后处理中由DSP计算。

示例代码为vdsp_rpc_sample/arm/nn/src路径下的test_quantize.cc和test_dequantize.cc,此处以量化调用代码为例进行介绍,反量化调用的代码编写思路相近。

该部分代码是为了让ARM做量化计算编写的,为了验证DSP的计算结果是否和ARM一致。

在test_quantize函数中,这里手动设置了一组输入数据信息。

  • src_mem:存放所有待量化计算的输入数据

  • scale_mem:存放所有scale值

  • zero_point_mem:存放所有zero_point值

  • dst_arm_mem:存放ARM的量化计算结果

  • dst_dsp_mem:存放DSP的量化计算结果

  • data_generate函数的具体实现在common.cc,基于shape生成待量化计算的输入数据

  • quantize_ref函数用于让ARM做量化计算

定义结构体src和dst,用于RPC调用时传递给DSP。

hbDSPQuantize函数封装了hbDSPRpc接口,通过RPC的方式向DSP发送量化计算指令。

验证ARM计算结果和DSP计算结果的一致性,验证通过则打印check result right。

方式2

保留模型内部的量化、反量化算子,将原本派发到ARM上的计算调度到DSP执行。

示例代码为vdsp_rpc_sample/arm/nn/src路径下的test_nn_plugin.cc,由于方式2的计算调度是由板端推理库自动进行的,无需用户在代码中额外编写程序,程序执行前在板端配置好相关环境变量即可,因此对该部分代码的理解可参考社区文章《模型推理快速上手》。

5 示例运行说明

由于ARM侧和DSP侧所有需要编译的文件都已经包括在了OE包当中,因此用户可以跳过编译这一步,直接将script文件夹复制到J5开发板上的可写路径下,如/userdata目录。
此时我们可以编写一个deploy.sh脚本并执行,用于在J5开发板上部署DSP镜像:

之后执行以下命令,给予dsp_relay_server和test_cv文件可执行权限:

最后进入script/nn文件夹,执行以下命令即可运行NN侧包括量化、反量化的全部示例:

用户也可以通过追加参数的形式指定需要执行的算子,所有可执行算子可以在运行脚本后添加help查看:

方式1运行量化计算的指令和打印信息如下:
方式1运行反量化计算的指令和打印信息如下:
方式2运行量化、反量化计算的指令和打印信息如下:
环境变量的相关配置已写在运行脚本中。
打印信息中,如果出现Run Quantize and Dequantize on DSP,就表明正在以方式2让DSP计算量化反量化算子。
硬件技术
征程5
评论0
0/1000