9.2. BPU SDK API 手册

本文档主要介绍了地瓜机器人天工开物工具链 Runtime 的 API、数据、结构体、排布及对齐规则等。 通过阅读本文档,用户可以在 D-Robotics 开发板上利用 API 完成模型的加载与释放,模型信息的获取,以及模型的推理等操作。

9.2.1. 数据类型和数据结构

9.2.1.1. 版本信息类

注解

注意,本小节中的版本信息类型的版本号随版本变化有所不同,此处的版本号仅供参考,实际版本请以您获取到的发布物为准。

9.2.1.1.1. HB_DNN_VERSION_MAJOR

#define HB_DNN_VERSION_MAJOR 1U

DNN 主版本号信息。

9.2.1.1.2. HB_DNN_VERSION_MINOR

#define HB_DNN_VERSION_MINOR 1U

DNN 次版本号信息。

9.2.1.1.3. HB_DNN_VERSION_PATCH

#define HB_DNN_VERSION_PATCH 0U

DNN 补丁版本号信息。

9.2.1.2. 模型类

9.2.1.2.1. HB_DNN_TENSOR_MAX_DIMENSIONS

#define HB_DNN_TENSOR_MAX_DIMENSIONS 8

张量最大的维度设置为 8

9.2.1.2.2. HB_DNN_INITIALIZE_INFER_CTRL_PARAM

#define HB_DNN_INITIALIZE_INFER_CTRL_PARAM(param) \
{                                                 \
    (param)->bpuCoreId = HB_BPU_CORE_ANY;         \
    (param)->priority = HB_DNN_PRIORITY_LOWEST;   \
    (param)->more = false;                        \
    (param)->customId = 0;                        \
    (param)->reserved1 = 0;                       \
    (param)->reserved2 = 0;                       \
}

初始化控制参数。

9.2.1.2.3. hbPackedDNNHandle_t

typedef void *hbPackedDNNHandle_t;

DNN 句柄,指向打包的多个模型。

9.2.1.2.4. hbDNNHandle_t

typedef void *hbDNNHandle_t;

DNN 句柄,指向单一模型。

9.2.1.2.5. hbDNNTaskHandle_t

typedef void *hbDNNTaskHandle_t;

任务句柄,指向一个任务。

9.2.1.2.6. hbDNNTaskDoneCb

typedef void (*hbDNNTaskDoneCb)(hbDNNTaskHandle_t taskHandle, int32_t status,
                                void *userdata);

用户自定义任务完成后需要执行的回调函数。

  • 参数

    • [in] taskHandle 任务句柄指针。

    • [in] status 任务返回的状态码。

    • [in] userdata 用户自定义的数据。

9.2.1.2.7. hbDNNTensorLayout

typedef enum {
  HB_DNN_LAYOUT_NHWC = 0,
  HB_DNN_LAYOUT_NCHW = 2,
  HB_DNN_LAYOUT_NONE = 255,
} hbDNNTensorLayout;

张量的排布形式。

NHWC 分别代表 Number、Height、Width 和 Channel。

  • 成员

成员名称

描述

HB_DNN_LAYOUT_NONE

没有定义排布形式。

HB_DNN_LAYOUT_NHWC

排布形式为 NHWC

HB_DNN_LAYOUT_NCHW

排布形式为 NCHW

9.2.1.2.8. hbDNNDataType

typedef enum {
  HB_DNN_IMG_TYPE_Y,
  HB_DNN_IMG_TYPE_NV12,
  HB_DNN_IMG_TYPE_NV12_SEPARATE,
  HB_DNN_IMG_TYPE_YUV444,
  HB_DNN_IMG_TYPE_RGB,
  HB_DNN_IMG_TYPE_BGR,
  HB_DNN_TENSOR_TYPE_S4,
  HB_DNN_TENSOR_TYPE_U4,
  HB_DNN_TENSOR_TYPE_S8,
  HB_DNN_TENSOR_TYPE_U8,
  HB_DNN_TENSOR_TYPE_F16,
  HB_DNN_TENSOR_TYPE_S16,
  HB_DNN_TENSOR_TYPE_U16,
  HB_DNN_TENSOR_TYPE_F32,
  HB_DNN_TENSOR_TYPE_S32,
  HB_DNN_TENSOR_TYPE_U32,
  HB_DNN_TENSOR_TYPE_F64,
  HB_DNN_TENSOR_TYPE_S64,
  HB_DNN_TENSOR_TYPE_U64,
  HB_DNN_TENSOR_TYPE_MAX
} hbDNNDataType;

张量的类型。

S 代表有符号, U 代表无符号, F 代表浮点型,后面的数字代表 bit 数。

HB_DNN_IMG_TYPE_NV12HB_DNN_IMG_TYPE_NV12_SEPARATE 都代表 NV12 的数据,只是在存储上有差异。

  • 成员

成员名称

描述

HB_DNN_IMG_TYPE_Y

张量类型为仅有 Y 通道的图片。

HB_DNN_IMG_TYPE_NV12

张量类型为一张 NV12 的图片。

HB_DNN_IMG_TYPE_NV12_SEPARATE

张量类型为 Y 通道及 UV 通道为输入的图片。

HB_DNN_IMG_TYPE_YUV444

张量类型为 YUV444 为输入的图片。

HB_DNN_IMG_TYPE_RGB

张量类型为 RGB 为输入的图片。

HB_DNN_IMG_TYPE_BGR

张量类型为 BGR 为输入的图片。

HB_DNN_TENSOR_TYPE_S4

张量类型为有符号 4bit。

HB_DNN_TENSOR_TYPE_U4

张量类型为无符号 4bit。

HB_DNN_TENSOR_TYPE_S8

张量类型为有符号 8bit。

HB_DNN_TENSOR_TYPE_U8

张量类型为无符号 8bit。

HB_DNN_TENSOR_TYPE_F16

张量类型为浮点型 16bit。

HB_DNN_TENSOR_TYPE_S16

张量类型为有符号 16bit。

HB_DNN_TENSOR_TYPE_U16

张量类型为无符号 16bit。

HB_DNN_TENSOR_TYPE_F32

张量类型为浮点型 32bit。

HB_DNN_TENSOR_TYPE_S32

张量类型为有符号 32bit。

HB_DNN_TENSOR_TYPE_U32

张量类型为无符号 32bit。

HB_DNN_TENSOR_TYPE_F64

张量类型为浮点型 64bit。

HB_DNN_TENSOR_TYPE_S64

张量类型为有符号 64bit。

HB_DNN_TENSOR_TYPE_U64

张量类型为无符号 64bit。

HB_DNN_TENSOR_TYPE_MAX

代表最大的张量类型编号。

9.2.1.2.9. hbDNNTensorShape

typedef struct {
  int32_t dimensionSize[HB_DNN_TENSOR_MAX_DIMENSIONS];
  int32_t numDimensions;
} hbDNNTensorShape;

张量的形状。

例如一张 224x224 的 bgr 彩色空间的图片 numDimensions=4,若排布形式为 NHWC, 则 dimensionSize 数组中按顺序存储图片 Number=1Height=224Width=224Channel=3

  • 成员

成员名称

描述

dimensionSize

张量每个维度的大小。

numDimensions

张量的维度。

9.2.1.2.10. hbDNNQuantiShift

typedef struct {
  int32_t shiftLen;
  uint8_t *shiftData;
} hbDNNQuantiShift;

量化/反量化的移位数据。

对于输入 :若采集到浮点数据 data[i], 对应的移位数据是 shift[i], 则送入模型的推理数据为: \(data[i] * (1 << shift[i])\) 取整;

对于输出 :若推理结果 data[i], 对应的移位数据是 shift[i], 则最终的推理结果为: \(data[i] / (1 << shift[i])\)

其中 shiftLen 由数据 data 按照 per-axisper-tensor (反)量化方式决定。 当数据 dataper-tensor (反)量化时, shiftLen 等于 1,此时不需要关注 quantizeAxis 数值; 否则等于数据 data 的第 quantizeAxis 维度大小。

  • 成员

成员名称

描述

shiftLen

移位数据的长度。

shiftData

移位数据的首地址。

9.2.1.2.11. hbDNNQuantiScale

typedef struct {
  int32_t scaleLen;
  float *scaleData;
  int32_t zeroPointLen;
  int8_t *zeroPointData;
} hbDNNQuantiScale;

量化/反量化的缩放数据。

对于输入 :若采集到浮点数据 data[i], 对应的缩放数据是 scale[i], 零点偏移数据是 zeroPoint[i],则送入模型的推理数据为: \(g((data[i] / scale[i]) + zeroPoint[i])\) , 其中: \(g(x) = clip(round(x))\), 截断到:U8: \(g(x)∈[0, 255]\), S8: \(g(x)∈[-128, 127]\);

对于输出 :若推理结果 data[i], 对应的缩放数据是 scale[i], 零点偏移数据是 zeroPoint[i],则最终的推理结果为: \((data[i] - zeroPoint[i])* scale[i]\)

其中 scaleLen 由数据 data 按照 per-axisper-tensor (反)量化方式决定。 当数据 dataper-tensor (反)量化时, scaleLen 等于 1,此时不需要关注 quantizeAxis 数值; 否则等于数据 dataquantizeAxis 维度大小。 zeroPointLenscaleLen 保持一致。

  • 成员

成员名称

描述

scaleLen

缩放数据的长度。

scaleData

缩放数据的首地址。

zeropointLen

零点偏移数据的长度。

zeropointData

零点偏移数据的首地址。

9.2.1.2.12. hbDNNQuantiType

typedef enum {
  NONE,
  SHIFT,
  SCALE,
} hbDNNQuantiType;

定点浮点转换的量化/反量化类型。

NONE 代表不需要对数据做任何处理;

SHIFT 类型对应的量化/反量化参数存储在 hbDNNQuantiShift 结构体中;

SCALE 对应的量化/反量化参数存储在 hbDNNQuantiScale 结构体中。

  • 成员

成员名称

描述

NONE

没有量化。

SHIFT

量化类型为 SHIFT

SCALE

量化类型为 SCALE

9.2.1.2.13. hbDNNTensorProperties

typedef struct {
  hbDNNTensorShape validShape;
  hbDNNTensorShape alignedShape;
  int32_t tensorLayout;
  int32_t tensorType;
  hbDNNQuantiShift shift;
  hbDNNQuantiScale scale;
  hbDNNQuantiType quantiType;
  int32_t quantizeAxis;
  int32_t alignedByteSize;
  int32_t stride[HB_DNN_TENSOR_MAX_DIMENSIONS];
} hbDNNTensorProperties;

张量的信息。

  • 成员

成员名称

描述

validShape

张量有效内容的形状。

alignedShape

张量对齐内容的形状。

tensorLayout

张量的排布形式。

tensorType

张量的类型。

shift

量化偏移量。

scale

量化缩放量。

quantiType

量化类型。

quantizeAxis

量化通道,仅按 per-axis 量化时生效。

alignedByteSize

张量对齐内容的内存大小。

stride

张量中 validShape 各维度步长。

注解

通过接口获取的张量信息为模型要求的,您可以根据实际输入修改对应的张量信息,目前只允许修改 alignedShapetensorType 的信息,而且必须符合要求。

alignedShape

  1. 若您根据 alignedShape 准备输入,则无需更改 alignedShape

  2. 若您根据 validShape 准备输入,则需更改 alignedShapevalidShape ,推理库内部会对数据进行 padding 操作。

tensorType

推理 NV12 输入的模型时,您可根据实际情况更改张量的 tensorType 属性为 HB_DNN_IMG_TYPE_NV12HB_DNN_IMG_TYPE_NV12_SEPARATE

9.2.1.2.14. hbDNNTaskPriority

typedef enum {
  HB_DNN_PRIORITY_LOWEST = 0,
  HB_DNN_PRIORITY_HIGHEST = 255,
  HB_DNN_PRIORITY_PREEMP = HB_DNN_PRIORITY_HIGHEST,
} hbDNNTaskPriority;

Task 优先级配置,提供默认参数。

9.2.1.2.15. hbDNNTensor

typedef struct {
  hbSysMem sysMem[4];
  hbDNNTensorProperties properties;
} hbDNNTensor;

张量。

用于存放输入输出的信息。其中 NV12_SEPARATE 类型的张量需要用 2 个 hbSysMem,其余都为 1 个。

  • 成员

成员名称

描述

sysMem

存放张量的内存。

properties

张量的信息。

9.2.1.2.16. hbDNNRoi

typedef struct {
  int32_t left;
  int32_t top;
  int32_t right;
  int32_t bottom;
} hbDNNRoi;

矩形的感兴趣区域。 \(W∈[left, right], H∈[top, bottom]\)

  • 成员

成员名称

描述

left

感兴趣区域左上点宽度像素点。

top

感兴趣区域左上点高度像素点。

right

感兴趣区域右下点宽度像素点。

bottom

感兴趣区域右下点高度像素点。

9.2.1.2.17. hbDNNInferCtrlParam

typedef struct {
  int32_t bpuCoreId;
  int32_t priority;
  int32_t more;
  int64_t customId;
  int32_t reserved1;
  int32_t reserved2;
} hbDNNInferCtrlParam;

模型推理的控制参数。

bpuCoreId 用于控制推理模型 BPU 节点使用的核;

more 参数用于小模型批量处理场景,当希望所有任务都执行完再获得输出时,除最后一个任务设置 more0 外, 之前的任务 more 都设置为 1,最多支持 255 个不同小模型的批量推理,小模型为 resizer 模型时,每一个 roi 都可能会被算作一个小模型。

customId 参数用于用户自定义优先级,定义 task 的优先级大小,例如:时间戳、frame id 等,数值越小优先级越高。优先级:priority > customId。

  • 成员

成员名称

描述

bpuCoreId

BPU 核 ID。

priority

任务优先级。

more

该任务后续是否有跟随任务。

customId

自定义优先级。

reserved1

保留字段 1。

Reserved2

保留字段 2。

9.2.1.3. 系统类

9.2.1.3.1. hbBPUCore

typedef enum {
  HB_BPU_CORE_ANY = 0,
  HB_BPU_CORE_0 = (1 << 0),
  HB_BPU_CORE_1 = (1 << 1)
} hbBPUCore;

BPU 核枚举,X5 系统仅有一个 BPU 核,仅支持指定 HB_BPU_CORE_ANY 或 HB_BPU_CORE_0。

  • 成员

成员名称

描述

HB_BPU_CORE_ANY

任意的 BPU 核。

HB_BPU_CORE_0

BPU 核 0。

HB_BPU_CORE_1

BPU 核 1。

9.2.1.3.2. hbSysMem

typedef struct {
  uint64_t phyAddr;
  void *virAddr;
  uint32_t memSize;
} hbSysMem;

系统内存结构体,用于申请系统内存。

  • 成员

成员名称

描述

phyAddr

物理地址。

virAddr

虚拟地址。

memSize

内存大小。

9.2.1.3.3. hbSysMemFlushFlag

typedef enum {
  HB_SYS_MEM_CACHE_INVALIDATE = 1,
  HB_SYS_MEM_CACHE_CLEAN = 2
} hbSysMemFlushFlag;

系统内存与缓存同步参数。

CPU 与内存之间有一个缓存区,导致缓存中内容与内存中内容会出现不同步的情况,为了每次都能够拿到最新的数据, 我们需要在 CPU 读前、写后进行数据更新。CPU 读前,将内存中数据更新到缓存中。CPU 写后,将缓存中数据更新到内存中。

../../../_images/hbSysMemFlushFlag.png
  • 成员

成员名称

描述

HB_SYS_MEM_CACHE_INVALIDATE

将内存同步到缓存中,CPU 读前使用。

HB_SYS_MEM_CACHE_CLEAN

将缓存数据同步到内存中,CPU 写后使用。

9.2.1.4. 插件类

9.2.1.4.1. hbDNNLayerCreator

typedef hobot::dnn::Layer *(*hbDNNLayerCreator)();

用户自定义 Layer 创建方法。

9.2.2. API 接口

9.2.2.1. 版本信息

9.2.2.1.1. hbDNNGetVersion()

char const *hbDNNGetVersion();

获取 DNN 预测库版本信息。

  • 返回值

    • 返回版本信息。

9.2.2.2. 模型加载/释放

9.2.2.2.1. hbDNNInitializeFromFiles()

int32_t hbDNNInitializeFromFiles(hbPackedDNNHandle_t *packedDNNHandle,
                                 char const **modelFileNames,
                                 int32_t modelFileCount);

从文件完成对 packedDNNHandle 的创建和初始化。调用方可以跨函数、跨线程使用返回的 packedDNNHandle

  • 参数

    • [out] packedDNNHandle D-Robotics DNN 句柄,指向多个模型。

    • [in] modelFileNames 模型文件的路径。

    • [in] modelFileCount 模型文件的个数。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.2.2. hbDNNInitializeFromDDR()

int32_t hbDNNInitializeFromDDR(hbPackedDNNHandle_t *packedDNNHandle,
                               const void **modelData,
                               int32_t *modelDataLengths,
                               int32_t modelDataCount);

从内存完成对 packedDNNHandle 的创建和初始化。调用方可以跨函数、跨线程使用返回的 packedDNNHandle

  • 参数

    • [out] packedDNNHandle D-Robotics DNN 句柄,指向多个模型。

    • [in] modelData 模型文件的指针。

    • [in] modelDataLengths 模型数据的长度。

    • [in] modelDataCount 模型数据的个数。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.2.3. hbDNNRelease()

int32_t hbDNNRelease(hbPackedDNNHandle_t packedDNNHandle);

packedDNNHandle 所指向的模型释放。

  • 参数

    • [in] packedDNNHandle D-Robotics DNN 句柄,指向多个模型。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.3. 模型信息

9.2.2.3.1. hbDNNGetModelNameList()

int32_t hbDNNGetModelNameList(char const ***modelNameList,
                              int32_t *modelNameCount,
                              hbPackedDNNHandle_t packedDNNHandle);

获取 packedDNNHandle 所指向模型的名称列表和个数。

  • 参数

    • [out] modelNameList 模型名称列表。

    • [out] modelNameCount 模型名称个数。

    • [in] packedDNNHandle D-Robotics DNN 句柄,指向多个模型。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.3.2. hbDNNGetModelHandle()

int32_t hbDNNGetModelHandle(hbDNNHandle_t *dnnHandle,
                            hbPackedDNNHandle_t packedDNNHandle,
                            char const *modelName);

packedDNNHandle 所指向模型列表中获取一个模型的句柄。调用方可以跨函数、跨线程使用返回的 dnnHandle

  • 参数

    • [out] dnnHandle DNN 句柄,指向一个模型。

    • [in] packedDNNHandle DNN 句柄,指向多个模型。

    • [in] modelName 模型名称。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.3.3. hbDNNGetInputCount()

int32_t hbDNNGetInputCount(int32_t *inputCount,
                           hbDNNHandle_t dnnHandle);

获取 dnnHandle 所指向模型输入张量的个数。

  • 参数

    • [out] inputCount 模型输入张量的个数。

    • [in] dnnHandle DNN 句柄,指向一个模型。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.3.4. hbDNNGetInputName()

int32_t hbDNNGetInputName(char const **name,
                          hbDNNHandle_t dnnHandle,
                          int32_t inputIndex);

获取 dnnHandle 所指向模型输入张量的名称。

  • 参数

    • [out] name 模型输入张量的名称。

    • [in] dnnHandle DNN 句柄,指向一个模型。

    • [in] inputIndex 模型输入张量的编号。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.3.5. hbDNNGetInputTensorProperties()

int32_t hbDNNGetInputTensorProperties(hbDNNTensorProperties *properties,
                                      hbDNNHandle_t dnnHandle,
                                      int32_t inputIndex);

获取 dnnHandle 所指向模型特定输入张量的属性。

  • 参数

    • [out] properties 输入张量的信息。

    • [in] dnnHandle DNN 句柄,指向一个模型。

    • [in] inputIndex 模型输入张量的编号。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.3.6. hbDNNGetOutputCount()

int32_t hbDNNGetOutputCount(int32_t *outputCount,
                            hbDNNHandle_t dnnHandle);

获取 dnnHandle 所指向模型输出张量的个数。

  • 参数

    • [out] outputCount 模型输出张量的个数。

    • [in] dnnHandle DNN 句柄,指向一个模型。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.3.7. hbDNNGetOutputName()

int32_t hbDNNGetOutputName(char const **name,
                           hbDNNHandle_t dnnHandle,
                           int32_t outputIndex);

获取 dnnHandle 所指向模型输出张量的名称。

  • 参数

    • [out] name 模型输出张量的名称。

    • [in] dnnHandle DNN 句柄,指向一个模型。

    • [in] outputIndex 模型输出张量的编号。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.3.8. hbDNNGetOutputTensorProperties()

int32_t hbDNNGetOutputTensorProperties(hbDNNTensorProperties *properties,
                                       hbDNNHandle_t dnnHandle,
                                       int32_t outputIndex);

获取 dnnHandle 所指向模型特定输出张量的属性。

  • 参数

    • [out] properties 输出张量的信息。

    • [in] dnnHandle DNN 句柄,指向一个模型。

    • [in] outputIndex 模型输出张量的编号。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.4. 模型推理

9.2.2.4.1. hbDNNInfer()

int32_t hbDNNInfer(hbDNNTaskHandle_t *taskHandle,
                   hbDNNTensor **output,
                   hbDNNTensor const *input,
                   hbDNNHandle_t dnnHandle,
                   hbDNNInferCtrlParam *inferCtrlParam);

根据输入参数执行推理任务。调用方可以跨函数、跨线程使用返回的 taskHandle

  • 参数

    • [out] taskHandle 任务句柄指针。

    • [in/out] output 推理任务的输出。

    • [in] input 推理任务的输入。

    • [in] dnnHandle DNN 句柄指针。

    • [in] inferCtrlParam 控制推理任务的参数。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

注解

使用该接口提交任务时应提前将 taskHandle 置为 nullptr,除非是给指定 taskHandle 追加任务(即使用 inferCtrlParam::more 功能)。

最多支持同时存在 32 个模型任务。

对于 batch 模型,允许分开设置输入张量的内存地址。例如:模型的输入 validShape/alignedShape 为[4, 3, 224, 224], 可以申请四个 hbDNNTensor, 每个 hbDNNTensor 的 validShape/alignedShape 都设置为[1, 3, 224, 224],存放每个 batch 的数据。当模型有多个输入时, input 的顺序应为 input0[batch0], input0[batch1], …, inputn[batch0], inputn[batch1], …。

9.2.2.4.2. hbDNNRoiInfer()

int32_t hbDNNRoiInfer(hbDNNTaskHandle_t *taskHandle,
                      hbDNNTensor **output,
                      hbDNNTensor const *input,
                      hbDNNRoi *rois,
                      int32_t roiCount,
                      hbDNNHandle_t dnnHandle,
                      hbDNNInferCtrlParam *inferCtrlParam);

根据输入参数执行 ROI 推理任务。调用方可以跨函数、跨线程使用返回的 taskHandle

  • 参数

    • [out] taskHandle 任务句柄指针。

    • [in/out] output 推理任务的输出。

    • [in] input 推理任务的输入。

    • [in] rois Roi 框信息。

    • [in] roiCount Roi 框数量。

    • [in] dnnHandle dnn 句柄指针。

    • [in] inferCtrlParam 控制推理任务的参数。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

注解

概念说明:

  • input_count : 模型输入分支数量

  • output_count : 模型输出分支数量

  • resizer_count : 模型输入源为 resizer 的分支数量(≤input_count),模型处理一批数据时,一个 resizer 输入源分支处理一个 roi

  • roiCount : roi 总数,其数值应大于等于 resizer_count

  • data_batch : 模型需要推理的数据批数,其数值为 roiCount / resizer_count

  • model_batch : 模型内部的 batch 数量。即模型实际推理时,输入给模型的 batch_size。地瓜机器人工具链支持将模型编译为 batch model

输入/输出示例说明:

以较为复杂的多输入模型为例,假设模型有 3 个输入分支(2 个 resizer 输入源,1 个 ddr 输入源)和 1 个输出分支,并以 model_batch=2 编译,模型共需处理 3 批数据共 6 个 roi(即每批数据有 2 个 roi),那么现有如下信息:

  • input_count = 3

  • output_count = 1

  • resizer_count = 2

  • roiCount = 6

  • data_batch = 3

  • model_batch = 2

所以模型推理这 3 批数据需要准备独立地址的 input_tensor 数量为 input_count * data_batch = 9

另假设模型输入/输出的静态信息如下:

  • 模型输入(model_info):

    • tensor_0_resizer: [2, 3, 128, 128]

    • tensor_1_resizer: [2, 3, 256, 256]

    • tensor_2_ddr: [2, 80, 1, 100]

  • 模型输出(model_info):

    • tensor_out:[2, 100, 1, 56]

那么模型在推理时的动态信息则为:

  • 模型输入(input_tensors):

    • [1x3x128x128, 1x3x256x256, 1x80x1x100, 1x3x128x128, 1x3x256x256, 1x80x1x100, 1x3x128x128, 1x3x256x256, 1x80x1x100]

  • 模型输出(output_tensors):

    • [4x100x1x56]

其中,因为 model_batch = 2,所以底层 BPU 单次执行可处理 2 批数据;又因为 data_batch = 3,所以 output_tensor 最高维的计算公式为 ceil[(data_batch) / model_batch] * model_batch,可见其一定为 model_batch 的整数倍,这也是 BPU 硬件指令要求,缺少的输入会自动忽略计算。这里模型输出[0~2x100x1x56]是有效数据,最后一组是无效数据。

接口限制说明:

  • 关于 data_batch 数量限制:其范围应该在[1, 255]。

  • 使用该接口提交任务时应提前将 taskHandle 置为 nullptr,除非是给指定 taskHandle 追加任务(即使用 inferCtrlParam::more 功能)。

  • roi 大小要求是 \(2 <= width <= 4096\), \(2 <= height <= 4096\)

  • 原图尺寸要求是 \(1 <= W <= 4096\), \(16 <= stride <= 131072\)stride 必须是 16 的倍数。

  • 输出尺寸要求是 \(2 <= Wout\), \(2 <= Hout\)

  • roi 缩放倍数限制 \(0 <= step <= 262143\),step 计算公式 \(step = ((src\_len - 1)*65536 + (dst\_len - 1)/2)/(dst\_len - 1)\),其中 src_len 为 roi 的 W 或 H,dst_len 为模型要求的 W 或 H。

  • 最多支持同时存在 32 个模型任务。

9.2.2.4.3. hbDNNWaitTaskDone()

int32_t hbDNNWaitTaskDone(hbDNNTaskHandle_t taskHandle,
                          int32_t timeout);

等待任务完成或超时。

  • 参数

    • [in] taskHandle 任务句柄指针。

    • [in] timeout 超时配置(单位:毫秒)。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

注解

  1. timeout > 0 表示等待时间;

  2. timeout <= 0 表示一直等待,直到任务完成。

9.2.2.4.4. hbDNNReleaseTask()

int32_t hbDNNReleaseTask(hbDNNTaskHandle_t taskHandle);

释放任务,如果任务未执行则会直接取消并释放任务,如果已经执行则会在运行到某些节点后取消并释放任务。

  • 参数

    • [in] taskHandle 任务句柄指针。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.4.5. hbDNNSetTaskDoneCb()

int32_t hbDNNSetTaskDoneCb(hbDNNTaskHandle_t taskHandle, hbDNNTaskDoneCb cb,
                           void *userdata);

注册一个回调函数,这个回调函数在任务完成后自动执行。

  • 参数

    • [in] taskHandle 任务句柄指针。

    • [in] cb 回调函数指针。

    • [in] userdata 用户自定义的数据。

  • 返回值

    • 返回 0 则表示回调函数注册成功,否则注册失败。

注解

该接口可以注册一个回调函数,任务执行完成后会调用这个回调函数去执行用户自定义的功能。如果不需要自定义输入,可以将 userdata 设为 nullptr。

9.2.2.5. 内存操作

9.2.2.5.1. hbSysAllocMem()

int32_t hbSysAllocMem(hbSysMem *mem, uint32_t size);

申请 BPU 内存。

  • 参数

    • [in] size 申请内存的大小。

    • [out] mem 内存指针。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.5.2. hbSysAllocCachedMem()

int32_t hbSysAllocCachedMem(hbSysMem *mem, uint32_t size);

申请缓存的 BPU 内存。

  • 参数

    • [in] size 申请内存的大小。

    • [out] mem 内存指针。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.5.3. hbSysFlushMem()

int32_t hbSysFlushMem(hbSysMem *mem, int32_t flag);

对缓存的 BPU 内存进行刷新。

  • 参数

    • [in] mem 内存指针。

    • [in] flag 刷新标志符。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.5.4. hbSysFreeMem()

int32_t hbSysFreeMem(hbSysMem *mem);

释放 BPU 内存。

  • 参数

    • [in] mem 内存指针。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.5.5. hbSysWriteMem()

int32_t hbSysWriteMem(hbSysMem *dest, char *src, uint32_t size);

写入 BPU 内存。

  • 参数

    • [out] dest 内存指针。

    • [in] src 数据指针。

    • [in] size 数据大小。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.5.6. hbSysReadMem()

int32_t hbSysReadMem(char *dest, hbSysMem *src, uint32_t size);

读取 BPU 内存。

  • 参数

    • [out] dest 数据指针。

    • [in] src 内存指针。

    • [in] size 数据大小。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.5.7. hbSysRegisterMem()

int32_t hbSysRegisterMem(hbSysMem *mem);

将已知物理地址的内存区间注册成可被 BPU 使用的内存标识,得到的内存是 cacheable 的。

  • 参数

    • [in/out] mem 内存指针。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.5.8. hbSysUnregisterMem()

int32_t hbSysUnregisterMem(hbSysMem *mem);

注销由 hbSysRegisterMem 注册的内存标识。

  • 参数

    • [in] mem 内存指针。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.6. 插件

9.2.2.6.1. hbDNNRegisterLayerCreator()

int32_t hbDNNRegisterLayerCreator(char const *layerType,
                                  hbDNNLayerCreator layerCreator);

注册 Layer 创建方法。

  • 参数

    • [in] layerType Layer 类型。

    • [in] layerCreator Layer 创建方法。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.6.2. hbDNNUnregisterLayerCreator()

int32_t hbDNNUnregisterLayerCreator(char const *layerType);

注销 Layer。

  • 参数

    • [in] layerType Layer 类型。

  • 返回值

    • 返回 0 则表示 API 成功执行,否则执行失败。

9.2.2.7. 状态码

9.2.2.7.1. hbDNNGetErrorDesc()

char const *hbDNNGetErrorDesc(int32_t errorCode);

将错误码翻译成自然语言。

  • 参数

    • [in] errorCode dnn 错误码。

  • 返回值

    • 返回 char * ,将内部错误码翻译成自然语言。

9.2.3. 数据排布及对齐规则

9.2.3.1. 数据排布

硬件内部为了提高计算效率,其数据使用特殊的排布方式以使得卷积运算中同一批次乘加用到的 feature map 和 kernel 在内存中相邻排放。 下面简要介绍 X5 中数据排布(layout)的概念。

神经网络模型中的变量可以用一个 4 维的张量表示,每个数字是这个张量中的元素,我们称之为自然排布。 将不同维度的不同元素按一定规则紧密排列在一起,形成一个独立的小块(block),然后将这些小块看成新的元素,组成新的 4 维张量, 我们称之为带有数据排布的张量。

输入输出数据会用到不同的 layout 数据排布,用户可通过 API 获取 layout 描述信息,不同的 layout 数据不可以直接比较。

注解

需要注意的是,在进行数据排布转换时,如果需要 padding,则 padding 的值建议设置为零。

此处介绍两种数据排布: NHWC_NATIVENCHW_NATIVE ,以 NHWC_NATIVE 为例,其数据排布如下:

N0H0W0C0

N0H0W0C1

……

N0H0W1C0

N0H0W1C1

……

……

……

……

N0H1W0C0

N0H1W0C1

……

……

……

……

N1H0W0C0

N1H0W0C1

……

……

……

……

一个 N*H*W*C 大小的张量可用如下 4 重循环表示:

for (int32_t n = 0; n < N; n++) {
    for (int32_t h = 0; h < H; h++) {
        for (int32_t w = 0; w < W; w++) {
            for (int32_t c = 0; c < C; c++) {
                int32_t native_offset = n*H*W*C + h*W*C + w*C + c;
            }
        }
    }
}

其中 NCHW_NATIVENHWC_NATIVE 相比,只是排布循环顺序不一样,此处不再单独列出。

注意

下文中提到的 native 都特指该 layout。

9.2.3.2. BPU 对齐限制规则

本节内容介绍使用 BPU 的对齐限制规则。

9.2.3.2.1. 模型输入要求

BPU 不限制模型输入大小或者奇偶。既像 YOLO 这种 416x416 的输入可以支持,对于像 SqueezeNet 这种 227x227 的输入也可以支持。 对于 NV12 输入比较特别,要求 HW 都是偶数,是为了满足 UV 是 Y 的一半的要求。

9.2.3.2.2. 对齐和有效数据

BPU 对数据有对齐限制。对齐要求和真实的数据排布用 hbDNNTensorProperties 中的 validShape , alignedShapestride 表示。

  • validShape 是有效的 shape;

  • alignedShape 是满足对齐要求的 shape, 由于硬件特性, alignedShape 均由四维数据表示;

  • stride 表示 validShape 各维度的步长,其中,NV12 输入的模型比较特殊,其 stride 均为 0,因为 NV12 输入的模型只要求 W 16 对齐。

目前四维模型的张量可以通过 validShapealignedShape 获取正确的数据排布,大于四维模型的张量可以通过 validShapestride 获取正确的数据排布。

在后续场景使用时,考虑到对齐要求,建议按照 alignedByteSize 大小来申请内存空间。

9.2.3.3. NV12 介绍

9.2.3.3.1. YUV 格式

YUV 格式主要用于优化彩色视频信号的传输。

YUV 分为三个分量:Y 表示明亮度,也就是灰度值;而 U 和 V 表示的则是色度,作用是描述影像色彩及饱和度,用于指定像素的颜色。

9.2.3.3.2. NV12 排布

NV12 图像格式属于 YUV 颜色空间中的 YUV420SP 格式,每四个 Y 分量共用一组 U 分量和 V 分量,Y 连续排序,U 与 V 交叉排序。

排列方式如下:

../../../_images/nv12_layout.png

9.2.4. 错误码

HB_DNN_SUCCESS = 0                              // 执行成功
HB_DNN_INVALID_ARGUMENT = -6000001              // 非法参数
HB_DNN_INVALID_MODEL = -6000002                 // 非法模型
HB_DNN_MODEL_NUMBER_EXCEED_LIMIT = -6000003     // 模型个数超过限制
HB_DNN_INVALID_PACKED_DNN_HANDLE = -6000004     // 非法packed handle
HB_DNN_INVALID_DNN_HANDLE = -6000005            // 非法handle
HB_DNN_CAN_NOT_OPEN_FILE = -6000006             // 文件不存在
HB_DNN_OUT_OF_MEMORY = -6000007                 // 没有足够的内存
HB_DNN_TIMEOUT = -6000008                       // 超时
HB_DNN_TASK_NUM_EXCEED_LIMIT = -6000009         // 任务数量超限制
HB_DNN_TASK_BATCH_SIZE_EXCEED_LIMIT = -6000010  // 多任务处理数量超限制
HB_DNN_INVALID_TASK_HANDLE = -6000011           // 非法task handle
HB_DNN_RUN_TASK_FAILED = -6000012               // 任务执行失败
HB_DNN_MODEL_IS_RUNNING = -6000013              // 任务执行中
HB_DNN_INCOMPATIBLE_MODEL = -6000014            // 不兼容的模型
HB_DNN_API_USE_ERROR = -6000015                 // 接口使用错误
HB_DNN_MULTI_PROGRESS_USE_ERROR = -6000016      // 多进程使用错误

HB_SYS_SUCCESS = 0                              // 执行成功
HB_SYS_INVALID_ARGUMENT = -6000129              // 非法参数
HB_SYS_OUT_OF_MEMORY = -6000130                 // 没有足够的内存
HB_SYS_REGISTER_MEM_FAILED = -6000131           // 注册内存失败

9.2.5. 配置信息

9.2.5.1. 常用环境变量

HB_DNN_LOG_LEVEL                // 设置日志等级。
HB_DNN_PLUGIN_PATH              // 自定义CPU算子动态链接库所在目录。
HB_DNN_PROFILER_LOG_PATH        // 模型运行各阶段耗时统计信息dump路径。
HB_DNN_SIM_PLATFORM             // x86模拟器模拟平台设置。
HB_DNN_SIM_BPU_MEM_SIZE         // x86模拟器设置BPU内存大小,单位MB。

9.2.5.2. 日志等级设置说明

  1. 日志等级。 dnn 中的日志主要分为 4 个等级:

    • HB_DNN_LOG_NONE = 0,不输出日志;

    • HB_DNN_LOG_WARNING = 3,该等级主要用来输出代码中的告警信息;

    • HB_DNN_LOG_ERROR = 4,该等级主要用来输出代码中的报错信息;

    • HB_DNN_LOG_FATAL = 5,该等级主要用来输出代码中的导致退出的错误信息。

  2. 日志等级设置规则:

    • 若发生的 LOG 等级 >= 设置的等级,则该 LOG 可以被打印,反之被屏蔽;

    • 设置的 LOG 等级越小,打印信息越多(等级 0 除外,0 不输出日志)。 例如:设置 LOG 等级为 3,即为 WARNING 级别,则 3,4,5 等级的 LOG 均可以被打印; 预测库默认 LOG 等级为 HB_DNN_LOG_WARNING ,则以下 LOG 级别的信息可以被打印: WARNINGERRORFATAL

9.2.5.3. x86 模拟器模拟平台配置说明

  1. x86 模拟器通过设置不同的选项模拟地瓜机器人不同的计算平台架构,其中:

    • export HB_DNN_SIM_PLATFORM=BERNOULLI ,表示模拟地瓜机器人 xj2 平台;

    • export HB_DNN_SIM_PLATFORM=BERNOULLI2 ,表示模拟地瓜机器人 xj3 平台;

    • export HB_DNN_SIM_PLATFORM=BAYES ,表示模拟地瓜机器人 j5 平台;

    • export HB_DNN_SIM_PLATFORM=BAYESE ,表示模拟地瓜机器人 x5 平台;

  2. 如果不设置 HB_DNN_SIM_PLATFORM 环境变量,会根据第一次加载的模型架构来设置模拟器平台,例如:第一次加载的模型是 BAYESE 架构,则程序默认设置的平台为 x5